summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/rtc-cdev2
-rw-r--r--Documentation/ABI/testing/sysfs-class-platform-profile2
-rw-r--r--Documentation/ABI/testing/sysfs-driver-uniwill-laptop53
-rw-r--r--Documentation/ABI/testing/sysfs-platform-asus-wmi17
-rw-r--r--Documentation/ABI/testing/sysfs-platform-ayaneo-ec19
-rw-r--r--Documentation/admin-guide/device-mapper/dm-raid.rst80
-rw-r--r--Documentation/admin-guide/device-mapper/verity.rst6
-rw-r--r--Documentation/admin-guide/laptops/index.rst1
-rw-r--r--Documentation/admin-guide/laptops/uniwill-laptop.rst60
-rw-r--r--Documentation/devicetree/bindings/eeprom/at24.yaml1
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-rk3x.yaml1
-rw-r--r--Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml4
-rw-r--r--Documentation/devicetree/bindings/input/ti,twl4030-keypad.yaml59
-rw-r--r--Documentation/devicetree/bindings/input/touchscreen/ar1021.txt15
-rw-r--r--Documentation/devicetree/bindings/input/touchscreen/azoteq,iqs5xx.yaml75
-rw-r--r--Documentation/devicetree/bindings/input/touchscreen/himax,hx83112b.yaml64
-rw-r--r--Documentation/devicetree/bindings/input/touchscreen/hynitron,cstxxx.yaml65
-rw-r--r--Documentation/devicetree/bindings/input/touchscreen/ilitek_ts_i2c.yaml76
-rw-r--r--Documentation/devicetree/bindings/input/touchscreen/maxim,max11801.yaml46
-rw-r--r--Documentation/devicetree/bindings/input/touchscreen/melfas,mip4_ts.yaml56
-rw-r--r--Documentation/devicetree/bindings/input/touchscreen/melfas_mip4.txt20
-rw-r--r--Documentation/devicetree/bindings/input/touchscreen/semtech,sx8654.yaml52
-rw-r--r--Documentation/devicetree/bindings/input/touchscreen/trivial-touch.yaml84
-rw-r--r--Documentation/devicetree/bindings/input/twl4030-keypad.txt27
-rw-r--r--Documentation/devicetree/bindings/mfd/apple,smc.yaml9
-rw-r--r--Documentation/devicetree/bindings/rtc/andestech,atcrtc100.yaml43
-rw-r--r--Documentation/devicetree/bindings/rtc/apple,smc-rtc.yaml35
-rw-r--r--Documentation/devicetree/bindings/rtc/nvidia,vrs-10.yaml59
-rw-r--r--Documentation/devicetree/bindings/rtc/renesas,rz-rtca3.yaml46
-rw-r--r--Documentation/devicetree/bindings/sound/cirrus,cs42xx8.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/cix,sky1-ipbloq-hda.yaml62
-rw-r--r--Documentation/devicetree/bindings/soundwire/qcom,soundwire.yaml8
-rw-r--r--Documentation/driver-api/wmi.rst2
-rw-r--r--Documentation/i2c/busses/i2c-i801.rst1
-rw-r--r--Documentation/power/runtime_pm.rst6
-rw-r--r--Documentation/wmi/devices/lenovo-wmi-gamezone.rst31
-rw-r--r--Documentation/wmi/devices/uniwill-laptop.rst198
-rw-r--r--MAINTAINERS37
-rw-r--r--arch/alpha/include/asm/console.h4
-rw-r--r--arch/alpha/include/asm/page.h4
-rw-r--r--arch/alpha/include/asm/pal.h4
-rw-r--r--arch/alpha/include/asm/thread_info.h8
-rw-r--r--arch/alpha/include/uapi/asm/ioctls.h8
-rw-r--r--arch/arm/Kconfig4
-rw-r--r--arch/arm/configs/am200epdkit_defconfig1
-rw-r--r--arch/arm/configs/lpc32xx_defconfig1
-rw-r--r--arch/arm/configs/omap1_defconfig1
-rw-r--r--arch/arm/configs/tegra_defconfig1
-rw-r--r--arch/arm/include/asm/word-at-a-time.h10
-rw-r--r--arch/arm/mm/alignment.c6
-rw-r--r--arch/arm/mm/fault.c100
-rw-r--r--arch/csky/abiv1/inc/abi/regdef.h2
-rw-r--r--arch/csky/abiv2/inc/abi/regdef.h2
-rw-r--r--arch/csky/include/asm/barrier.h4
-rw-r--r--arch/csky/include/asm/cache.h2
-rw-r--r--arch/csky/include/asm/ftrace.h4
-rw-r--r--arch/csky/include/asm/jump_label.h4
-rw-r--r--arch/csky/include/asm/page.h4
-rw-r--r--arch/csky/include/asm/ptrace.h4
-rw-r--r--arch/csky/include/asm/sections.h1
-rw-r--r--arch/csky/include/asm/string.h2
-rw-r--r--arch/csky/include/asm/thread_info.h4
-rw-r--r--arch/csky/include/uapi/asm/ptrace.h4
-rw-r--r--arch/csky/mm/fault.c4
-rw-r--r--arch/loongarch/Kconfig5
-rw-r--r--arch/loongarch/Makefile7
-rw-r--r--arch/loongarch/configs/loongson32_defconfig1105
-rw-r--r--arch/loongarch/configs/loongson64_defconfig (renamed from arch/loongarch/configs/loongson3_defconfig)7
-rw-r--r--arch/loongarch/include/asm/Kbuild1
-rw-r--r--arch/loongarch/include/asm/addrspace.h15
-rw-r--r--arch/loongarch/include/asm/asm.h77
-rw-r--r--arch/loongarch/include/asm/asmmacro.h118
-rw-r--r--arch/loongarch/include/asm/atomic-amo.h206
-rw-r--r--arch/loongarch/include/asm/atomic-llsc.h100
-rw-r--r--arch/loongarch/include/asm/atomic.h197
-rw-r--r--arch/loongarch/include/asm/bitops.h11
-rw-r--r--arch/loongarch/include/asm/bitrev.h2
-rw-r--r--arch/loongarch/include/asm/checksum.h4
-rw-r--r--arch/loongarch/include/asm/cmpxchg.h48
-rw-r--r--arch/loongarch/include/asm/cpu-features.h3
-rw-r--r--arch/loongarch/include/asm/dmi.h2
-rw-r--r--arch/loongarch/include/asm/elf.h31
-rw-r--r--arch/loongarch/include/asm/inst.h12
-rw-r--r--arch/loongarch/include/asm/irq.h12
-rw-r--r--arch/loongarch/include/asm/jump_label.h12
-rw-r--r--arch/loongarch/include/asm/local.h37
-rw-r--r--arch/loongarch/include/asm/loongarch.h102
-rw-r--r--arch/loongarch/include/asm/module.h11
-rw-r--r--arch/loongarch/include/asm/page.h2
-rw-r--r--arch/loongarch/include/asm/percpu.h44
-rw-r--r--arch/loongarch/include/asm/pgtable-bits.h36
-rw-r--r--arch/loongarch/include/asm/pgtable.h79
-rw-r--r--arch/loongarch/include/asm/stackframe.h34
-rw-r--r--arch/loongarch/include/asm/string.h2
-rw-r--r--arch/loongarch/include/asm/timex.h33
-rw-r--r--arch/loongarch/include/asm/uaccess.h63
-rw-r--r--arch/loongarch/include/asm/vdso/gettimeofday.h4
-rw-r--r--arch/loongarch/include/uapi/asm/Kbuild1
-rw-r--r--arch/loongarch/include/uapi/asm/ptrace.h10
-rw-r--r--arch/loongarch/include/uapi/asm/unistd.h6
-rw-r--r--arch/loongarch/kernel/Makefile.syscalls1
-rw-r--r--arch/loongarch/kernel/cpu-probe.c13
-rw-r--r--arch/loongarch/kernel/efi-header.S4
-rw-r--r--arch/loongarch/kernel/efi.c4
-rw-r--r--arch/loongarch/kernel/entry.S22
-rw-r--r--arch/loongarch/kernel/env.c5
-rw-r--r--arch/loongarch/kernel/fpu.S111
-rw-r--r--arch/loongarch/kernel/head.S39
-rw-r--r--arch/loongarch/kernel/module-sections.c1
-rw-r--r--arch/loongarch/kernel/module.c204
-rw-r--r--arch/loongarch/kernel/proc.c10
-rw-r--r--arch/loongarch/kernel/process.c11
-rw-r--r--arch/loongarch/kernel/ptrace.c5
-rw-r--r--arch/loongarch/kernel/relocate.c13
-rw-r--r--arch/loongarch/kernel/setup.c8
-rw-r--r--arch/loongarch/kernel/switch.S28
-rw-r--r--arch/loongarch/kernel/syscall.c15
-rw-r--r--arch/loongarch/kernel/time.c31
-rw-r--r--arch/loongarch/kernel/traps.c15
-rw-r--r--arch/loongarch/kernel/unaligned.c30
-rw-r--r--arch/loongarch/kvm/vcpu.c5
-rw-r--r--arch/loongarch/lib/bswapdi.c13
-rw-r--r--arch/loongarch/lib/bswapsi.c13
-rw-r--r--arch/loongarch/lib/clear_user.S22
-rw-r--r--arch/loongarch/lib/copy_user.S28
-rw-r--r--arch/loongarch/lib/dump_tlb.c14
-rw-r--r--arch/loongarch/lib/unaligned.S72
-rw-r--r--arch/loongarch/mm/init.c4
-rw-r--r--arch/loongarch/mm/page.S118
-rw-r--r--arch/loongarch/mm/tlb.c12
-rw-r--r--arch/loongarch/mm/tlbex.S322
-rw-r--r--arch/loongarch/pci/pci.c2
-rw-r--r--arch/loongarch/power/hibernate.c6
-rw-r--r--arch/loongarch/power/platform.c4
-rw-r--r--arch/loongarch/power/suspend.c24
-rw-r--r--arch/loongarch/power/suspend_asm.S72
-rw-r--r--arch/loongarch/vdso/Makefile7
-rw-r--r--arch/loongarch/vdso/vdso.lds.S4
-rw-r--r--arch/loongarch/vdso/vgetcpu.c8
-rw-r--r--arch/mips/configs/gcw0_defconfig1
-rw-r--r--arch/mips/configs/loongson1_defconfig1
-rw-r--r--arch/mips/configs/qi_lb60_defconfig1
-rw-r--r--arch/mips/configs/rbtx49xx_defconfig1
-rw-r--r--arch/mips/configs/rs90_defconfig1
-rw-r--r--arch/powerpc/configs/85xx-hw.config1
-rw-r--r--arch/powerpc/configs/86xx-hw.config1
-rw-r--r--arch/powerpc/configs/mpc5200_defconfig1
-rw-r--r--arch/powerpc/configs/ppc6xx_defconfig1
-rw-r--r--arch/s390/Kconfig2
-rw-r--r--arch/s390/boot/vmem.c16
-rw-r--r--arch/s390/include/asm/bug.h5
-rw-r--r--arch/s390/include/asm/page.h2
-rw-r--r--arch/s390/include/asm/pci.h5
-rw-r--r--arch/s390/mm/gmap_helpers.c9
-rw-r--r--arch/s390/mm/pageattr.c2
-rw-r--r--arch/s390/mm/vmem.c14
-rw-r--r--arch/s390/pci/pci.c6
-rw-r--r--arch/s390/pci/pci_bus.c18
-rw-r--r--arch/s390/pci/pci_irq.c332
-rw-r--r--arch/sh/configs/edosk7760_defconfig1
-rw-r--r--arch/sh/configs/se7724_defconfig1
-rw-r--r--arch/sh/configs/sh7785lcr_32bit_defconfig1
-rw-r--r--block/bio.c6
-rw-r--r--block/blk-mq-dma.c1
-rw-r--r--block/blk-mq.c29
-rw-r--r--block/blk-zoned.c2
-rw-r--r--drivers/acpi/platform_profile.c7
-rw-r--r--drivers/base/power/runtime-test.c8
-rw-r--r--drivers/base/power/runtime.c14
-rw-r--r--drivers/block/ublk_drv.c28
-rw-r--r--drivers/firmware/efi/libstub/loongarch.c8
-rw-r--r--drivers/gpio/Kconfig2
-rw-r--r--drivers/gpio/gpio-mmio.c10
-rw-r--r--drivers/gpio/gpio-regmap.c2
-rw-r--r--drivers/gpio/gpiolib-acpi-quirks.c22
-rw-r--r--drivers/gpio/gpiolib-shared.c54
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c2
-rw-r--r--drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h62
-rw-r--r--drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx12.asm37
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_queue.c1
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_svm.c46
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_topology.c4
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h3
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c8
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c59
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_surface.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml2_0/display_mode_core.c134
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c3
-rw-r--r--drivers/gpu/drm/amd/display/include/audio_types.h12
-rw-r--r--drivers/gpu/drm/bridge/ti-sn65dsi83.c11
-rw-r--r--drivers/gpu/drm/drm_gem_dma_helper.c2
-rw-r--r--drivers/gpu/drm/drm_gem_shmem_helper.c2
-rw-r--r--drivers/gpu/drm/drm_plane.c8
-rw-r--r--drivers/gpu/drm/i915/display/intel_fbdev.c11
-rw-r--r--drivers/gpu/drm/i915/intel_memory_region.h2
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_mode.c25
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/nouveau_i2c_encoder.c20
-rw-r--r--drivers/gpu/drm/nouveau/include/dispnv04/i2c/encoder_i2c.h19
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fence.c6
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_hwmon.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c61
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c10
-rw-r--r--drivers/gpu/drm/panel/panel-novatek-nt35560.c8
-rw-r--r--drivers/gpu/drm/panthor/panthor_sched.c19
-rw-r--r--drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c4
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_crtc.c2
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_drv.c53
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_drv.h2
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_vm.c6
-rw-r--r--drivers/hid/hid-asus.c1
-rw-r--r--drivers/i2c/algos/i2c-algo-pcf.c105
-rw-r--r--drivers/i2c/busses/Kconfig3
-rw-r--r--drivers/i2c/busses/i2c-amd-mp2-pci.c5
-rw-r--r--drivers/i2c/busses/i2c-bcm2835.c12
-rw-r--r--drivers/i2c/busses/i2c-designware-core.h2
-rw-r--r--drivers/i2c/busses/i2c-designware-master.c7
-rw-r--r--drivers/i2c/busses/i2c-designware-platdrv.c13
-rw-r--r--drivers/i2c/busses/i2c-i801.c3
-rw-r--r--drivers/i2c/busses/i2c-k1.c19
-rw-r--r--drivers/i2c/busses/i2c-qcom-cci.c46
-rw-r--r--drivers/i2c/busses/i2c-stm32.c7
-rw-r--r--drivers/i3c/master.c17
-rw-r--r--drivers/i3c/master/adi-i3c-master.c18
-rw-r--r--drivers/i3c/master/dw-i3c-master.c8
-rw-r--r--drivers/i3c/master/i3c-master-cdns.c8
-rw-r--r--drivers/i3c/master/mipi-i3c-hci/core.c8
-rw-r--r--drivers/i3c/master/renesas-i3c.c6
-rw-r--r--drivers/input/misc/qnap-mcu-input.c2
-rw-r--r--drivers/input/touchscreen/cyttsp5.c4
-rw-r--r--drivers/input/touchscreen/ti_am335x_tsc.c4
-rw-r--r--drivers/input/touchscreen/zforce_ts.c3
-rw-r--r--drivers/irqchip/irq-loongarch-avec.c5
-rw-r--r--drivers/md/Kconfig2
-rw-r--r--drivers/md/bcache/request.c6
-rw-r--r--drivers/md/dm-bufio.c10
-rw-r--r--drivers/md/dm-core.h1
-rw-r--r--drivers/md/dm-crypt.c117
-rw-r--r--drivers/md/dm-ebs-target.c2
-rw-r--r--drivers/md/dm-exception-store.h2
-rw-r--r--drivers/md/dm-log-writes.c1
-rw-r--r--drivers/md/dm-mpath.c63
-rw-r--r--drivers/md/dm-pcache/cache.c13
-rw-r--r--drivers/md/dm-pcache/cache_segment.c13
-rw-r--r--drivers/md/dm-raid.c2
-rw-r--r--drivers/md/dm-snap.c73
-rw-r--r--drivers/md/dm-sysfs.c8
-rw-r--r--drivers/md/dm-table.c4
-rw-r--r--drivers/md/dm-thin.c19
-rw-r--r--drivers/md/dm-vdo/action-manager.c2
-rw-r--r--drivers/md/dm-vdo/admin-state.c75
-rw-r--r--drivers/md/dm-vdo/block-map.c51
-rw-r--r--drivers/md/dm-vdo/completion.c5
-rw-r--r--drivers/md/dm-vdo/data-vio.c34
-rw-r--r--drivers/md/dm-vdo/dedupe.c42
-rw-r--r--drivers/md/dm-vdo/dm-vdo-target.c5
-rw-r--r--drivers/md/dm-vdo/encodings.c26
-rw-r--r--drivers/md/dm-vdo/flush.c6
-rw-r--r--drivers/md/dm-vdo/funnel-workqueue.c7
-rw-r--r--drivers/md/dm-vdo/io-submitter.c26
-rw-r--r--drivers/md/dm-vdo/logical-zone.c20
-rw-r--r--drivers/md/dm-vdo/packer.c15
-rw-r--r--drivers/md/dm-vdo/physical-zone.c5
-rw-r--r--drivers/md/dm-vdo/recovery-journal.c30
-rw-r--r--drivers/md/dm-vdo/slab-depot.c96
-rw-r--r--drivers/md/dm-vdo/vdo.c9
-rw-r--r--drivers/md/dm-vdo/vdo.h4
-rw-r--r--drivers/md/dm-vdo/vio.c3
-rw-r--r--drivers/md/dm-vdo/vio.h6
-rw-r--r--drivers/md/dm-verity-fec.c41
-rw-r--r--drivers/md/dm-verity-fec.h10
-rw-r--r--drivers/md/dm-verity-target.c209
-rw-r--r--drivers/md/dm-verity.h52
-rw-r--r--drivers/md/dm-zone.c3
-rw-r--r--drivers/md/dm.c46
-rw-r--r--drivers/of/property.c33
-rw-r--r--drivers/pci/controller/pcie-rzg3s-host.c2
-rw-r--r--drivers/platform/Kconfig2
-rw-r--r--drivers/platform/Makefile1
-rw-r--r--drivers/platform/arm64/lenovo-thinkpad-t14s.c58
-rw-r--r--drivers/platform/surface/aggregator/core.c2
-rw-r--r--drivers/platform/surface/aggregator/ssh_packet_layer.c2
-rw-r--r--drivers/platform/surface/aggregator/ssh_request_layer.c2
-rw-r--r--drivers/platform/surface/surface_acpi_notify.c2
-rw-r--r--drivers/platform/wmi/Kconfig34
-rw-r--r--drivers/platform/wmi/Makefile8
-rw-r--r--drivers/platform/wmi/core.c (renamed from drivers/platform/x86/wmi.c)34
-rw-r--r--drivers/platform/x86/Kconfig72
-rw-r--r--drivers/platform/x86/Makefile8
-rw-r--r--drivers/platform/x86/acer-wmi.c290
-rw-r--r--drivers/platform/x86/amd/hfi/hfi.c11
-rw-r--r--drivers/platform/x86/amd/hsmp/acpi.c9
-rw-r--r--drivers/platform/x86/amd/pmf/auto-mode.c14
-rw-r--r--drivers/platform/x86/amd/pmf/cnqf.c14
-rw-r--r--drivers/platform/x86/amd/pmf/core.c23
-rw-r--r--drivers/platform/x86/amd/pmf/pmf.h27
-rw-r--r--drivers/platform/x86/amd/pmf/spc.c2
-rw-r--r--drivers/platform/x86/amd/pmf/sps.c38
-rw-r--r--drivers/platform/x86/amd/pmf/tee-if.c92
-rw-r--r--drivers/platform/x86/asus-armoury.c1161
-rw-r--r--drivers/platform/x86/asus-armoury.h1541
-rw-r--r--drivers/platform/x86/asus-wmi.c185
-rw-r--r--drivers/platform/x86/ayaneo-ec.c593
-rw-r--r--drivers/platform/x86/dell/alienware-wmi-wmax.c124
-rw-r--r--drivers/platform/x86/gpd-pocket-fan.c4
-rw-r--r--drivers/platform/x86/hp/hp-wmi.c24
-rw-r--r--drivers/platform/x86/intel/hid.c12
-rw-r--r--drivers/platform/x86/intel/pmc/arl.c12
-rw-r--r--drivers/platform/x86/intel/pmc/core.c149
-rw-r--r--drivers/platform/x86/intel/pmc/core.h16
-rw-r--r--drivers/platform/x86/intel/pmc/lnl.c2
-rw-r--r--drivers/platform/x86/intel/pmc/mtl.c9
-rw-r--r--drivers/platform/x86/intel/pmc/ptl.c3
-rw-r--r--drivers/platform/x86/intel/pmc/wcl.c18
-rw-r--r--drivers/platform/x86/intel/vsec.c2
-rw-r--r--drivers/platform/x86/lenovo/ideapad-laptop.c218
-rw-r--r--drivers/platform/x86/lenovo/wmi-gamezone.c35
-rw-r--r--drivers/platform/x86/lg-laptop.c11
-rw-r--r--drivers/platform/x86/oxpec.c115
-rw-r--r--drivers/platform/x86/serial-multi-instantiate.c13
-rw-r--r--drivers/platform/x86/uniwill/Kconfig38
-rw-r--r--drivers/platform/x86/uniwill/Makefile8
-rw-r--r--drivers/platform/x86/uniwill/uniwill-acpi.c1912
-rw-r--r--drivers/platform/x86/uniwill/uniwill-wmi.c92
-rw-r--r--drivers/platform/x86/uniwill/uniwill-wmi.h129
-rw-r--r--drivers/platform/x86/x86-android-tablets/lenovo.c2
-rw-r--r--drivers/platform/x86/x86-android-tablets/vexia_atla10_ec.c2
-rw-r--r--drivers/pwm/Kconfig2
-rw-r--r--drivers/regulator/core.c13
-rw-r--r--drivers/regulator/fixed.c11
-rw-r--r--drivers/regulator/spacemit-p1.c4
-rw-r--r--drivers/rtc/Kconfig41
-rw-r--r--drivers/rtc/Makefile3
-rw-r--r--drivers/rtc/rtc-amlogic-a4.c32
-rw-r--r--drivers/rtc/rtc-atcrtc100.c381
-rw-r--r--drivers/rtc/rtc-ds1685.c3
-rw-r--r--drivers/rtc/rtc-gamecube.c4
-rw-r--r--drivers/rtc/rtc-isl12026.c7
-rw-r--r--drivers/rtc/rtc-macsmc.c140
-rw-r--r--drivers/rtc/rtc-max31335.c6
-rw-r--r--drivers/rtc/rtc-nvidia-vrs10.c542
-rw-r--r--drivers/rtc/rtc-pic32.c2
-rw-r--r--drivers/rtc/rtc-renesas-rtca3.c3
-rw-r--r--drivers/rtc/rtc-rv3028.c2
-rw-r--r--drivers/rtc/rtc-rv3032.c2
-rw-r--r--drivers/rtc/rtc-rv8803.c2
-rw-r--r--drivers/rtc/rtc-rx6110.c2
-rw-r--r--drivers/rtc/rtc-rx8010.c1
-rw-r--r--drivers/rtc/rtc-rx8025.c2
-rw-r--r--drivers/rtc/rtc-s35390a.c18
-rw-r--r--drivers/rtc/rtc-sa1100.c3
-rw-r--r--drivers/rtc/rtc-sh.c1
-rw-r--r--drivers/rtc/rtc-tegra.c45
-rw-r--r--drivers/s390/char/sclp_mem.c16
-rw-r--r--drivers/s390/char/vmur.c8
-rw-r--r--drivers/soundwire/bus.c10
-rw-r--r--drivers/soundwire/bus.h22
-rw-r--r--drivers/soundwire/cadence_master.c239
-rw-r--r--drivers/soundwire/cadence_master.h19
-rw-r--r--drivers/soundwire/debugfs.c14
-rw-r--r--drivers/soundwire/generic_bandwidth_allocation.c3
-rw-r--r--drivers/soundwire/intel_ace2x.c104
-rw-r--r--drivers/soundwire/qcom.c257
-rw-r--r--drivers/spi/spi-microchip-core-spi.c1
-rw-r--r--fs/nfs/callback.c4
-rw-r--r--fs/nfs/callback.h3
-rw-r--r--fs/nfs/client.c21
-rw-r--r--fs/nfs/delegation.c8
-rw-r--r--fs/nfs/delegation.h13
-rw-r--r--fs/nfs/dir.c46
-rw-r--r--fs/nfs/inode.c3
-rw-r--r--fs/nfs/internal.h3
-rw-r--r--fs/nfs/localio.c4
-rw-r--r--fs/nfs/namespace.c16
-rw-r--r--fs/nfs/nfs3proc.c3
-rw-r--r--fs/nfs/nfs4client.c27
-rw-r--r--fs/nfs/nfs4proc.c111
-rw-r--r--fs/nfs/nfs4trace.h1
-rw-r--r--fs/nfs/nfs4xdr.c106
-rw-r--r--fs/nfs/pnfs.c1
-rw-r--r--fs/nfs/proc.c3
-rw-r--r--fs/nfs/super.c33
-rw-r--r--fs/nfs/unlink.c3
-rw-r--r--fs/nls/nls_base.c27
-rw-r--r--fs/smb/client/cifspdu.h65
-rw-r--r--fs/smb/client/nterr.c5
-rw-r--r--fs/smb/client/nterr.h1014
-rw-r--r--fs/smb/common/fscc.h56
-rw-r--r--fs/smb/common/smb2pdu.h48
-rw-r--r--fs/smb/server/nterr.h543
-rw-r--r--fs/smb/server/smb2misc.c1
-rw-r--r--fs/smb/server/smb2pdu.c7
-rw-r--r--fs/smb/server/smb_common.h7
-rw-r--r--include/linux/dma-mapping.h2
-rw-r--r--include/linux/i3c/master.h12
-rw-r--r--include/linux/irqdesc.h6
-rw-r--r--include/linux/nfs_fs.h1
-rw-r--r--include/linux/nfs_fs_sb.h6
-rw-r--r--include/linux/nfs_xdr.h10
-rw-r--r--include/linux/of.h9
-rw-r--r--include/linux/platform_data/x86/asus-wmi-leds-ids.h50
-rw-r--r--include/linux/platform_data/x86/asus-wmi.h58
-rw-r--r--include/linux/platform_data/x86/intel_pmc_ipc.h4
-rw-r--r--include/linux/platform_profile.h1
-rw-r--r--include/linux/pm_runtime.h4
-rw-r--r--include/linux/restart_block.h2
-rw-r--r--include/linux/rtc/ds1685.h1
-rw-r--r--include/linux/slab.h7
-rw-r--r--include/linux/sunrpc/bc_xprt.h7
-rw-r--r--include/linux/wmi.h15
-rw-r--r--include/sound/hda-sdw-bpt.h7
-rw-r--r--include/sound/hdaudio.h3
-rw-r--r--include/uapi/linux/i2c.h2
-rw-r--r--include/uapi/sound/asound.h2
-rw-r--r--io_uring/io_uring.c3
-rw-r--r--kernel/dma/pool.c2
-rw-r--r--kernel/futex/waitwake.c9
-rw-r--r--kernel/irq/irqdesc.c6
-rw-r--r--mm/slab.h1
-rw-r--r--mm/slab_common.c52
-rw-r--r--mm/slub.c55
-rw-r--r--net/sunrpc/backchannel_rqst.c35
-rw-r--r--net/sunrpc/xprtrdma/backchannel.c8
-rw-r--r--scripts/coccinelle/api/pm_runtime.cocci1
-rwxr-xr-xscripts/package/install-extmod-build2
-rw-r--r--scripts/tracepoint-update.c3
-rw-r--r--sound/core/Kconfig2
-rw-r--r--sound/firewire/motu/motu-hwdep.c7
-rw-r--r--sound/hda/codecs/realtek/alc269.c4
-rw-r--r--sound/hda/codecs/side-codecs/cs35l41_hda.c2
-rw-r--r--sound/hda/controllers/Kconfig14
-rw-r--r--sound/hda/controllers/Makefile2
-rw-r--r--sound/hda/controllers/cix-ipbloq.c436
-rw-r--r--sound/hda/core/bus.c1
-rw-r--r--sound/hda/core/controller.c12
-rw-r--r--sound/hda/core/intel-dsp-config.c3
-rw-r--r--sound/hda/core/stream.c10
-rw-r--r--sound/soc/amd/acp/acp-i2s.c2
-rw-r--r--sound/soc/amd/acp/acp-legacy-common.c30
-rw-r--r--sound/soc/bcm/bcm63xx-pcm-whistler.c4
-rw-r--r--sound/soc/codecs/Kconfig3
-rw-r--r--sound/soc/codecs/ak4458.c10
-rw-r--r--sound/soc/codecs/ak5558.c10
-rw-r--r--sound/soc/codecs/cs-amp-lib.c29
-rw-r--r--sound/soc/codecs/cs35l41.c7
-rw-r--r--sound/soc/codecs/nau8325.c4
-rw-r--r--sound/soc/codecs/wcd937x.c4
-rw-r--r--sound/soc/codecs/wcd938x.c3
-rw-r--r--sound/soc/codecs/wcd939x.c3
-rw-r--r--sound/soc/qcom/qdsp6/q6afe.c4
-rw-r--r--sound/soc/rockchip/rockchip_pdm.c2
-rw-r--r--sound/soc/sof/intel/hda-sdw-bpt.c13
-rw-r--r--sound/usb/mixer_quirks.c1
-rw-r--r--tools/power/x86/intel-speed-select/isst-config.c2
-rw-r--r--tools/power/x86/intel-speed-select/isst-core-tpmi.c46
-rw-r--r--tools/testing/selftests/futex/functional/.gitignore1
-rw-r--r--tools/testing/selftests/futex/functional/Makefile3
-rw-r--r--tools/testing/selftests/futex/functional/futex_numa_mpol.c5
-rw-r--r--tools/testing/selftests/futex/functional/futex_wait.c8
-rw-r--r--tools/testing/selftests/futex/functional/futex_waitv.c2
-rw-r--r--tools/testing/selftests/futex/functional/robust_list.c552
463 files changed, 16357 insertions, 4751 deletions
diff --git a/Documentation/ABI/testing/rtc-cdev b/Documentation/ABI/testing/rtc-cdev
index 25910c3c3d7e..cec099a27c6d 100644
--- a/Documentation/ABI/testing/rtc-cdev
+++ b/Documentation/ABI/testing/rtc-cdev
@@ -14,7 +14,7 @@ Description:
for RTCs that support alarms
* RTC_ALM_READ, RTC_ALM_SET: Read or set the alarm time for
- RTCs that support alarms. Can be set upto 24 hours in the
+ RTCs that support alarms. Can be set up to 24 hours in the
future. Requires a separate RTC_AIE_ON call to enable the
alarm interrupt. (Prefer to use RTC_WKALM_*)
diff --git a/Documentation/ABI/testing/sysfs-class-platform-profile b/Documentation/ABI/testing/sysfs-class-platform-profile
index dc72adfb830a..fcab26894ec3 100644
--- a/Documentation/ABI/testing/sysfs-class-platform-profile
+++ b/Documentation/ABI/testing/sysfs-class-platform-profile
@@ -23,6 +23,8 @@ Description: This file contains a space-separated list of profiles supported
power consumption with a slight bias
towards performance
performance High performance operation
+ max-power Higher performance operation that may exceed
+ internal battery draw limits when on AC power
custom Driver defined custom profile
==================== ========================================
diff --git a/Documentation/ABI/testing/sysfs-driver-uniwill-laptop b/Documentation/ABI/testing/sysfs-driver-uniwill-laptop
new file mode 100644
index 000000000000..eaeb659793d2
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-uniwill-laptop
@@ -0,0 +1,53 @@
+What: /sys/bus/platform/devices/INOU0000:XX/fn_lock_toggle_enable
+Date: November 2025
+KernelVersion: 6.19
+Contact: Armin Wolf <W_Armin@gmx.de>
+Description:
+ Allows userspace applications to enable/disable the FN lock feature
+ of the integrated keyboard by writing "1"/"0" into this file.
+
+ Reading this file returns the current enable status of the FN lock functionality.
+
+What: /sys/bus/platform/devices/INOU0000:XX/super_key_toggle_enable
+Date: November 2025
+KernelVersion: 6.19
+Contact: Armin Wolf <W_Armin@gmx.de>
+Description:
+ Allows userspace applications to enable/disable the super key functionality
+ of the integrated keyboard by writing "1"/"0" into this file.
+
+ Reading this file returns the current enable status of the super key functionality.
+
+What: /sys/bus/platform/devices/INOU0000:XX/touchpad_toggle_enable
+Date: November 2025
+KernelVersion: 6.19
+Contact: Armin Wolf <W_Armin@gmx.de>
+Description:
+ Allows userspace applications to enable/disable the touchpad toggle functionality
+ of the integrated touchpad by writing "1"/"0" into this file.
+
+ Reading this file returns the current enable status of the touchpad toggle
+ functionality.
+
+What: /sys/bus/platform/devices/INOU0000:XX/rainbow_animation
+Date: November 2025
+KernelVersion: 6.19
+Contact: Armin Wolf <W_Armin@gmx.de>
+Description:
+ Forces the integrated lightbar to display a rainbow animation when the machine
+ is not suspended. Writing "1"/"0" into this file enables/disables this
+ functionality.
+
+ Reading this file returns the current status of the rainbow animation functionality.
+
+What: /sys/bus/platform/devices/INOU0000:XX/breathing_in_suspend
+Date: November 2025
+KernelVersion: 6.19
+Contact: Armin Wolf <W_Armin@gmx.de>
+Description:
+ Causes the integrated lightbar to display a breathing animation when the machine
+ has been suspended and is running on AC power. Writing "1"/"0" into this file
+ enables/disables this functionality.
+
+ Reading this file returns the current status of the breathing animation
+ functionality.
diff --git a/Documentation/ABI/testing/sysfs-platform-asus-wmi b/Documentation/ABI/testing/sysfs-platform-asus-wmi
index 28144371a0f1..89acb6638df8 100644
--- a/Documentation/ABI/testing/sysfs-platform-asus-wmi
+++ b/Documentation/ABI/testing/sysfs-platform-asus-wmi
@@ -63,6 +63,7 @@ Date: Aug 2022
KernelVersion: 6.1
Contact: "Luke Jones" <luke@ljones.dev>
Description:
+ DEPRECATED, WILL BE REMOVED SOON: please use asus-armoury
Switch the GPU hardware MUX mode. Laptops with this feature can
can be toggled to boot with only the dGPU (discrete mode) or in
standard Optimus/Hybrid mode. On switch a reboot is required:
@@ -75,6 +76,7 @@ Date: Aug 2022
KernelVersion: 5.17
Contact: "Luke Jones" <luke@ljones.dev>
Description:
+ DEPRECATED, WILL BE REMOVED SOON: please use asus-armoury
Disable discrete GPU:
* 0 - Enable dGPU,
* 1 - Disable dGPU
@@ -84,6 +86,7 @@ Date: Aug 2022
KernelVersion: 5.17
Contact: "Luke Jones" <luke@ljones.dev>
Description:
+ DEPRECATED, WILL BE REMOVED SOON: please use asus-armoury
Enable the external GPU paired with ROG X-Flow laptops.
Toggling this setting will also trigger ACPI to disable the dGPU:
@@ -95,6 +98,7 @@ Date: Aug 2022
KernelVersion: 5.17
Contact: "Luke Jones" <luke@ljones.dev>
Description:
+ DEPRECATED, WILL BE REMOVED SOON: please use asus-armoury
Enable an LCD response-time boost to reduce or remove ghosting:
* 0 - Disable,
* 1 - Enable
@@ -104,6 +108,7 @@ Date: Jun 2023
KernelVersion: 6.5
Contact: "Luke Jones" <luke@ljones.dev>
Description:
+ DEPRECATED, WILL BE REMOVED SOON: please use asus-armoury
Get the current charging mode being used:
* 1 - Barrel connected charger,
* 2 - USB-C charging
@@ -114,6 +119,7 @@ Date: Jun 2023
KernelVersion: 6.5
Contact: "Luke Jones" <luke@ljones.dev>
Description:
+ DEPRECATED, WILL BE REMOVED SOON: please use asus-armoury
Show if the egpu (XG Mobile) is correctly connected:
* 0 - False,
* 1 - True
@@ -123,6 +129,7 @@ Date: Jun 2023
KernelVersion: 6.5
Contact: "Luke Jones" <luke@ljones.dev>
Description:
+ DEPRECATED, WILL BE REMOVED SOON: please use asus-armoury
Change the mini-LED mode:
* 0 - Single-zone,
* 1 - Multi-zone
@@ -133,6 +140,7 @@ Date: Apr 2024
KernelVersion: 6.10
Contact: "Luke Jones" <luke@ljones.dev>
Description:
+ DEPRECATED, WILL BE REMOVED SOON: please use asus-armoury
List the available mini-led modes.
What: /sys/devices/platform/<platform>/ppt_pl1_spl
@@ -140,6 +148,7 @@ Date: Jun 2023
KernelVersion: 6.5
Contact: "Luke Jones" <luke@ljones.dev>
Description:
+ DEPRECATED, WILL BE REMOVED SOON: please use asus-armoury
Set the Package Power Target total of CPU: PL1 on Intel, SPL on AMD.
Shown on Intel+Nvidia or AMD+Nvidia based systems:
@@ -150,6 +159,7 @@ Date: Jun 2023
KernelVersion: 6.5
Contact: "Luke Jones" <luke@ljones.dev>
Description:
+ DEPRECATED, WILL BE REMOVED SOON: please use asus-armoury
Set the Slow Package Power Tracking Limit of CPU: PL2 on Intel, SPPT,
on AMD. Shown on Intel+Nvidia or AMD+Nvidia based systems:
@@ -160,6 +170,7 @@ Date: Jun 2023
KernelVersion: 6.5
Contact: "Luke Jones" <luke@ljones.dev>
Description:
+ DEPRECATED, WILL BE REMOVED SOON: please use asus-armoury
Set the Fast Package Power Tracking Limit of CPU. AMD+Nvidia only:
* min=5, max=250
@@ -168,6 +179,7 @@ Date: Jun 2023
KernelVersion: 6.5
Contact: "Luke Jones" <luke@ljones.dev>
Description:
+ DEPRECATED, WILL BE REMOVED SOON: please use asus-armoury
Set the APU SPPT limit. Shown on full AMD systems only:
* min=5, max=130
@@ -176,6 +188,7 @@ Date: Jun 2023
KernelVersion: 6.5
Contact: "Luke Jones" <luke@ljones.dev>
Description:
+ DEPRECATED, WILL BE REMOVED SOON: please use asus-armoury
Set the platform SPPT limit. Shown on full AMD systems only:
* min=5, max=130
@@ -184,6 +197,7 @@ Date: Jun 2023
KernelVersion: 6.5
Contact: "Luke Jones" <luke@ljones.dev>
Description:
+ DEPRECATED, WILL BE REMOVED SOON: please use asus-armoury
Set the dynamic boost limit of the Nvidia dGPU:
* min=5, max=25
@@ -192,6 +206,7 @@ Date: Jun 2023
KernelVersion: 6.5
Contact: "Luke Jones" <luke@ljones.dev>
Description:
+ DEPRECATED, WILL BE REMOVED SOON: please use asus-armoury
Set the target temperature limit of the Nvidia dGPU:
* min=75, max=87
@@ -200,6 +215,7 @@ Date: Apr 2024
KernelVersion: 6.10
Contact: "Luke Jones" <luke@ljones.dev>
Description:
+ DEPRECATED, WILL BE REMOVED SOON: please use asus-armoury
Set if the BIOS POST sound is played on boot.
* 0 - False,
* 1 - True
@@ -209,6 +225,7 @@ Date: Apr 2024
KernelVersion: 6.10
Contact: "Luke Jones" <luke@ljones.dev>
Description:
+ DEPRECATED, WILL BE REMOVED SOON: please use asus-armoury
Set if the MCU can go in to low-power mode on system sleep
* 0 - False,
* 1 - True
diff --git a/Documentation/ABI/testing/sysfs-platform-ayaneo-ec b/Documentation/ABI/testing/sysfs-platform-ayaneo-ec
new file mode 100644
index 000000000000..4cffbf5fc7ca
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-platform-ayaneo-ec
@@ -0,0 +1,19 @@
+What: /sys/devices/platform/ayaneo-ec/controller_power
+Date: Nov 2025
+KernelVersion: 6.19
+Contact: "Antheas Kapenekakis" <lkml@antheas.dev>
+Description:
+ Current controller power state. Allows turning on and off
+ the controller power (e.g. for power savings). Write 1 to
+ turn on, 0 to turn off. File is readable and writable.
+
+What: /sys/devices/platform/ayaneo-ec/controller_modules
+Date: Nov 2025
+KernelVersion: 6.19
+Contact: "Antheas Kapenekakis" <lkml@antheas.dev>
+Description:
+ Shows which controller modules are currently connected to
+ the device. Possible values are "left", "right" and "both".
+ File is read-only. The Windows software for this device
+ will only set controller power to 1 if both module sides
+ are connected (i.e. this file returns "both").
diff --git a/Documentation/admin-guide/device-mapper/dm-raid.rst b/Documentation/admin-guide/device-mapper/dm-raid.rst
index bb17e26e3c1b..e11f10764770 100644
--- a/Documentation/admin-guide/device-mapper/dm-raid.rst
+++ b/Documentation/admin-guide/device-mapper/dm-raid.rst
@@ -20,10 +20,10 @@ The target is named "raid" and it accepts the following parameters::
raid0 RAID0 striping (no resilience)
raid1 RAID1 mirroring
raid4 RAID4 with dedicated last parity disk
- raid5_n RAID5 with dedicated last parity disk supporting takeover
+ raid5_n RAID5 with dedicated last parity disk supporting takeover from/to raid1
Same as raid4
- - Transitory layout
+ - Transitory layout for takeover from/to raid1
raid5_la RAID5 left asymmetric
- rotating parity 0 with data continuation
@@ -48,8 +48,8 @@ The target is named "raid" and it accepts the following parameters::
raid6_n_6 RAID6 with dedicate parity disks
- parity and Q-syndrome on the last 2 disks;
- layout for takeover from/to raid4/raid5_n
- raid6_la_6 Same as "raid_la" plus dedicated last Q-syndrome disk
+ layout for takeover from/to raid0/raid4/raid5_n
+ raid6_la_6 Same as "raid_la" plus dedicated last Q-syndrome disk supporting takeover from/to raid5
- layout for takeover from raid5_la from/to raid6
raid6_ra_6 Same as "raid5_ra" dedicated last Q-syndrome disk
@@ -173,9 +173,9 @@ The target is named "raid" and it accepts the following parameters::
The delta_disks option value (-251 < N < +251) triggers
device removal (negative value) or device addition (positive
value) to any reshape supporting raid levels 4/5/6 and 10.
- RAID levels 4/5/6 allow for addition of devices (metadata
- and data device tuple), raid10_near and raid10_offset only
- allow for device addition. raid10_far does not support any
+ RAID levels 4/5/6 allow for addition and removal of devices
+ (metadata and data device tuple), raid10_near and raid10_offset
+ only allow for device addition. raid10_far does not support any
reshaping at all.
A minimum of devices have to be kept to enforce resilience,
which is 3 devices for raid4/5 and 4 devices for raid6.
@@ -372,6 +372,72 @@ to safely enable discard support for RAID 4/5/6:
'devices_handle_discards_safely'
+Takeover/Reshape Support
+------------------------
+The target natively supports these two types of MDRAID conversions:
+
+o Takeover: Converts an array from one RAID level to another
+
+o Reshape: Changes the internal layout while maintaining the current RAID level
+
+Each operation is only valid under specific constraints imposed by the existing array's layout and configuration.
+
+
+Takeover:
+linear -> raid1 with N >= 2 mirrors
+raid0 -> raid4 (add dedicated parity device)
+raid0 -> raid5 (add dedicated parity device)
+raid0 -> raid10 with near layout and N >= 2 mirror groups (raid0 stripes have to become first member within mirror groups)
+raid1 -> linear
+raid1 -> raid5 with 2 mirrors
+raid4 -> raid5 w/ rotating parity
+raid5 with dedicated parity device -> raid4
+raid5 -> raid6 (with dedicated Q-syndrome)
+raid6 (with dedicated Q-syndrome) -> raid5
+raid10 with near layout and even number of disks -> raid0 (select any in-sync device from each mirror group)
+
+Reshape:
+linear: not possible
+raid0: not possible
+raid1: change number of mirrors
+raid4: add and remove stripes (minimum 3), change stripesize
+raid5: add and remove stripes (minimum 3, special case 2 for raid1 takeover), change rotating parity algorithms, change stripesize
+raid6: add and remove stripes (minimum 4), change rotating syndrome algorithms, change stripesize
+raid10 near: add stripes (minimum 4), change stripesize, no stripe removal possible, change to offset layout
+raid10 offset: add stripes, change stripesize, no stripe removal possible, change to near layout
+raid10 far: not possible
+
+Table line examples:
+
+### raid1 -> raid5
+#
+# 2 devices limitation in raid1.
+# raid5 personality is able to just map 2 like raid1.
+# Reshape after takeover to change to full raid5 layout
+
+ 0 1960886272 raid raid1 3 0 region_size 2048 2 /dev/dm-0 /dev/dm-1 /dev/dm-2 /dev/dm-3
+
+# dm-0 and dm-2 are e.g. 4MiB large metadata devices, dm-1 and dm-3 have to be at least 1960886272 big.
+#
+# Table line to takeover to raid5
+
+ 0 1960886272 raid raid5 3 0 region_size 2048 2 /dev/dm-0 /dev/dm-1 /dev/dm-2 /dev/dm-3
+
+# Add required out-of-place reshape space to the beginniong of the given 2 data devices,
+# allocate another metadata/data device tuple with the same sizes for the parity space
+# and zero the first 4K of the metadata device.
+#
+# Example table of the out-of-place reshape space addition for one data device, e.g. dm-1
+
+ 0 8192 linear 8:0 0 1960903888 # <- must be free space segment
+ 8192 1960886272 linear 8:0 0 2048 # previous data segment
+
+# Mapping table for e.g. raid5_rs reshape causing the size of the raid device to double-fold once the reshape finishes.
+# Check the status output (e.g. "dmsetup status $RaidDev") for progess.
+
+ 0 $((2 * 1960886272)) raid raid5 7 0 region_size 2048 data_offset 8192 delta_disk 1 2 /dev/dm-0 /dev/dm-1 /dev/dm-2 /dev/dm-3
+
+
Version History
---------------
diff --git a/Documentation/admin-guide/device-mapper/verity.rst b/Documentation/admin-guide/device-mapper/verity.rst
index 8c3f1f967a3c..3ecab1cff9c6 100644
--- a/Documentation/admin-guide/device-mapper/verity.rst
+++ b/Documentation/admin-guide/device-mapper/verity.rst
@@ -236,8 +236,10 @@ is available at the cryptsetup project's wiki page
Status
======
-V (for Valid) is returned if every check performed so far was valid.
-If any check failed, C (for Corruption) is returned.
+1. V (for Valid) is returned if every check performed so far was valid.
+ If any check failed, C (for Corruption) is returned.
+2. Number of corrected blocks by Forward Error Correction.
+ '-' if Forward Error Correction is not enabled.
Example
=======
diff --git a/Documentation/admin-guide/laptops/index.rst b/Documentation/admin-guide/laptops/index.rst
index db842b629303..6432c251dc95 100644
--- a/Documentation/admin-guide/laptops/index.rst
+++ b/Documentation/admin-guide/laptops/index.rst
@@ -17,3 +17,4 @@ Laptop Drivers
sonypi
thinkpad-acpi
toshiba_haps
+ uniwill-laptop
diff --git a/Documentation/admin-guide/laptops/uniwill-laptop.rst b/Documentation/admin-guide/laptops/uniwill-laptop.rst
new file mode 100644
index 000000000000..a16baf15516b
--- /dev/null
+++ b/Documentation/admin-guide/laptops/uniwill-laptop.rst
@@ -0,0 +1,60 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+Uniwill laptop extra features
+=============================
+
+On laptops manufactured by Uniwill (either directly or as ODM), the ``uniwill-laptop`` driver
+handles various platform-specific features.
+
+Module Loading
+--------------
+
+The ``uniwill-laptop`` driver relies on a DMI table to automatically load on supported devices.
+When using the ``force`` module parameter, this DMI check will be omitted, allowing the driver
+to be loaded on unsupported devices for testing purposes.
+
+Hotkeys
+-------
+
+Usually the FN keys work without a special driver. However as soon as the ``uniwill-laptop`` driver
+is loaded, the FN keys need to be handled manually. This is done automatically by the driver itself.
+
+Keyboard settings
+-----------------
+
+The ``uniwill-laptop`` driver allows the user to enable/disable:
+
+ - the FN and super key lock functionality of the integrated keyboard
+ - the touchpad toggle functionality of the integrated touchpad
+
+See Documentation/ABI/testing/sysfs-driver-uniwill-laptop for details.
+
+Hwmon interface
+---------------
+
+The ``uniwill-laptop`` driver supports reading of the CPU and GPU temperature and supports up to
+two fans. Userspace applications can access sensor readings over the hwmon sysfs interface.
+
+Platform profile
+----------------
+
+Support for changing the platform performance mode is currently not implemented.
+
+Battery Charging Control
+------------------------
+
+The ``uniwill-laptop`` driver supports controlling the battery charge limit. This happens over
+the standard ``charge_control_end_threshold`` power supply sysfs attribute. All values
+between 1 and 100 percent are supported.
+
+Additionally the driver signals the presence of battery charging issues through the standard
+``health`` power supply sysfs attribute.
+
+Lightbar
+--------
+
+The ``uniwill-laptop`` driver exposes the lightbar found on some models as a standard multicolor
+LED class device. The default name of this LED class device is ``uniwill:multicolor:status``.
+
+See Documentation/ABI/testing/sysfs-driver-uniwill-laptop for details on how to control the various
+animation modes of the lightbar.
diff --git a/Documentation/devicetree/bindings/eeprom/at24.yaml b/Documentation/devicetree/bindings/eeprom/at24.yaml
index 50af7ccf6e21..c21282634780 100644
--- a/Documentation/devicetree/bindings/eeprom/at24.yaml
+++ b/Documentation/devicetree/bindings/eeprom/at24.yaml
@@ -131,6 +131,7 @@ properties:
- const: atmel,24c32
- items:
- enum:
+ - belling,bl24s64
- onnn,n24s64b
- puya,p24c64f
- const: atmel,24c64
diff --git a/Documentation/devicetree/bindings/i2c/i2c-rk3x.yaml b/Documentation/devicetree/bindings/i2c/i2c-rk3x.yaml
index 4ac5a40a3886..91805fe8f393 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-rk3x.yaml
+++ b/Documentation/devicetree/bindings/i2c/i2c-rk3x.yaml
@@ -37,6 +37,7 @@ properties:
- rockchip,px30-i2c
- rockchip,rk3308-i2c
- rockchip,rk3328-i2c
+ - rockchip,rk3506-i2c
- rockchip,rk3528-i2c
- rockchip,rk3562-i2c
- rockchip,rk3568-i2c
diff --git a/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml b/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml
index 9bc99d736343..33852a5ffca8 100644
--- a/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml
+++ b/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml
@@ -15,6 +15,7 @@ properties:
oneOf:
- enum:
- qcom,msm8226-cci
+ - qcom,msm8953-cci
- qcom,msm8974-cci
- qcom,msm8996-cci
@@ -25,6 +26,7 @@ properties:
- items:
- enum:
+ - qcom,kaanapali-cci
- qcom,qcm2290-cci
- qcom,sa8775p-cci
- qcom,sc7280-cci
@@ -128,6 +130,7 @@ allOf:
compatible:
contains:
enum:
+ - qcom,kaanapali-cci
- qcom,qcm2290-cci
then:
properties:
@@ -146,6 +149,7 @@ allOf:
- contains:
enum:
- qcom,msm8916-cci
+ - qcom,msm8953-cci
- const: qcom,msm8996-cci
then:
diff --git a/Documentation/devicetree/bindings/input/ti,twl4030-keypad.yaml b/Documentation/devicetree/bindings/input/ti,twl4030-keypad.yaml
new file mode 100644
index 000000000000..c69aa7f5cca7
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/ti,twl4030-keypad.yaml
@@ -0,0 +1,59 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/input/ti,twl4030-keypad.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Texas Instruments TWL4030-family Keypad Controller
+
+maintainers:
+ - Peter Ujfalusi <peter.ujfalusi@gmail.com>
+
+description:
+ TWL4030's Keypad controller is used to interface a SoC with a matrix-type
+ keypad device. The keypad controller supports multiple row and column lines.
+ A key can be placed at each intersection of a unique row and a unique column.
+ The keypad controller can sense a key-press and key-release and report the
+ event using a interrupt to the cpu.
+
+allOf:
+ - $ref: matrix-keymap.yaml#
+
+properties:
+ compatible:
+ const: ti,twl4030-keypad
+
+ interrupts:
+ maxItems: 1
+
+required:
+ - compatible
+ - interrupts
+ - keypad,num-rows
+ - keypad,num-columns
+ - linux,keymap
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/input/input.h>
+
+ keypad {
+ compatible = "ti,twl4030-keypad";
+ interrupts = <1>;
+ keypad,num-rows = <8>;
+ keypad,num-columns = <8>;
+ linux,keymap = <
+ /* row 0 */
+ MATRIX_KEY(0, 0, KEY_1)
+ MATRIX_KEY(0, 1, KEY_2)
+ MATRIX_KEY(0, 2, KEY_3)
+
+ /* ...and so on for a full 8x8 matrix... */
+
+ /* row 7 */
+ MATRIX_KEY(7, 6, KEY_Y)
+ MATRIX_KEY(7, 7, KEY_Z)
+ >;
+ };
diff --git a/Documentation/devicetree/bindings/input/touchscreen/ar1021.txt b/Documentation/devicetree/bindings/input/touchscreen/ar1021.txt
deleted file mode 100644
index 82019bd6094e..000000000000
--- a/Documentation/devicetree/bindings/input/touchscreen/ar1021.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-* Microchip AR1020 and AR1021 touchscreen interface (I2C)
-
-Required properties:
-- compatible : "microchip,ar1021-i2c"
-- reg : I2C slave address
-- interrupts : touch controller interrupt
-
-Example:
-
- touchscreen@4d {
- compatible = "microchip,ar1021-i2c";
- reg = <0x4d>;
- interrupt-parent = <&gpio3>;
- interrupts = <11 IRQ_TYPE_LEVEL_HIGH>;
- };
diff --git a/Documentation/devicetree/bindings/input/touchscreen/azoteq,iqs5xx.yaml b/Documentation/devicetree/bindings/input/touchscreen/azoteq,iqs5xx.yaml
deleted file mode 100644
index b5f377215c09..000000000000
--- a/Documentation/devicetree/bindings/input/touchscreen/azoteq,iqs5xx.yaml
+++ /dev/null
@@ -1,75 +0,0 @@
-# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/input/touchscreen/azoteq,iqs5xx.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: Azoteq IQS550/572/525 Trackpad/Touchscreen Controller
-
-maintainers:
- - Jeff LaBundy <jeff@labundy.com>
-
-description: |
- The Azoteq IQS550, IQS572 and IQS525 trackpad and touchscreen controllers
- employ projected-capacitance sensing and can track up to five independent
- contacts.
-
- Link to datasheet: https://www.azoteq.com/
-
-allOf:
- - $ref: touchscreen.yaml#
-
-properties:
- compatible:
- enum:
- - azoteq,iqs550
- - azoteq,iqs572
- - azoteq,iqs525
-
- reg:
- maxItems: 1
-
- interrupts:
- maxItems: 1
-
- reset-gpios:
- maxItems: 1
-
- wakeup-source: true
-
- touchscreen-size-x: true
- touchscreen-size-y: true
- touchscreen-inverted-x: true
- touchscreen-inverted-y: true
- touchscreen-swapped-x-y: true
-
-required:
- - compatible
- - reg
- - interrupts
-
-additionalProperties: false
-
-examples:
- - |
- #include <dt-bindings/gpio/gpio.h>
- #include <dt-bindings/interrupt-controller/irq.h>
-
- i2c {
- #address-cells = <1>;
- #size-cells = <0>;
-
- touchscreen@74 {
- compatible = "azoteq,iqs550";
- reg = <0x74>;
- interrupt-parent = <&gpio>;
- interrupts = <27 IRQ_TYPE_LEVEL_HIGH>;
- reset-gpios = <&gpio 22 (GPIO_ACTIVE_LOW |
- GPIO_PUSH_PULL)>;
-
- touchscreen-size-x = <800>;
- touchscreen-size-y = <480>;
- };
- };
-
-...
diff --git a/Documentation/devicetree/bindings/input/touchscreen/himax,hx83112b.yaml b/Documentation/devicetree/bindings/input/touchscreen/himax,hx83112b.yaml
deleted file mode 100644
index f5cfacb5e966..000000000000
--- a/Documentation/devicetree/bindings/input/touchscreen/himax,hx83112b.yaml
+++ /dev/null
@@ -1,64 +0,0 @@
-# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/input/touchscreen/himax,hx83112b.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: Himax hx83112b touchscreen controller
-
-maintainers:
- - Job Noorman <job@noorman.info>
-
-allOf:
- - $ref: touchscreen.yaml#
-
-properties:
- compatible:
- enum:
- - himax,hx83100a
- - himax,hx83112b
-
- reg:
- maxItems: 1
-
- interrupts:
- maxItems: 1
-
- reset-gpios:
- maxItems: 1
-
- touchscreen-inverted-x: true
- touchscreen-inverted-y: true
- touchscreen-size-x: true
- touchscreen-size-y: true
- touchscreen-swapped-x-y: true
-
-additionalProperties: false
-
-required:
- - compatible
- - reg
- - interrupts
- - reset-gpios
- - touchscreen-size-x
- - touchscreen-size-y
-
-examples:
- - |
- #include <dt-bindings/interrupt-controller/irq.h>
- #include <dt-bindings/gpio/gpio.h>
- i2c {
- #address-cells = <1>;
- #size-cells = <0>;
- touchscreen@48 {
- compatible = "himax,hx83112b";
- reg = <0x48>;
- interrupt-parent = <&tlmm>;
- interrupts = <65 IRQ_TYPE_LEVEL_LOW>;
- touchscreen-size-x = <1080>;
- touchscreen-size-y = <2160>;
- reset-gpios = <&tlmm 64 GPIO_ACTIVE_LOW>;
- };
- };
-
-...
diff --git a/Documentation/devicetree/bindings/input/touchscreen/hynitron,cstxxx.yaml b/Documentation/devicetree/bindings/input/touchscreen/hynitron,cstxxx.yaml
deleted file mode 100644
index 9cb5d4af00f7..000000000000
--- a/Documentation/devicetree/bindings/input/touchscreen/hynitron,cstxxx.yaml
+++ /dev/null
@@ -1,65 +0,0 @@
-# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/input/touchscreen/hynitron,cstxxx.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: Hynitron cstxxx series touchscreen controller
-
-description: |
- Bindings for Hynitron cstxxx series multi-touch touchscreen
- controllers.
-
-maintainers:
- - Chris Morgan <macromorgan@hotmail.com>
-
-allOf:
- - $ref: touchscreen.yaml#
-
-properties:
- compatible:
- enum:
- - hynitron,cst340
-
- reg:
- maxItems: 1
-
- interrupts:
- maxItems: 1
-
- reset-gpios:
- maxItems: 1
-
- touchscreen-size-x: true
- touchscreen-size-y: true
- touchscreen-inverted-x: true
- touchscreen-inverted-y: true
- touchscreen-swapped-x-y: true
-
-additionalProperties: false
-
-required:
- - compatible
- - reg
- - interrupts
- - reset-gpios
-
-examples:
- - |
- #include <dt-bindings/gpio/gpio.h>
- #include <dt-bindings/interrupt-controller/arm-gic.h>
- i2c {
- #address-cells = <1>;
- #size-cells = <0>;
- touchscreen@1a {
- compatible = "hynitron,cst340";
- reg = <0x1a>;
- interrupt-parent = <&gpio4>;
- interrupts = <9 IRQ_TYPE_EDGE_FALLING>;
- reset-gpios = <&gpio4 6 GPIO_ACTIVE_LOW>;
- touchscreen-size-x = <640>;
- touchscreen-size-y = <480>;
- };
- };
-
-...
diff --git a/Documentation/devicetree/bindings/input/touchscreen/ilitek_ts_i2c.yaml b/Documentation/devicetree/bindings/input/touchscreen/ilitek_ts_i2c.yaml
deleted file mode 100644
index 9f7328999756..000000000000
--- a/Documentation/devicetree/bindings/input/touchscreen/ilitek_ts_i2c.yaml
+++ /dev/null
@@ -1,76 +0,0 @@
-# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/input/touchscreen/ilitek_ts_i2c.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: Ilitek I2C Touchscreen Controller
-
-maintainers:
- - Dmitry Torokhov <dmitry.torokhov@gmail.com>
-
-allOf:
- - $ref: touchscreen.yaml#
-
-properties:
- compatible:
- enum:
- - ilitek,ili210x
- - ilitek,ili2117
- - ilitek,ili2120
- - ilitek,ili2130
- - ilitek,ili2131
- - ilitek,ili2132
- - ilitek,ili2316
- - ilitek,ili2322
- - ilitek,ili2323
- - ilitek,ili2326
- - ilitek,ili251x
- - ilitek,ili2520
- - ilitek,ili2521
-
- reg:
- maxItems: 1
-
- interrupts:
- maxItems: 1
-
- reset-gpios:
- maxItems: 1
-
- wakeup-source:
- type: boolean
- description: touchscreen can be used as a wakeup source.
-
- touchscreen-size-x: true
- touchscreen-size-y: true
- touchscreen-inverted-x: true
- touchscreen-inverted-y: true
- touchscreen-swapped-x-y: true
-
-additionalProperties: false
-
-required:
- - compatible
- - reg
- - interrupts
-
-examples:
- - |
- #include <dt-bindings/interrupt-controller/irq.h>
- #include <dt-bindings/gpio/gpio.h>
- i2c {
- #address-cells = <1>;
- #size-cells = <0>;
-
- touchscreen@41 {
- compatible = "ilitek,ili2520";
- reg = <0x41>;
-
- interrupt-parent = <&gpio1>;
- interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
- reset-gpios = <&gpio1 8 GPIO_ACTIVE_LOW>;
- touchscreen-inverted-y;
- wakeup-source;
- };
- };
diff --git a/Documentation/devicetree/bindings/input/touchscreen/maxim,max11801.yaml b/Documentation/devicetree/bindings/input/touchscreen/maxim,max11801.yaml
deleted file mode 100644
index 4f528d220199..000000000000
--- a/Documentation/devicetree/bindings/input/touchscreen/maxim,max11801.yaml
+++ /dev/null
@@ -1,46 +0,0 @@
-# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/input/touchscreen/maxim,max11801.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: MAXI MAX11801 Resistive touch screen controller with i2c interface
-
-maintainers:
- - Frank Li <Frank.Li@nxp.com>
-
-properties:
- compatible:
- const: maxim,max11801
-
- reg:
- maxItems: 1
-
- interrupts:
- maxItems: 1
-
-allOf:
- - $ref: touchscreen.yaml
-
-required:
- - compatible
- - reg
- - interrupts
-
-unevaluatedProperties: false
-
-examples:
- - |
- #include <dt-bindings/interrupt-controller/irq.h>
-
- i2c {
- #address-cells = <1>;
- #size-cells = <0>;
-
- touchscreen@48 {
- compatible = "maxim,max11801";
- reg = <0x48>;
- interrupt-parent = <&gpio3>;
- interrupts = <31 IRQ_TYPE_EDGE_FALLING>;
- };
- };
diff --git a/Documentation/devicetree/bindings/input/touchscreen/melfas,mip4_ts.yaml b/Documentation/devicetree/bindings/input/touchscreen/melfas,mip4_ts.yaml
new file mode 100644
index 000000000000..314be65c56ca
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/melfas,mip4_ts.yaml
@@ -0,0 +1,56 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/input/touchscreen/melfas,mip4_ts.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MELFAS MIP4 Touchscreen
+
+maintainers:
+ - Ariel D'Alessandro <ariel.dalessandro@collabora.com>
+
+properties:
+ compatible:
+ const: melfas,mip4_ts
+
+ reg:
+ description: I2C address of the chip (0x48 or 0x34)
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ ce-gpios:
+ description:
+ GPIO connected to the CE (chip enable) pin of the chip (active high)
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - interrupts
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ touchscreen@34 {
+ compatible = "melfas,mip4_ts";
+ reg = <0x34>;
+
+ interrupts-extended = <&tlmm 13 IRQ_TYPE_EDGE_FALLING>;
+ ce-gpios = <&tlmm 12 GPIO_ACTIVE_HIGH>;
+
+ pinctrl-0 = <&touchscreen_default>;
+ pinctrl-names = "default";
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/input/touchscreen/melfas_mip4.txt b/Documentation/devicetree/bindings/input/touchscreen/melfas_mip4.txt
deleted file mode 100644
index b2ab5498e519..000000000000
--- a/Documentation/devicetree/bindings/input/touchscreen/melfas_mip4.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-* MELFAS MIP4 Touchscreen
-
-Required properties:
-- compatible: must be "melfas,mip4_ts"
-- reg: I2C slave address of the chip (0x48 or 0x34)
-- interrupts: interrupt to which the chip is connected
-
-Optional properties:
-- ce-gpios: GPIO connected to the CE (chip enable) pin of the chip
-
-Example:
- i2c@00000000 {
- touchscreen: melfas_mip4@48 {
- compatible = "melfas,mip4_ts";
- reg = <0x48>;
- interrupt-parent = <&gpio>;
- interrupts = <0 IRQ_TYPE_EDGE_FALLING>;
- ce-gpios = <&gpio 0 GPIO_ACTIVE_HIGH>;
- };
- };
diff --git a/Documentation/devicetree/bindings/input/touchscreen/semtech,sx8654.yaml b/Documentation/devicetree/bindings/input/touchscreen/semtech,sx8654.yaml
deleted file mode 100644
index b2554064b688..000000000000
--- a/Documentation/devicetree/bindings/input/touchscreen/semtech,sx8654.yaml
+++ /dev/null
@@ -1,52 +0,0 @@
-# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/input/touchscreen/semtech,sx8654.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: Semtech SX8654 I2C Touchscreen Controller
-
-maintainers:
- - Frank Li <Frank.Li@nxp.com>
-
-properties:
- compatible:
- enum:
- - semtech,sx8650
- - semtech,sx8654
- - semtech,sx8655
- - semtech,sx8656
-
- reg:
- maxItems: 1
-
- interrupts:
- maxItems: 1
-
- reset-gpios:
- maxItems: 1
-
-required:
- - compatible
- - reg
- - interrupts
-
-additionalProperties: false
-
-examples:
- - |
- #include <dt-bindings/gpio/gpio.h>
- #include <dt-bindings/interrupt-controller/irq.h>
-
- i2c {
- #address-cells = <1>;
- #size-cells = <0>;
-
- touchscreen@48 {
- compatible = "semtech,sx8654";
- reg = <0x48>;
- interrupt-parent = <&gpio6>;
- interrupts = <3 IRQ_TYPE_EDGE_FALLING>;
- reset-gpios = <&gpio4 2 GPIO_ACTIVE_LOW>;
- };
- };
diff --git a/Documentation/devicetree/bindings/input/touchscreen/trivial-touch.yaml b/Documentation/devicetree/bindings/input/touchscreen/trivial-touch.yaml
new file mode 100644
index 000000000000..fa27c6754ca4
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/trivial-touch.yaml
@@ -0,0 +1,84 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/input/touchscreen/trivial-touch.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Trivial touch screen controller with i2c interface
+
+maintainers:
+ - Frank Li <Frank.Li@nxp.com>
+
+properties:
+ compatible:
+ enum:
+ # The Azoteq IQS550, IQS572 and IQS525 trackpad and touchscreen controllers
+ - azoteq,iqs550
+ - azoteq,iqs572
+ - azoteq,iqs525
+ # Himax hx83100a touchscreen controller
+ - himax,hx83100a
+ # Himax hx83112b touchscreen controller
+ - himax,hx83112b
+ # Hynitron cstxxx series touchscreen controller
+ - hynitron,cst340
+ # Ilitek I2C Touchscreen Controller
+ - ilitek,ili210x
+ - ilitek,ili2117
+ - ilitek,ili2120
+ - ilitek,ili2130
+ - ilitek,ili2131
+ - ilitek,ili2132
+ - ilitek,ili2316
+ - ilitek,ili2322
+ - ilitek,ili2323
+ - ilitek,ili2326
+ - ilitek,ili251x
+ - ilitek,ili2520
+ - ilitek,ili2521
+ # MAXI MAX11801 Resistive touch screen controller with i2c interface
+ - maxim,max11801
+ # Microchip AR1020 and AR1021 touchscreen interface (I2C)
+ - microchip,ar1021-i2c
+ # Trivial touch screen controller with i2c interface
+ - semtech,sx8650
+ - semtech,sx8654
+ - semtech,sx8655
+ - semtech,sx8656
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ reset-gpios:
+ maxItems: 1
+
+ wakeup-source: true
+
+allOf:
+ - $ref: touchscreen.yaml
+
+required:
+ - compatible
+ - reg
+ - interrupts
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ touchscreen@48 {
+ compatible = "maxim,max11801";
+ reg = <0x48>;
+ interrupt-parent = <&gpio3>;
+ interrupts = <31 IRQ_TYPE_EDGE_FALLING>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/input/twl4030-keypad.txt b/Documentation/devicetree/bindings/input/twl4030-keypad.txt
deleted file mode 100644
index e4be2f76a717..000000000000
--- a/Documentation/devicetree/bindings/input/twl4030-keypad.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-* TWL4030's Keypad Controller device tree bindings
-
-TWL4030's Keypad controller is used to interface a SoC with a matrix-type
-keypad device. The keypad controller supports multiple row and column lines.
-A key can be placed at each intersection of a unique row and a unique column.
-The keypad controller can sense a key-press and key-release and report the
-event using a interrupt to the cpu.
-
-This binding is based on the matrix-keymap binding with the following
-changes:
-
- * keypad,num-rows and keypad,num-columns are required.
-
-Required SoC Specific Properties:
-- compatible: should be one of the following
- - "ti,twl4030-keypad": For controllers compatible with twl4030 keypad
- controller.
-- interrupt: should be one of the following
- - <1>: For controllers compatible with twl4030 keypad controller.
-
-Example:
- twl_keypad: keypad {
- compatible = "ti,twl4030-keypad";
- interrupts = <1>;
- keypad,num-rows = <8>;
- keypad,num-columns = <8>;
- };
diff --git a/Documentation/devicetree/bindings/mfd/apple,smc.yaml b/Documentation/devicetree/bindings/mfd/apple,smc.yaml
index 5429538f7e2e..0410e712c900 100644
--- a/Documentation/devicetree/bindings/mfd/apple,smc.yaml
+++ b/Documentation/devicetree/bindings/mfd/apple,smc.yaml
@@ -46,6 +46,9 @@ properties:
reboot:
$ref: /schemas/power/reset/apple,smc-reboot.yaml
+ rtc:
+ $ref: /schemas/rtc/apple,smc-rtc.yaml
+
additionalProperties: false
required:
@@ -80,5 +83,11 @@ examples:
nvmem-cell-names = "shutdown_flag", "boot_stage",
"boot_error_count", "panic_count";
};
+
+ rtc {
+ compatible = "apple,smc-rtc";
+ nvmem-cells = <&rtc_offset>;
+ nvmem-cell-names = "rtc_offset";
+ };
};
};
diff --git a/Documentation/devicetree/bindings/rtc/andestech,atcrtc100.yaml b/Documentation/devicetree/bindings/rtc/andestech,atcrtc100.yaml
new file mode 100644
index 000000000000..ec0a736793c7
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/andestech,atcrtc100.yaml
@@ -0,0 +1,43 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/rtc/andestech,atcrtc100.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Andes ATCRTC100 Real-Time Clock
+
+maintainers:
+ - CL Wang <cl634@andestech.com>
+
+allOf:
+ - $ref: rtc.yaml#
+
+properties:
+ compatible:
+ enum:
+ - andestech,atcrtc100
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ items:
+ - description: Periodic timekeeping interrupt
+ - description: RTC alarm interrupt
+
+required:
+ - compatible
+ - reg
+ - interrupts
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ rtc@f0300000 {
+ compatible = "andestech,atcrtc100";
+ reg = <0xf0300000 0x100>;
+ interrupts = <1 IRQ_TYPE_LEVEL_HIGH>, <2 IRQ_TYPE_LEVEL_HIGH>;
+ };
diff --git a/Documentation/devicetree/bindings/rtc/apple,smc-rtc.yaml b/Documentation/devicetree/bindings/rtc/apple,smc-rtc.yaml
new file mode 100644
index 000000000000..607b610665a2
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/apple,smc-rtc.yaml
@@ -0,0 +1,35 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/rtc/apple,smc-rtc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Apple SMC RTC
+
+description:
+ Apple Silicon Macs (M1, etc.) have an RTC that is part of the PMU IC,
+ but most of the PMU functionality is abstracted out by the SMC.
+ An additional RTC offset stored inside NVMEM is required to compute
+ the current date/time.
+
+maintainers:
+ - Sven Peter <sven@kernel.org>
+
+properties:
+ compatible:
+ const: apple,smc-rtc
+
+ nvmem-cells:
+ items:
+ - description: 48bit RTC offset, specified in 32768 (2^15) Hz clock ticks
+
+ nvmem-cell-names:
+ items:
+ - const: rtc_offset
+
+required:
+ - compatible
+ - nvmem-cells
+ - nvmem-cell-names
+
+additionalProperties: false
diff --git a/Documentation/devicetree/bindings/rtc/nvidia,vrs-10.yaml b/Documentation/devicetree/bindings/rtc/nvidia,vrs-10.yaml
new file mode 100644
index 000000000000..c7dbc8b83c00
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/nvidia,vrs-10.yaml
@@ -0,0 +1,59 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/rtc/nvidia,vrs-10.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NVIDIA Voltage Regulator Specification Real Time Clock
+
+maintainers:
+ - Shubhi Garg <shgarg@nvidia.com>
+
+description:
+ NVIDIA VRS-10 (Voltage Regulator Specification) is a Power Management IC
+ (PMIC) that implements a power sequencing solution with I2C interface.
+ The device includes a real-time clock (RTC) with 32kHz clock output and
+ backup battery support, alarm functionality for system wake-up from
+ suspend and shutdown states, OTP memory for power sequencing configuration,
+ and an interrupt controller for managing VRS events.
+
+properties:
+ compatible:
+ const: nvidia,vrs-10
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ interrupt-controller: true
+
+ '#interrupt-cells':
+ const: 2
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - interrupt-controller
+ - '#interrupt-cells'
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pmic@3c {
+ compatible = "nvidia,vrs-10";
+ reg = <0x3c>;
+ interrupt-parent = <&pmc>;
+ interrupts = <24 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/rtc/renesas,rz-rtca3.yaml b/Documentation/devicetree/bindings/rtc/renesas,rz-rtca3.yaml
index e70eeb66aa64..ccb1638c35b9 100644
--- a/Documentation/devicetree/bindings/rtc/renesas,rz-rtca3.yaml
+++ b/Documentation/devicetree/bindings/rtc/renesas,rz-rtca3.yaml
@@ -9,14 +9,12 @@ title: Renesas RTCA-3 Real Time Clock
maintainers:
- Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
-allOf:
- - $ref: rtc.yaml#
-
properties:
compatible:
items:
- enum:
- renesas,r9a08g045-rtca3 # RZ/G3S
+ - renesas,r9a09g057-rtca3 # RZ/V2H
- const: renesas,rz-rtca3
reg:
@@ -48,8 +46,12 @@ properties:
maxItems: 1
resets:
- items:
- - description: VBATTB module reset
+ minItems: 1
+ maxItems: 2
+
+ reset-names:
+ minItems: 1
+ maxItems: 2
required:
- compatible
@@ -61,6 +63,39 @@ required:
- power-domains
- resets
+allOf:
+ - $ref: rtc.yaml#
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: renesas,r9a08g045-rtca3
+ then:
+ properties:
+ resets:
+ items:
+ - description: VBATTB module reset
+ reset-names:
+ const: vbattb
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: renesas,r9a09g057-rtca3
+ then:
+ properties:
+ resets:
+ items:
+ - description: RTC reset
+ - description: Reset for the RTEST registers
+ reset-names:
+ items:
+ - const: rtc
+ - const: rtest
+ required:
+ - reset-names
+
additionalProperties: false
examples:
@@ -81,4 +116,5 @@ examples:
clock-names = "bus", "counter";
power-domains = <&cpg>;
resets = <&cpg R9A08G045_VBAT_BRESETN>;
+ reset-names = "vbattb";
};
diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs42xx8.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs42xx8.yaml
index cd47905eb20a..7ae72bd901f4 100644
--- a/Documentation/devicetree/bindings/sound/cirrus,cs42xx8.yaml
+++ b/Documentation/devicetree/bindings/sound/cirrus,cs42xx8.yaml
@@ -9,6 +9,9 @@ title: Cirrus Logic CS42448/CS42888 audio CODEC
maintainers:
- patches@opensource.cirrus.com
+allOf:
+ - $ref: dai-common.yaml#
+
properties:
compatible:
enum:
@@ -63,7 +66,7 @@ then:
- VLC-supply
- VLS-supply
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/sound/cix,sky1-ipbloq-hda.yaml b/Documentation/devicetree/bindings/sound/cix,sky1-ipbloq-hda.yaml
new file mode 100644
index 000000000000..02ac5f1aa926
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/cix,sky1-ipbloq-hda.yaml
@@ -0,0 +1,62 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/cix,sky1-ipbloq-hda.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: CIX IPBLOQ HDA controller
+
+description:
+ CIX IPBLOQ High Definition Audio (HDA) Controller
+
+maintainers:
+ - Joakim Zhang <joakim.zhang@cixtech.com>
+
+allOf:
+ - $ref: sound-card-common.yaml#
+
+properties:
+ compatible:
+ const: cix,sky1-ipbloq-hda
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ maxItems: 2
+
+ clock-names:
+ items:
+ - const: ipg
+ - const: per
+
+ resets:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - clocks
+ - clock-names
+ - resets
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include<dt-bindings/interrupt-controller/arm-gic.h>
+
+ hda@70c0000 {
+ compatible = "cix,sky1-ipbloq-hda";
+ reg = <0x70c0000 0x10000>;
+ interrupts = <GIC_SPI 234 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&audss_clk 7>,
+ <&audss_clk 8>;
+ clock-names = "ipg", "per";
+ resets = <&audss_rst 14>;
+ model = "CIX SKY1 EVB HDA";
+ };
diff --git a/Documentation/devicetree/bindings/soundwire/qcom,soundwire.yaml b/Documentation/devicetree/bindings/soundwire/qcom,soundwire.yaml
index 95d947fda6a7..003023729fb8 100644
--- a/Documentation/devicetree/bindings/soundwire/qcom,soundwire.yaml
+++ b/Documentation/devicetree/bindings/soundwire/qcom,soundwire.yaml
@@ -23,6 +23,7 @@ properties:
- qcom,soundwire-v1.6.0
- qcom,soundwire-v1.7.0
- qcom,soundwire-v2.0.0
+ - qcom,soundwire-v3.1.0
- items:
- enum:
- qcom,soundwire-v2.1.0
@@ -73,10 +74,12 @@ properties:
qcom,din-ports:
$ref: /schemas/types.yaml#/definitions/uint32
description: count of data in ports
+ deprecated: true
qcom,dout-ports:
$ref: /schemas/types.yaml#/definitions/uint32
description: count of data out ports
+ deprecated: true
qcom,ports-word-length:
$ref: /schemas/types.yaml#/definitions/uint8-array
@@ -223,8 +226,6 @@ required:
- '#sound-dai-cells'
- '#address-cells'
- '#size-cells'
- - qcom,dout-ports
- - qcom,din-ports
- qcom,ports-offset1
- qcom,ports-offset2
@@ -257,9 +258,6 @@ examples:
clocks = <&lpass_rx_macro>;
clock-names = "iface";
- qcom,din-ports = <0>;
- qcom,dout-ports = <5>;
-
resets = <&lpass_audiocc LPASS_AUDIO_SWR_RX_CGCR>;
reset-names = "swr_audio_cgcr";
diff --git a/Documentation/driver-api/wmi.rst b/Documentation/driver-api/wmi.rst
index 4e8dbdb1fc67..db835b43c937 100644
--- a/Documentation/driver-api/wmi.rst
+++ b/Documentation/driver-api/wmi.rst
@@ -16,5 +16,5 @@ which will be bound to compatible WMI devices by the driver core.
.. kernel-doc:: include/linux/wmi.h
:internal:
-.. kernel-doc:: drivers/platform/x86/wmi.c
+.. kernel-doc:: drivers/platform/wmi/core.c
:export:
diff --git a/Documentation/i2c/busses/i2c-i801.rst b/Documentation/i2c/busses/i2c-i801.rst
index 36c563ad3f06..c939a5bfc8d0 100644
--- a/Documentation/i2c/busses/i2c-i801.rst
+++ b/Documentation/i2c/busses/i2c-i801.rst
@@ -51,6 +51,7 @@ Supported adapters:
* Intel Arrow Lake (SOC)
* Intel Panther Lake (SOC)
* Intel Wildcat Lake (SOC)
+ * Intel Diamond Rapids (SOC)
Datasheets: Publicly available at the Intel website
diff --git a/Documentation/power/runtime_pm.rst b/Documentation/power/runtime_pm.rst
index 8246df3cecd7..455b9d135d85 100644
--- a/Documentation/power/runtime_pm.rst
+++ b/Documentation/power/runtime_pm.rst
@@ -443,13 +443,11 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
necessary to execute the subsystem-level resume callback for the device
to satisfy that request, otherwise 0 is returned
- `int pm_runtime_barrier(struct device *dev);`
+ `void pm_runtime_barrier(struct device *dev);`
- check if there's a resume request pending for the device and resume it
(synchronously) in that case, cancel any other pending runtime PM requests
regarding it and wait for all runtime PM operations on it in progress to
- complete; returns 1 if there was a resume request pending and it was
- necessary to execute the subsystem-level resume callback for the device to
- satisfy that request, otherwise 0 is returned
+ complete
`void pm_suspend_ignore_children(struct device *dev, bool enable);`
- set/unset the power.ignore_children flag of the device
diff --git a/Documentation/wmi/devices/lenovo-wmi-gamezone.rst b/Documentation/wmi/devices/lenovo-wmi-gamezone.rst
index 997263e51a7d..1769ad3d57b9 100644
--- a/Documentation/wmi/devices/lenovo-wmi-gamezone.rst
+++ b/Documentation/wmi/devices/lenovo-wmi-gamezone.rst
@@ -19,27 +19,26 @@ WMI GUID ``887B54E3-DDDC-4B2C-8B88-68A26A8835D0``
The Gamezone Data WMI interface provides platform-profile and fan curve
settings for devices that fall under the "Gaming Series" of Lenovo devices.
It uses a notifier chain to inform other Lenovo WMI interface drivers of the
-current platform profile when it changes.
+current platform profile when it changes. The currently set profile can be
+determined by the user on the hardware by looking at the color of the power
+or profile LED, depending on the model.
The following platform profiles are supported:
- - low-power
- - balanced
- - balanced-performance
- - performance
- - custom
+ - low-power, blue LED
+ - balanced, white LED
+ - performance, red LED
+ - max-power, purple LED
+ - custom, purple LED
-Balanced-Performance
+Extreme Mode
~~~~~~~~~~~~~~~~~~~~
Some newer Lenovo "Gaming Series" laptops have an "Extreme Mode" profile
-enabled in their BIOS. For these devices, the performance platform profile
-corresponds to the BIOS Extreme Mode, while the balanced-performance
-platform profile corresponds to the BIOS Performance mode. For legacy
-devices, the performance platform profile will correspond with the BIOS
-Performance mode.
-
-For some newer devices the "Extreme Mode" profile is incomplete in the BIOS
-and setting it will cause undefined behavior. A BIOS bug quirk table is
-provided to ensure these devices cannot set "Extreme Mode" from the driver.
+enabled in their BIOS. When available, this mode will be represented by the
+max-power platform profile.
+
+For a subset of these devices the "Extreme Mode" profile is incomplete in
+the BIOS and setting it will cause undefined behavior. A BIOS bug quirk table
+is provided to ensure these devices cannot set "Extreme Mode" from the driver.
Custom Profile
~~~~~~~~~~~~~~
diff --git a/Documentation/wmi/devices/uniwill-laptop.rst b/Documentation/wmi/devices/uniwill-laptop.rst
new file mode 100644
index 000000000000..e246bf293450
--- /dev/null
+++ b/Documentation/wmi/devices/uniwill-laptop.rst
@@ -0,0 +1,198 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+
+========================================
+Uniwill Notebook driver (uniwill-laptop)
+========================================
+
+Introduction
+============
+
+Many notebooks manufactured by Uniwill (either directly or as ODM) provide a EC interface
+for controlling various platform settings like sensors and fan control. This interface is
+used by the ``uniwill-laptop`` driver to map those features onto standard kernel interfaces.
+
+EC WMI interface description
+============================
+
+The EC WMI interface description can be decoded from the embedded binary MOF (bmof)
+data using the `bmfdec <https://github.com/pali/bmfdec>`_ utility:
+
+::
+
+ [WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x409"),
+ Description("Class used to operate methods on a ULong"),
+ guid("{ABBC0F6F-8EA1-11d1-00A0-C90629100000}")]
+ class AcpiTest_MULong {
+ [key, read] string InstanceName;
+ [read] boolean Active;
+
+ [WmiMethodId(1), Implemented, read, write, Description("Return the contents of a ULong")]
+ void GetULong([out, Description("Ulong Data")] uint32 Data);
+
+ [WmiMethodId(2), Implemented, read, write, Description("Set the contents of a ULong")]
+ void SetULong([in, Description("Ulong Data")] uint32 Data);
+
+ [WmiMethodId(3), Implemented, read, write,
+ Description("Generate an event containing ULong data")]
+ void FireULong([in, Description("WMI requires a parameter")] uint32 Hack);
+
+ [WmiMethodId(4), Implemented, read, write, Description("Get and Set the contents of a ULong")]
+ void GetSetULong([in, Description("Ulong Data")] uint64 Data,
+ [out, Description("Ulong Data")] uint32 Return);
+
+ [WmiMethodId(5), Implemented, read, write,
+ Description("Get and Set the contents of a ULong for Dollby button")]
+ void GetButton([in, Description("Ulong Data")] uint64 Data,
+ [out, Description("Ulong Data")] uint32 Return);
+ };
+
+Most of the WMI-related code was copied from the Windows driver samples, which unfortunately means
+that the WMI-GUID is not unique. This makes the WMI-GUID unusable for autoloading.
+
+WMI method GetULong()
+---------------------
+
+This WMI method was copied from the Windows driver samples and has no function.
+
+WMI method SetULong()
+---------------------
+
+This WMI method was copied from the Windows driver samples and has no function.
+
+WMI method FireULong()
+----------------------
+
+This WMI method allows to inject a WMI event with a 32-bit payload. Its primary purpose seems
+to be debugging.
+
+WMI method GetSetULong()
+------------------------
+
+This WMI method is used to communicate with the EC. The ``Data`` argument holds the following
+information (starting with the least significant byte):
+
+1. 16-bit address
+2. 16-bit data (set to ``0x0000`` when reading)
+3. 16-bit operation (``0x0100`` for reading and ``0x0000`` for writing)
+4. 16-bit reserved (set to ``0x0000``)
+
+The first 8 bits of the ``Return`` value contain the data returned by the EC when reading.
+The special value ``0xFEFEFEFE`` is used to indicate a communication failure with the EC.
+
+WMI method GetButton()
+----------------------
+
+This WMI method is not implemented on all machines and has an unknown purpose.
+
+Reverse-Engineering the EC WMI interface
+========================================
+
+.. warning:: Randomly poking the EC can potentially cause damage to the machine and other unwanted
+ side effects, please be careful.
+
+The EC behind the ``GetSetULong`` method is used by the OEM software supplied by the manufacturer.
+Reverse-engineering of this software is difficult since it uses an obfuscator, however some parts
+are not obfuscated. In this case `dnSpy <https://github.com/dnSpy/dnSpy>`_ could also be helpful.
+
+The EC can be accessed under Windows using powershell (requires admin privileges):
+
+::
+
+ > $obj = Get-CimInstance -Namespace root/wmi -ClassName AcpiTest_MULong | Select-Object -First 1
+ > Invoke-CimMethod -InputObject $obj -MethodName GetSetULong -Arguments @{Data = <input>}
+
+WMI event interface description
+===============================
+
+The WMI interface description can also be decoded from the embedded binary MOF (bmof)
+data:
+
+::
+
+ [WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x409"),
+ Description("Class containing event generated ULong data"),
+ guid("{ABBC0F72-8EA1-11d1-00A0-C90629100000}")]
+ class AcpiTest_EventULong : WmiEvent {
+ [key, read] string InstanceName;
+ [read] boolean Active;
+
+ [WmiDataId(1), read, write, Description("ULong Data")] uint32 ULong;
+ };
+
+Most of the WMI-related code was again copied from the Windows driver samples, causing this WMI
+interface to suffer from the same restrictions as the EC WMI interface described above.
+
+WMI event data
+--------------
+
+The WMI event data contains a single 32-bit value which is used to indicate various platform events.
+
+Reverse-Engineering the Uniwill WMI event interface
+===================================================
+
+The driver logs debug messages when receiving a WMI event. Thus enabling debug messages will be
+useful for finding unknown event codes.
+
+EC ACPI interface description
+=============================
+
+The ``INOU0000`` ACPI device is a virtual device used to access various hardware registers
+available on notebooks manufactured by Uniwill. Reading and writing those registers happens
+by calling ACPI control methods. The ``uniwill-laptop`` driver uses this device to communicate
+with the EC because the ACPI control methods are faster than the WMI methods described above.
+
+ACPI control methods used for reading registers take a single ACPI integer containing the address
+of the register to read and return a ACPI integer containing the data inside said register. ACPI
+control methods used for writing registers however take two ACPI integers, with the additional
+ACPI integer containing the data to be written into the register. Such ACPI control methods return
+nothing.
+
+System memory
+-------------
+
+System memory can be accessed with a granularity of either a single byte (``MMRB`` for reading and
+``MMWB`` for writing) or four bytes (``MMRD`` for reading and ``MMWD`` for writing). Those ACPI
+control methods are unused because they provide no benefit when compared to the native memory
+access functions provided by the kernel.
+
+EC RAM
+------
+
+The internal RAM of the EC can be accessed with a granularity of a single byte using the ``ECRR``
+(read) and ``ECRW`` (write) ACPI control methods, with the maximum register address being ``0xFFF``.
+The OEM software waits 6 ms after calling one of those ACPI control methods, likely to avoid
+overwhelming the EC when being connected over LPC.
+
+PCI config space
+----------------
+
+The PCI config space can be accessed with a granularity of four bytes using the ``PCRD`` (read) and
+``PCWD`` (write) ACPI control methods. The exact address format is unknown, and poking random PCI
+devices might confuse the PCI subsystem. Because of this those ACPI control methods are not used.
+
+IO ports
+--------
+
+IO ports can be accessed with a granularity of four bytes using the ``IORD`` (read) and ``IOWD``
+(write) ACPI control methods. Those ACPI control methods are unused because they provide no benefit
+when compared to the native IO port access functions provided by the kernel.
+
+CMOS RAM
+--------
+
+The CMOS RAM can be accessed with a granularity of a single byte using the ``RCMS`` (read) and
+``WCMS`` ACPI control methods. Using those ACPI methods might interfere with the native CMOS RAM
+access functions provided by the kernel due to the usage of indexed IO, so they are unused.
+
+Indexed IO
+----------
+
+Indexed IO with IO ports with a granularity of a single byte can be performed using the ``RIOP``
+(read) and ``WIOP`` (write) ACPI control methods. Those ACPI methods are unused because they
+provide no benifit when compared to the native IO port access functions provided by the kernel.
+
+Special thanks go to github user `pobrn` which developed the
+`qc71_laptop <https://github.com/pobrn/qc71_laptop>`_ driver on which this driver is partly based.
+The same is true for Tuxedo Computers, which developed the
+`tuxedo-drivers <https://gitlab.com/tuxedocomputers/development/packages/tuxedo-drivers>`_ package
+which also served as a foundation for this driver.
diff --git a/MAINTAINERS b/MAINTAINERS
index 84cda6701685..56975a34e0de 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -402,7 +402,7 @@ S: Maintained
F: Documentation/ABI/testing/sysfs-bus-wmi
F: Documentation/driver-api/wmi.rst
F: Documentation/wmi/
-F: drivers/platform/x86/wmi.c
+F: drivers/platform/wmi/
F: include/uapi/linux/wmi.h
ACRN HYPERVISOR SERVICE MODULE
@@ -2475,6 +2475,7 @@ F: Documentation/devicetree/bindings/pinctrl/apple,pinctrl.yaml
F: Documentation/devicetree/bindings/power/apple*
F: Documentation/devicetree/bindings/power/reset/apple,smc-reboot.yaml
F: Documentation/devicetree/bindings/pwm/apple,s5l-fpwm.yaml
+F: Documentation/devicetree/bindings/rtc/apple,smc-rtc.yaml
F: Documentation/devicetree/bindings/spi/apple,spi.yaml
F: Documentation/devicetree/bindings/spmi/apple,spmi.yaml
F: Documentation/devicetree/bindings/usb/apple,dwc3.yaml
@@ -2501,6 +2502,7 @@ F: drivers/nvmem/apple-spmi-nvmem.c
F: drivers/pinctrl/pinctrl-apple-gpio.c
F: drivers/power/reset/macsmc-reboot.c
F: drivers/pwm/pwm-apple.c
+F: drivers/rtc/rtc-macsmc.c
F: drivers/soc/apple/*
F: drivers/spi/spi-apple.c
F: drivers/spmi/spmi-apple-controller.c
@@ -4015,6 +4017,12 @@ F: drivers/power/reset/atc260x-poweroff.c
F: drivers/regulator/atc260x-regulator.c
F: include/linux/mfd/atc260x/*
+ATCRTC100 RTC DRIVER
+M: CL Wang <cl634@andestech.com>
+S: Supported
+F: Documentation/devicetree/bindings/rtc/andestech,atcrtc100.yaml
+F: drivers/rtc/rtc-atcrtc100.c
+
ATHEROS 71XX/9XXX GPIO DRIVER
M: Alban Bedel <albeu@free.fr>
S: Maintained
@@ -4262,6 +4270,13 @@ W: https://ez.analog.com/linux-software-drivers
F: Documentation/devicetree/bindings/pwm/adi,axi-pwmgen.yaml
F: drivers/pwm/pwm-axi-pwmgen.c
+AYANEO PLATFORM EC DRIVER
+M: Antheas Kapenekakis <lkml@antheas.dev>
+L: platform-driver-x86@vger.kernel.org
+S: Maintained
+F: Documentation/ABI/testing/sysfs-platform-ayaneo
+F: drivers/platform/x86/ayaneo-ec.c
+
AZ6007 DVB DRIVER
M: Mauro Carvalho Chehab <mchehab@kernel.org>
L: linux-media@vger.kernel.org
@@ -7218,6 +7233,7 @@ DEVICE-MAPPER (LVM)
M: Alasdair Kergon <agk@redhat.com>
M: Mike Snitzer <snitzer@kernel.org>
M: Mikulas Patocka <mpatocka@redhat.com>
+M: Benjamin Marzinski <bmarzins@redhat.com>
L: dm-devel@lists.linux.dev
S: Maintained
Q: http://patchwork.kernel.org/project/dm-devel/list/
@@ -18684,6 +18700,13 @@ S: Maintained
F: drivers/video/fbdev/nvidia/
F: drivers/video/fbdev/riva/
+NVIDIA VRS RTC DRIVER
+M: Shubhi Garg <shgarg@nvidia.com>
+L: linux-tegra@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/rtc/nvidia,vrs-10.yaml
+F: drivers/rtc/rtc-nvidia-vrs10.c
+
NVIDIA WMI EC BACKLIGHT DRIVER
M: Daniel Dadap <ddadap@nvidia.com>
L: platform-driver-x86@vger.kernel.org
@@ -26448,6 +26471,7 @@ F: include/trace/
F: kernel/trace/
F: kernel/tracepoint.c
F: scripts/tracing/
+F: scripts/tracepoint-update.c
F: tools/testing/selftests/ftrace/
TRACING MMIO ACCESSES (MMIOTRACE)
@@ -26789,6 +26813,17 @@ L: linux-scsi@vger.kernel.org
S: Maintained
F: drivers/ufs/host/ufs-renesas.c
+UNIWILL LAPTOP DRIVER
+M: Armin Wolf <W_Armin@gmx.de>
+L: platform-driver-x86@vger.kernel.org
+S: Maintained
+F: Documentation/ABI/testing/sysfs-driver-uniwill-laptop
+F: Documentation/admin-guide/laptops/uniwill-laptop.rst
+F: Documentation/wmi/devices/uniwill-laptop.rst
+F: drivers/platform/x86/uniwill/uniwill-acpi.c
+F: drivers/platform/x86/uniwill/uniwill-wmi.c
+F: drivers/platform/x86/uniwill/uniwill-wmi.h
+
UNSORTED BLOCK IMAGES (UBI)
M: Richard Weinberger <richard@nod.at>
R: Zhihao Cheng <chengzhihao1@huawei.com>
diff --git a/arch/alpha/include/asm/console.h b/arch/alpha/include/asm/console.h
index 088b7b9eb15a..1cabdb6064bb 100644
--- a/arch/alpha/include/asm/console.h
+++ b/arch/alpha/include/asm/console.h
@@ -4,7 +4,7 @@
#include <uapi/asm/console.h>
-#ifndef __ASSEMBLY__
+#ifndef __ASSEMBLER__
extern long callback_puts(long unit, const char *s, long length);
extern long callback_getc(long unit);
extern long callback_open_console(void);
@@ -26,5 +26,5 @@ struct crb_struct;
struct hwrpb_struct;
extern int callback_init_done;
extern void * callback_init(void *);
-#endif /* __ASSEMBLY__ */
+#endif /* __ASSEMBLER__ */
#endif /* __AXP_CONSOLE_H */
diff --git a/arch/alpha/include/asm/page.h b/arch/alpha/include/asm/page.h
index 5ec4c77e432e..d2c6667d73e9 100644
--- a/arch/alpha/include/asm/page.h
+++ b/arch/alpha/include/asm/page.h
@@ -6,7 +6,7 @@
#include <asm/pal.h>
#include <vdso/page.h>
-#ifndef __ASSEMBLY__
+#ifndef __ASSEMBLER__
#define STRICT_MM_TYPECHECKS
@@ -74,7 +74,7 @@ typedef struct page *pgtable_t;
#define PAGE_OFFSET 0xfffffc0000000000
#endif
-#endif /* !__ASSEMBLY__ */
+#endif /* !__ASSEMBLER__ */
#define __pa(x) ((unsigned long) (x) - PAGE_OFFSET)
#define __va(x) ((void *)((unsigned long) (x) + PAGE_OFFSET))
diff --git a/arch/alpha/include/asm/pal.h b/arch/alpha/include/asm/pal.h
index db2b3b18b34c..799a64c05198 100644
--- a/arch/alpha/include/asm/pal.h
+++ b/arch/alpha/include/asm/pal.h
@@ -4,7 +4,7 @@
#include <uapi/asm/pal.h>
-#ifndef __ASSEMBLY__
+#ifndef __ASSEMBLER__
extern void halt(void) __attribute__((noreturn));
#define __halt() __asm__ __volatile__ ("call_pal %0 #halt" : : "i" (PAL_halt))
@@ -183,5 +183,5 @@ qemu_get_vmtime(void)
return v0;
}
-#endif /* !__ASSEMBLY__ */
+#endif /* !__ASSEMBLER__ */
#endif /* __ALPHA_PAL_H */
diff --git a/arch/alpha/include/asm/thread_info.h b/arch/alpha/include/asm/thread_info.h
index 4a4d00b37986..98ccbca64984 100644
--- a/arch/alpha/include/asm/thread_info.h
+++ b/arch/alpha/include/asm/thread_info.h
@@ -4,14 +4,14 @@
#ifdef __KERNEL__
-#ifndef __ASSEMBLY__
+#ifndef __ASSEMBLER__
#include <asm/processor.h>
#include <asm/types.h>
#include <asm/hwrpb.h>
#include <asm/sysinfo.h>
#endif
-#ifndef __ASSEMBLY__
+#ifndef __ASSEMBLER__
struct thread_info {
struct pcb_struct pcb; /* palcode state */
@@ -44,7 +44,7 @@ register struct thread_info *__current_thread_info __asm__("$8");
register unsigned long *current_stack_pointer __asm__ ("$30");
-#endif /* __ASSEMBLY__ */
+#endif /* __ASSEMBLER__ */
/* Thread information allocation. */
#define THREAD_SIZE_ORDER 1
@@ -110,7 +110,7 @@ register unsigned long *current_stack_pointer __asm__ ("$30");
put_user(res, (int __user *)(value)); \
})
-#ifndef __ASSEMBLY__
+#ifndef __ASSEMBLER__
extern void __save_fpu(void);
static inline void save_fpu(void)
diff --git a/arch/alpha/include/uapi/asm/ioctls.h b/arch/alpha/include/uapi/asm/ioctls.h
index 971311605288..a09d04b49cc6 100644
--- a/arch/alpha/include/uapi/asm/ioctls.h
+++ b/arch/alpha/include/uapi/asm/ioctls.h
@@ -23,10 +23,10 @@
#define TCSETSW _IOW('t', 21, struct termios)
#define TCSETSF _IOW('t', 22, struct termios)
-#define TCGETA _IOR('t', 23, struct termio)
-#define TCSETA _IOW('t', 24, struct termio)
-#define TCSETAW _IOW('t', 25, struct termio)
-#define TCSETAF _IOW('t', 28, struct termio)
+#define TCGETA 0x40127417
+#define TCSETA 0x80127418
+#define TCSETAW 0x80127419
+#define TCSETAF 0x8012741c
#define TCSBRK _IO('t', 29)
#define TCXONC _IO('t', 30)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index ff61891abe53..fa83c040ee2d 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -82,7 +82,7 @@ config ARM
select HAS_IOPORT
select HAVE_ARCH_AUDITSYSCALL if AEABI && !OABI_COMPAT
select HAVE_ARCH_BITREVERSE if (CPU_32v7M || CPU_32v7) && !CPU_32v6
- select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL && !CPU_ENDIAN_BE32 && MMU
+ select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL && !CPU_ENDIAN_BE32 && MMU && (!PREEMPT_RT || !SMP)
select HAVE_ARCH_KFENCE if MMU && !XIP_KERNEL
select HAVE_ARCH_KGDB if !CPU_ENDIAN_BE32 && MMU
select HAVE_ARCH_KASAN if MMU && !XIP_KERNEL
@@ -1213,7 +1213,7 @@ config HIGHMEM
config HIGHPTE
bool "Allocate 2nd-level pagetables from highmem" if EXPERT
- depends on HIGHMEM
+ depends on HIGHMEM && !PREEMPT_RT
default y
help
The VM uses one page of physical memory for each page table.
diff --git a/arch/arm/configs/am200epdkit_defconfig b/arch/arm/configs/am200epdkit_defconfig
index 134a559aba3d..2367b1685c1c 100644
--- a/arch/arm/configs/am200epdkit_defconfig
+++ b/arch/arm/configs/am200epdkit_defconfig
@@ -68,7 +68,6 @@ CONFIG_SOUND=m
CONFIG_SND=m
CONFIG_SND_MIXER_OSS=m
CONFIG_SND_PCM_OSS=m
-# CONFIG_SND_SUPPORT_OLD_API is not set
# CONFIG_SND_VERBOSE_PROCFS is not set
CONFIG_SND_PXA2XX_AC97=m
CONFIG_USB_GADGET=y
diff --git a/arch/arm/configs/lpc32xx_defconfig b/arch/arm/configs/lpc32xx_defconfig
index 2bddb0924a8c..b9e2e603cd95 100644
--- a/arch/arm/configs/lpc32xx_defconfig
+++ b/arch/arm/configs/lpc32xx_defconfig
@@ -113,7 +113,6 @@ CONFIG_LOGO=y
# CONFIG_LOGO_LINUX_VGA16 is not set
CONFIG_SOUND=y
CONFIG_SND=y
-# CONFIG_SND_SUPPORT_OLD_API is not set
# CONFIG_SND_VERBOSE_PROCFS is not set
CONFIG_SND_DEBUG=y
CONFIG_SND_DEBUG_VERBOSE=y
diff --git a/arch/arm/configs/omap1_defconfig b/arch/arm/configs/omap1_defconfig
index dee820474f44..df88763fc7c3 100644
--- a/arch/arm/configs/omap1_defconfig
+++ b/arch/arm/configs/omap1_defconfig
@@ -148,7 +148,6 @@ CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_MIXER_OSS=y
CONFIG_SND_PCM_OSS=y
-# CONFIG_SND_SUPPORT_OLD_API is not set
# CONFIG_SND_VERBOSE_PROCFS is not set
CONFIG_SND_DUMMY=y
CONFIG_SND_USB_AUDIO=y
diff --git a/arch/arm/configs/tegra_defconfig b/arch/arm/configs/tegra_defconfig
index ce70ff07c978..68aedaf92667 100644
--- a/arch/arm/configs/tegra_defconfig
+++ b/arch/arm/configs/tegra_defconfig
@@ -219,7 +219,6 @@ CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
CONFIG_LOGO=y
CONFIG_SOUND=y
CONFIG_SND=y
-# CONFIG_SND_SUPPORT_OLD_API is not set
# CONFIG_SND_DRIVERS is not set
CONFIG_SND_HDA_TEGRA=y
CONFIG_SND_HDA_INPUT_BEEP=y
diff --git a/arch/arm/include/asm/word-at-a-time.h b/arch/arm/include/asm/word-at-a-time.h
index f9a3897b06e7..5023f98d8293 100644
--- a/arch/arm/include/asm/word-at-a-time.h
+++ b/arch/arm/include/asm/word-at-a-time.h
@@ -67,7 +67,7 @@ static inline unsigned long find_zero(unsigned long mask)
*/
static inline unsigned long load_unaligned_zeropad(const void *addr)
{
- unsigned long ret, offset;
+ unsigned long ret, tmp;
/* Load word from unaligned pointer addr */
asm(
@@ -75,9 +75,9 @@ static inline unsigned long load_unaligned_zeropad(const void *addr)
"2:\n"
" .pushsection .text.fixup,\"ax\"\n"
" .align 2\n"
- "3: and %1, %2, #0x3\n"
- " bic %2, %2, #0x3\n"
- " ldr %0, [%2]\n"
+ "3: bic %1, %2, #0x3\n"
+ " ldr %0, [%1]\n"
+ " and %1, %2, #0x3\n"
" lsl %1, %1, #0x3\n"
#ifndef __ARMEB__
" lsr %0, %0, %1\n"
@@ -90,7 +90,7 @@ static inline unsigned long load_unaligned_zeropad(const void *addr)
" .align 3\n"
" .long 1b, 3b\n"
" .popsection"
- : "=&r" (ret), "=&r" (offset)
+ : "=&r" (ret), "=&r" (tmp)
: "r" (addr), "Qo" (*(unsigned long *)addr));
return ret;
diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c
index 3c6ddb1afdc4..812380f30ae3 100644
--- a/arch/arm/mm/alignment.c
+++ b/arch/arm/mm/alignment.c
@@ -19,10 +19,11 @@
#include <linux/init.h>
#include <linux/sched/signal.h>
#include <linux/uaccess.h>
+#include <linux/unaligned.h>
#include <asm/cp15.h>
#include <asm/system_info.h>
-#include <linux/unaligned.h>
+#include <asm/system_misc.h>
#include <asm/opcodes.h>
#include "fault.h"
@@ -809,6 +810,9 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
int thumb2_32b = 0;
int fault;
+ if (addr >= TASK_SIZE && user_mode(regs))
+ harden_branch_predictor();
+
if (interrupts_enabled(regs))
local_irq_enable();
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index 2bc828a1940c..ed4330cc3f4e 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -128,6 +128,19 @@ static inline bool is_translation_fault(unsigned int fsr)
return false;
}
+static inline bool is_permission_fault(unsigned int fsr)
+{
+ int fs = fsr_fs(fsr);
+#ifdef CONFIG_ARM_LPAE
+ if ((fs & FS_MMU_NOLL_MASK) == FS_PERM_NOLL)
+ return true;
+#else
+ if (fs == FS_L1_PERM || fs == FS_L2_PERM)
+ return true;
+#endif
+ return false;
+}
+
static void die_kernel_fault(const char *msg, struct mm_struct *mm,
unsigned long addr, unsigned int fsr,
struct pt_regs *regs)
@@ -162,6 +175,8 @@ __do_kernel_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
*/
if (addr < PAGE_SIZE) {
msg = "NULL pointer dereference";
+ } else if (is_permission_fault(fsr) && fsr & FSR_LNX_PF) {
+ msg = "execution of memory";
} else {
if (is_translation_fault(fsr) &&
kfence_handle_page_fault(addr, is_write_fault(fsr), regs))
@@ -183,9 +198,6 @@ __do_user_fault(unsigned long addr, unsigned int fsr, unsigned int sig,
{
struct task_struct *tsk = current;
- if (addr > TASK_SIZE)
- harden_branch_predictor();
-
#ifdef CONFIG_DEBUG_USER
if (((user_debug & UDBG_SEGV) && (sig == SIGSEGV)) ||
((user_debug & UDBG_BUS) && (sig == SIGBUS))) {
@@ -225,19 +237,6 @@ void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
}
#ifdef CONFIG_MMU
-static inline bool is_permission_fault(unsigned int fsr)
-{
- int fs = fsr_fs(fsr);
-#ifdef CONFIG_ARM_LPAE
- if ((fs & FS_MMU_NOLL_MASK) == FS_PERM_NOLL)
- return true;
-#else
- if (fs == FS_L1_PERM || fs == FS_L2_PERM)
- return true;
-#endif
- return false;
-}
-
#ifdef CONFIG_CPU_TTBR0_PAN
static inline bool ttbr0_usermode_access_allowed(struct pt_regs *regs)
{
@@ -260,6 +259,37 @@ static inline bool ttbr0_usermode_access_allowed(struct pt_regs *regs)
#endif
static int __kprobes
+do_kernel_address_page_fault(struct mm_struct *mm, unsigned long addr,
+ unsigned int fsr, struct pt_regs *regs)
+{
+ if (user_mode(regs)) {
+ /*
+ * Fault from user mode for a kernel space address. User mode
+ * should not be faulting in kernel space, which includes the
+ * vector/khelper page. Handle the branch predictor hardening
+ * while interrupts are still disabled, then send a SIGSEGV.
+ */
+ harden_branch_predictor();
+ __do_user_fault(addr, fsr, SIGSEGV, SEGV_MAPERR, regs);
+ } else {
+ /*
+ * Fault from kernel mode. Enable interrupts if they were
+ * enabled in the parent context. Section (upper page table)
+ * translation faults are handled via do_translation_fault(),
+ * so we will only get here for a non-present kernel space
+ * PTE or PTE permission fault. This may happen in exceptional
+ * circumstances and need the fixup tables to be walked.
+ */
+ if (interrupts_enabled(regs))
+ local_irq_enable();
+
+ __do_kernel_fault(mm, addr, fsr, regs);
+ }
+
+ return 0;
+}
+
+static int __kprobes
do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
{
struct mm_struct *mm = current->mm;
@@ -272,6 +302,12 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
if (kprobe_page_fault(regs, fsr))
return 0;
+ /*
+ * Handle kernel addresses faults separately, which avoids touching
+ * the mmap lock from contexts that are not able to sleep.
+ */
+ if (addr >= TASK_SIZE)
+ return do_kernel_address_page_fault(mm, addr, fsr, regs);
/* Enable interrupts if they were enabled in the parent context. */
if (interrupts_enabled(regs))
@@ -448,16 +484,20 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
* We enter here because the first level page table doesn't contain
* a valid entry for the address.
*
- * If the address is in kernel space (>= TASK_SIZE), then we are
- * probably faulting in the vmalloc() area.
+ * If this is a user address (addr < TASK_SIZE), we handle this as a
+ * normal page fault. This leaves the remainder of the function to handle
+ * kernel address translation faults.
+ *
+ * Since user mode is not permitted to access kernel addresses, pass these
+ * directly to do_kernel_address_page_fault() to handle.
*
- * If the init_task's first level page tables contains the relevant
- * entry, we copy the it to this task. If not, we send the process
- * a signal, fixup the exception, or oops the kernel.
+ * Otherwise, we're probably faulting in the vmalloc() area, so try to fix
+ * that up. Note that we must not take any locks or enable interrupts in
+ * this case.
*
- * NOTE! We MUST NOT take any locks for this case. We may be in an
- * interrupt or a critical region, and should only copy the information
- * from the master page table, nothing more.
+ * If vmalloc() fixup fails, that means the non-leaf page tables did not
+ * contain an entry for this address, so handle this via
+ * do_kernel_address_page_fault().
*/
#ifdef CONFIG_MMU
static int __kprobes
@@ -523,7 +563,8 @@ do_translation_fault(unsigned long addr, unsigned int fsr,
return 0;
bad_area:
- do_bad_area(addr, fsr, regs);
+ do_kernel_address_page_fault(current->mm, addr, fsr, regs);
+
return 0;
}
#else /* CONFIG_MMU */
@@ -543,7 +584,16 @@ do_translation_fault(unsigned long addr, unsigned int fsr,
static int
do_sect_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
{
+ /*
+ * If this is a kernel address, but from user mode, then userspace
+ * is trying bad stuff. Invoke the branch predictor handling.
+ * Interrupts are disabled here.
+ */
+ if (addr >= TASK_SIZE && user_mode(regs))
+ harden_branch_predictor();
+
do_bad_area(addr, fsr, regs);
+
return 0;
}
#endif /* CONFIG_ARM_LPAE */
diff --git a/arch/csky/abiv1/inc/abi/regdef.h b/arch/csky/abiv1/inc/abi/regdef.h
index 7b386fd67070..c75ecf2cafd7 100644
--- a/arch/csky/abiv1/inc/abi/regdef.h
+++ b/arch/csky/abiv1/inc/abi/regdef.h
@@ -3,7 +3,7 @@
#ifndef __ASM_CSKY_REGDEF_H
#define __ASM_CSKY_REGDEF_H
-#ifdef __ASSEMBLY__
+#ifdef __ASSEMBLER__
#define syscallid r1
#else
#define syscallid "r1"
diff --git a/arch/csky/abiv2/inc/abi/regdef.h b/arch/csky/abiv2/inc/abi/regdef.h
index 0933addbc27b..fc08d56ccdbe 100644
--- a/arch/csky/abiv2/inc/abi/regdef.h
+++ b/arch/csky/abiv2/inc/abi/regdef.h
@@ -3,7 +3,7 @@
#ifndef __ASM_CSKY_REGDEF_H
#define __ASM_CSKY_REGDEF_H
-#ifdef __ASSEMBLY__
+#ifdef __ASSEMBLER__
#define syscallid r7
#else
#define syscallid "r7"
diff --git a/arch/csky/include/asm/barrier.h b/arch/csky/include/asm/barrier.h
index 15de58b10aec..c33fdcfe3770 100644
--- a/arch/csky/include/asm/barrier.h
+++ b/arch/csky/include/asm/barrier.h
@@ -3,7 +3,7 @@
#ifndef __ASM_CSKY_BARRIER_H
#define __ASM_CSKY_BARRIER_H
-#ifndef __ASSEMBLY__
+#ifndef __ASSEMBLER__
#define nop() asm volatile ("nop\n":::"memory")
@@ -84,5 +84,5 @@
#include <asm-generic/barrier.h>
-#endif /* __ASSEMBLY__ */
+#endif /* __ASSEMBLER__ */
#endif /* __ASM_CSKY_BARRIER_H */
diff --git a/arch/csky/include/asm/cache.h b/arch/csky/include/asm/cache.h
index 4b5c09bf1d25..d575482e0fce 100644
--- a/arch/csky/include/asm/cache.h
+++ b/arch/csky/include/asm/cache.h
@@ -10,7 +10,7 @@
#define ARCH_DMA_MINALIGN L1_CACHE_BYTES
-#ifndef __ASSEMBLY__
+#ifndef __ASSEMBLER__
void dcache_wb_line(unsigned long start);
diff --git a/arch/csky/include/asm/ftrace.h b/arch/csky/include/asm/ftrace.h
index 00f9f7647e3f..21532f218058 100644
--- a/arch/csky/include/asm/ftrace.h
+++ b/arch/csky/include/asm/ftrace.h
@@ -11,7 +11,7 @@
#define MCOUNT_ADDR ((unsigned long)_mcount)
-#ifndef __ASSEMBLY__
+#ifndef __ASSEMBLER__
extern void _mcount(unsigned long);
@@ -28,5 +28,5 @@ struct dyn_arch_ftrace {
void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
unsigned long frame_pointer);
-#endif /* !__ASSEMBLY__ */
+#endif /* !__ASSEMBLER__ */
#endif /* __ASM_CSKY_FTRACE_H */
diff --git a/arch/csky/include/asm/jump_label.h b/arch/csky/include/asm/jump_label.h
index ef2e37a10a0f..603b0caa8024 100644
--- a/arch/csky/include/asm/jump_label.h
+++ b/arch/csky/include/asm/jump_label.h
@@ -3,7 +3,7 @@
#ifndef __ASM_CSKY_JUMP_LABEL_H
#define __ASM_CSKY_JUMP_LABEL_H
-#ifndef __ASSEMBLY__
+#ifndef __ASSEMBLER__
#include <linux/types.h>
@@ -48,5 +48,5 @@ void arch_jump_label_transform_static(struct jump_entry *entry,
enum jump_label_type type);
#define arch_jump_label_transform_static arch_jump_label_transform_static
-#endif /* __ASSEMBLY__ */
+#endif /* __ASSEMBLER__ */
#endif /* __ASM_CSKY_JUMP_LABEL_H */
diff --git a/arch/csky/include/asm/page.h b/arch/csky/include/asm/page.h
index 4911d0892b71..76774dbce869 100644
--- a/arch/csky/include/asm/page.h
+++ b/arch/csky/include/asm/page.h
@@ -26,7 +26,7 @@
#define PHYS_OFFSET_OFFSET (CONFIG_DRAM_BASE & (SSEG_SIZE - 1))
-#ifndef __ASSEMBLY__
+#ifndef __ASSEMBLER__
#include <linux/pfn.h>
@@ -84,5 +84,5 @@ static inline unsigned long virt_to_pfn(const void *kaddr)
#include <asm-generic/memory_model.h>
#include <asm-generic/getorder.h>
-#endif /* !__ASSEMBLY__ */
+#endif /* !__ASSEMBLER__ */
#endif /* __ASM_CSKY_PAGE_H */
diff --git a/arch/csky/include/asm/ptrace.h b/arch/csky/include/asm/ptrace.h
index 0634b7895d81..5f01839e1184 100644
--- a/arch/csky/include/asm/ptrace.h
+++ b/arch/csky/include/asm/ptrace.h
@@ -8,7 +8,7 @@
#include <linux/types.h>
#include <linux/compiler.h>
-#ifndef __ASSEMBLY__
+#ifndef __ASSEMBLER__
#define PS_S 0x80000000 /* Supervisor Mode */
@@ -98,5 +98,5 @@ static inline unsigned long regs_get_register(struct pt_regs *regs,
asmlinkage int syscall_trace_enter(struct pt_regs *regs);
asmlinkage void syscall_trace_exit(struct pt_regs *regs);
-#endif /* __ASSEMBLY__ */
+#endif /* __ASSEMBLER__ */
#endif /* __ASM_CSKY_PTRACE_H */
diff --git a/arch/csky/include/asm/sections.h b/arch/csky/include/asm/sections.h
index 83e82b7c0f6c..ee5cdf226a9b 100644
--- a/arch/csky/include/asm/sections.h
+++ b/arch/csky/include/asm/sections.h
@@ -8,5 +8,6 @@
extern char _start[];
asmlinkage void csky_start(unsigned int unused, void *dtb_start);
+asmlinkage void csky_start_secondary(void);
#endif /* __ASM_SECTIONS_H */
diff --git a/arch/csky/include/asm/string.h b/arch/csky/include/asm/string.h
index a0d81e9d6b8f..82e99f52b547 100644
--- a/arch/csky/include/asm/string.h
+++ b/arch/csky/include/asm/string.h
@@ -3,7 +3,7 @@
#ifndef _CSKY_STRING_MM_H_
#define _CSKY_STRING_MM_H_
-#ifndef __ASSEMBLY__
+#ifndef __ASSEMBLER__
#include <linux/types.h>
#include <linux/compiler.h>
#include <abi/string.h>
diff --git a/arch/csky/include/asm/thread_info.h b/arch/csky/include/asm/thread_info.h
index b5ed788f0c68..fdd4f8ad45ac 100644
--- a/arch/csky/include/asm/thread_info.h
+++ b/arch/csky/include/asm/thread_info.h
@@ -3,7 +3,7 @@
#ifndef _ASM_CSKY_THREAD_INFO_H
#define _ASM_CSKY_THREAD_INFO_H
-#ifndef __ASSEMBLY__
+#ifndef __ASSEMBLER__
#include <asm/types.h>
#include <asm/page.h>
@@ -51,7 +51,7 @@ static inline struct thread_info *current_thread_info(void)
return (struct thread_info *)(sp & ~(THREAD_SIZE - 1));
}
-#endif /* !__ASSEMBLY__ */
+#endif /* !__ASSEMBLER__ */
#define TIF_SIGPENDING 0 /* signal pending */
#define TIF_NOTIFY_RESUME 1 /* callback before returning to user */
diff --git a/arch/csky/include/uapi/asm/ptrace.h b/arch/csky/include/uapi/asm/ptrace.h
index 3be9c14334a6..90a5c36e4345 100644
--- a/arch/csky/include/uapi/asm/ptrace.h
+++ b/arch/csky/include/uapi/asm/ptrace.h
@@ -3,7 +3,7 @@
#ifndef _CSKY_PTRACE_H
#define _CSKY_PTRACE_H
-#ifndef __ASSEMBLY__
+#ifndef __ASSEMBLER__
struct pt_regs {
unsigned long tls;
@@ -47,5 +47,5 @@ struct user_fp {
unsigned long reserved;
};
-#endif /* __ASSEMBLY__ */
+#endif /* __ASSEMBLER__ */
#endif /* _CSKY_PTRACE_H */
diff --git a/arch/csky/mm/fault.c b/arch/csky/mm/fault.c
index a6ca7dff4215..7ff401108985 100644
--- a/arch/csky/mm/fault.c
+++ b/arch/csky/mm/fault.c
@@ -45,8 +45,8 @@ static inline void csky_cmpxchg_fixup(struct pt_regs *regs)
if (trap_no(regs) != VEC_TLBMODIFIED)
return;
- if (instruction_pointer(regs) == csky_cmpxchg_stw)
- instruction_pointer_set(regs, csky_cmpxchg_ldw);
+ if (instruction_pointer(regs) == (unsigned long)&csky_cmpxchg_stw)
+ instruction_pointer_set(regs, (unsigned long)&csky_cmpxchg_ldw);
return;
}
#endif
diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
index 5b1116733d88..730f34214519 100644
--- a/arch/loongarch/Kconfig
+++ b/arch/loongarch/Kconfig
@@ -115,6 +115,7 @@ config LOONGARCH
select GPIOLIB
select HAS_IOPORT
select HAVE_ARCH_AUDITSYSCALL
+ select HAVE_ARCH_BITREVERSE
select HAVE_ARCH_JUMP_LABEL
select HAVE_ARCH_JUMP_LABEL_RELATIVE
select HAVE_ARCH_KASAN
@@ -567,6 +568,10 @@ config ARCH_STRICT_ALIGN
to run kernel only on systems with h/w unaligned access support in
order to optimise for performance.
+config CPU_HAS_AMO
+ bool
+ default 64BIT
+
config CPU_HAS_FPU
bool
default y
diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile
index 96ca1a688984..8d45b860fe56 100644
--- a/arch/loongarch/Makefile
+++ b/arch/loongarch/Makefile
@@ -5,7 +5,12 @@
boot := arch/loongarch/boot
-KBUILD_DEFCONFIG := loongson3_defconfig
+ifeq ($(shell uname -m),loongarch32)
+KBUILD_DEFCONFIG := loongson32_defconfig
+else
+KBUILD_DEFCONFIG := loongson64_defconfig
+endif
+
KBUILD_DTBS := dtbs
image-name-y := vmlinux
diff --git a/arch/loongarch/configs/loongson32_defconfig b/arch/loongarch/configs/loongson32_defconfig
new file mode 100644
index 000000000000..276b1577e0be
--- /dev/null
+++ b/arch/loongarch/configs/loongson32_defconfig
@@ -0,0 +1,1105 @@
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_KERNEL_ZSTD=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_BPF_SYSCALL=y
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_DYNAMIC=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_PSI=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_IKHEADERS=y
+CONFIG_LOG_BUF_SHIFT=18
+CONFIG_MEMCG=y
+CONFIG_BLK_CGROUP=y
+CONFIG_CFS_BANDWIDTH=y
+CONFIG_CGROUP_PIDS=y
+CONFIG_CGROUP_RDMA=y
+CONFIG_CGROUP_DMEM=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_PERF=y
+CONFIG_CGROUP_BPF=y
+CONFIG_CGROUP_MISC=y
+CONFIG_NAMESPACES=y
+CONFIG_USER_NS=y
+CONFIG_CHECKPOINT_RESTORE=y
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_EXPERT=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_PERF_EVENTS=y
+CONFIG_KEXEC=y
+CONFIG_LOONGARCH=y
+CONFIG_32BIT=y
+CONFIG_32BIT_STANDARD=y
+CONFIG_MACH_LOONGSON32=y
+CONFIG_PAGE_SIZE_16KB=y
+CONFIG_HZ_250=y
+CONFIG_DMI=y
+CONFIG_EFI=y
+CONFIG_SUSPEND=y
+CONFIG_HIBERNATION=y
+CONFIG_ACPI=y
+CONFIG_ACPI_SPCR_TABLE=y
+CONFIG_ACPI_TAD=y
+CONFIG_ACPI_DOCK=y
+CONFIG_ACPI_IPMI=m
+CONFIG_ACPI_HOTPLUG_CPU=y
+CONFIG_ACPI_PCI_SLOT=y
+CONFIG_ACPI_HOTPLUG_MEMORY=y
+CONFIG_ACPI_BGRT=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
+CONFIG_VIRTUALIZATION=y
+CONFIG_JUMP_LABEL=y
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_COMPRESS=y
+CONFIG_MODULE_COMPRESS_ZSTD=y
+CONFIG_MODULE_DECOMPRESS=y
+CONFIG_BLK_DEV_ZONED=y
+CONFIG_BLK_DEV_THROTTLING=y
+CONFIG_BLK_WBT=y
+CONFIG_BLK_CGROUP_IOLATENCY=y
+CONFIG_BLK_CGROUP_FC_APPID=y
+CONFIG_BLK_CGROUP_IOCOST=y
+CONFIG_BLK_CGROUP_IOPRIO=y
+CONFIG_BLK_INLINE_ENCRYPTION=y
+CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_UNIXWARE_DISKLABEL=y
+CONFIG_CMDLINE_PARTITION=y
+CONFIG_IOSCHED_BFQ=y
+CONFIG_BFQ_GROUP_IOSCHED=y
+CONFIG_BINFMT_MISC=m
+CONFIG_ZSWAP=y
+CONFIG_ZSWAP_COMPRESSOR_DEFAULT_ZSTD=y
+CONFIG_ZSMALLOC=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_MEMORY_HOTPLUG=y
+# CONFIG_MHP_DEFAULT_ONLINE_TYPE_OFFLINE is not set
+CONFIG_MHP_DEFAULT_ONLINE_TYPE_ONLINE_AUTO=y
+# CONFIG_MHP_DEFAULT_ONLINE_TYPE_ONLINE_KERNEL is not set
+# CONFIG_MHP_DEFAULT_ONLINE_TYPE_ONLINE_MOVABLE is not set
+CONFIG_MEMORY_HOTREMOVE=y
+CONFIG_KSM=y
+CONFIG_CMA=y
+CONFIG_CMA_SYSFS=y
+CONFIG_USERFAULTFD=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_TLS=m
+CONFIG_TLS_DEVICE=y
+CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=y
+CONFIG_XDP_SOCKETS=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE_DEMUX=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_ESP_OFFLOAD=m
+CONFIG_INET_ESPINTCP=y
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_UDP_DIAG=y
+CONFIG_TCP_CONG_ADVANCED=y
+CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_VEGAS=m
+CONFIG_TCP_CONG_NV=m
+CONFIG_TCP_CONG_SCALABLE=m
+CONFIG_TCP_CONG_VENO=m
+CONFIG_TCP_CONG_DCTCP=m
+CONFIG_TCP_CONG_CDG=m
+CONFIG_TCP_CONG_BBR=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_ESP_OFFLOAD=m
+CONFIG_INET6_ESPINTCP=y
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_MROUTE=y
+CONFIG_MPTCP=y
+CONFIG_NETWORK_PHY_TIMESTAMPING=y
+CONFIG_NETFILTER=y
+CONFIG_BRIDGE_NETFILTER=m
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_CONNTRACK_AMANDA=m
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
+CONFIG_NF_CONNTRACK_SNMP=m
+CONFIG_NF_CONNTRACK_PPTP=m
+CONFIG_NF_CONNTRACK_TFTP=m
+CONFIG_NF_CT_NETLINK=m
+CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=y
+CONFIG_NFT_CT=m
+CONFIG_NFT_CONNLIMIT=m
+CONFIG_NFT_LOG=m
+CONFIG_NFT_LIMIT=m
+CONFIG_NFT_MASQ=m
+CONFIG_NFT_REDIR=m
+CONFIG_NFT_NAT=m
+CONFIG_NFT_TUNNEL=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_QUOTA=m
+CONFIG_NFT_REJECT=m
+CONFIG_NFT_COMPAT=m
+CONFIG_NFT_HASH=m
+CONFIG_NFT_FIB_INET=m
+CONFIG_NFT_SOCKET=m
+CONFIG_NFT_OSF=m
+CONFIG_NFT_TPROXY=m
+CONFIG_NETFILTER_XT_SET=m
+CONFIG_NETFILTER_XT_TARGET_AUDIT=m
+CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_CT=m
+CONFIG_NETFILTER_XT_TARGET_DSCP=m
+CONFIG_NETFILTER_XT_TARGET_HMARK=m
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m
+CONFIG_NETFILTER_XT_TARGET_LED=m
+CONFIG_NETFILTER_XT_TARGET_LOG=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_TRACE=m
+CONFIG_NETFILTER_XT_TARGET_SECMARK=m
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
+CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m
+CONFIG_NETFILTER_XT_MATCH_BPF=m
+CONFIG_NETFILTER_XT_MATCH_CGROUP=m
+CONFIG_NETFILTER_XT_MATCH_CLUSTER=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_CPU=m
+CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m
+CONFIG_NETFILTER_XT_MATCH_DSCP=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
+CONFIG_NETFILTER_XT_MATCH_IPVS=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+CONFIG_NETFILTER_XT_MATCH_NFACCT=m
+CONFIG_NETFILTER_XT_MATCH_OSF=m
+CONFIG_NETFILTER_XT_MATCH_OWNER=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_NETFILTER_XT_MATCH_RATEEST=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SOCKET=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_TIME=m
+CONFIG_NETFILTER_XT_MATCH_U32=m
+CONFIG_IP_SET=m
+CONFIG_IP_VS=m
+CONFIG_IP_VS_IPV6=y
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_AH=y
+CONFIG_IP_VS_PROTO_SCTP=y
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_NFCT=y
+CONFIG_NF_TABLES_IPV4=y
+CONFIG_NFT_DUP_IPV4=m
+CONFIG_NFT_FIB_IPV4=m
+CONFIG_NF_TABLES_ARP=y
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_RPFILTER=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_SYNPROXY=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_SECURITY=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+CONFIG_NF_TABLES_IPV6=y
+CONFIG_NFT_FIB_IPV6=m
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_MH=m
+CONFIG_IP6_NF_MATCH_RPFILTER=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_SRH=m
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_TARGET_SYNPROXY=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_RAW=m
+CONFIG_IP6_NF_SECURITY=m
+CONFIG_IP6_NF_NAT=m
+CONFIG_IP6_NF_TARGET_MASQUERADE=m
+CONFIG_IP6_NF_TARGET_NPT=m
+CONFIG_NF_TABLES_BRIDGE=m
+CONFIG_NF_CONNTRACK_BRIDGE=m
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_IP6=m
+CONFIG_IP_SCTP=m
+CONFIG_RDS=y
+CONFIG_L2TP=m
+CONFIG_L2TP_V3=y
+CONFIG_L2TP_IP=m
+CONFIG_L2TP_ETH=m
+CONFIG_BRIDGE=m
+CONFIG_VLAN_8021Q=m
+CONFIG_VLAN_8021Q_GVRP=y
+CONFIG_VLAN_8021Q_MVRP=y
+CONFIG_LLC2=m
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_MULTIQ=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFB=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_CBS=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_NETEM=m
+CONFIG_NET_SCH_MQPRIO=m
+CONFIG_NET_SCH_SKBPRIO=m
+CONFIG_NET_SCH_QFQ=m
+CONFIG_NET_SCH_CODEL=m
+CONFIG_NET_SCH_FQ_CODEL=m
+CONFIG_NET_SCH_CAKE=m
+CONFIG_NET_SCH_FQ=m
+CONFIG_NET_SCH_PIE=m
+CONFIG_NET_SCH_FQ_PIE=m
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_SCH_DEFAULT=y
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_NET_CLS_FLOW=m
+CONFIG_NET_CLS_CGROUP=m
+CONFIG_NET_CLS_BPF=m
+CONFIG_NET_CLS_FLOWER=m
+CONFIG_NET_CLS_MATCHALL=m
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=m
+CONFIG_NET_ACT_GACT=m
+CONFIG_NET_ACT_MIRRED=m
+CONFIG_NET_ACT_NAT=m
+CONFIG_NET_ACT_BPF=m
+CONFIG_OPENVSWITCH=m
+CONFIG_VSOCKETS=m
+CONFIG_VIRTIO_VSOCKETS=m
+CONFIG_NETLINK_DIAG=y
+CONFIG_CGROUP_NET_PRIO=y
+CONFIG_BPF_STREAM_PARSER=y
+CONFIG_BT=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=m
+CONFIG_BT_HS=y
+CONFIG_BT_HCIBTUSB=m
+CONFIG_BT_HCIBTUSB_AUTOSUSPEND=y
+CONFIG_BT_HCIBTUSB_MTK=y
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_BCSP=y
+CONFIG_BT_HCIUART_ATH3K=y
+CONFIG_BT_HCIUART_INTEL=y
+CONFIG_BT_HCIUART_AG6XX=y
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBPA10X=m
+CONFIG_BT_HCIBFUSB=m
+CONFIG_BT_HCIDTL1=m
+CONFIG_BT_HCIBT3C=m
+CONFIG_BT_HCIBLUECARD=m
+CONFIG_BT_HCIVHCI=m
+CONFIG_BT_MRVL=m
+CONFIG_BT_ATH3K=m
+CONFIG_BT_VIRTIO=m
+CONFIG_CFG80211=m
+CONFIG_CFG80211_WEXT=y
+CONFIG_MAC80211=m
+CONFIG_RFKILL=m
+CONFIG_RFKILL_INPUT=y
+CONFIG_NET_9P=y
+CONFIG_NET_9P_VIRTIO=y
+CONFIG_CEPH_LIB=m
+CONFIG_PCIEPORTBUS=y
+CONFIG_HOTPLUG_PCI_PCIE=y
+CONFIG_PCIEAER=y
+# CONFIG_PCIEASPM is not set
+CONFIG_PCI_IOV=y
+CONFIG_HOTPLUG_PCI=y
+CONFIG_HOTPLUG_PCI_SHPC=y
+CONFIG_PCI_HOST_GENERIC=y
+CONFIG_PCCARD=m
+CONFIG_YENTA=m
+CONFIG_RAPIDIO=y
+CONFIG_RAPIDIO_TSI721=y
+CONFIG_RAPIDIO_ENABLE_RX_TX_PORTS=y
+CONFIG_RAPIDIO_ENUM_BASIC=m
+CONFIG_RAPIDIO_CHMAN=m
+CONFIG_RAPIDIO_MPORT_CDEV=m
+CONFIG_UEVENT_HELPER=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_FW_LOADER_COMPRESS=y
+CONFIG_FW_LOADER_COMPRESS_ZSTD=y
+CONFIG_EFI_ZBOOT=y
+CONFIG_EFI_BOOTLOADER_CONTROL=m
+CONFIG_EFI_CAPSULE_LOADER=m
+CONFIG_EFI_TEST=m
+CONFIG_MTD=m
+CONFIG_MTD_BLOCK=m
+CONFIG_MTD_CFI=m
+CONFIG_MTD_JEDECPROBE=m
+CONFIG_MTD_CFI_INTELEXT=m
+CONFIG_MTD_CFI_AMDSTD=m
+CONFIG_MTD_CFI_STAA=m
+CONFIG_MTD_RAM=m
+CONFIG_MTD_ROM=m
+CONFIG_MTD_RAW_NAND=m
+CONFIG_MTD_NAND_PLATFORM=m
+CONFIG_MTD_NAND_LOONGSON=m
+CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC=y
+CONFIG_MTD_NAND_ECC_SW_BCH=y
+CONFIG_MTD_UBI=m
+CONFIG_MTD_UBI_BLOCK=y
+CONFIG_PARPORT=y
+CONFIG_PARPORT_PC=y
+CONFIG_PARPORT_SERIAL=y
+CONFIG_PARPORT_PC_FIFO=y
+CONFIG_ZRAM=m
+CONFIG_ZRAM_BACKEND_LZ4=y
+CONFIG_ZRAM_BACKEND_LZ4HC=y
+CONFIG_ZRAM_BACKEND_ZSTD=y
+CONFIG_ZRAM_BACKEND_DEFLATE=y
+CONFIG_ZRAM_BACKEND_842=y
+CONFIG_ZRAM_BACKEND_LZO=y
+CONFIG_ZRAM_DEF_COMP_ZSTD=y
+CONFIG_ZRAM_WRITEBACK=y
+CONFIG_ZRAM_MEMORY_TRACKING=y
+CONFIG_ZRAM_MULTI_COMP=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_DRBD=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_VIRTIO_BLK=y
+CONFIG_BLK_DEV_RBD=m
+CONFIG_BLK_DEV_NVME=y
+CONFIG_NVME_MULTIPATH=y
+CONFIG_NVME_RDMA=m
+CONFIG_NVME_FC=m
+CONFIG_NVME_TCP=m
+CONFIG_NVME_TARGET=m
+CONFIG_NVME_TARGET_PASSTHRU=y
+CONFIG_NVME_TARGET_LOOP=m
+CONFIG_NVME_TARGET_RDMA=m
+CONFIG_NVME_TARGET_FC=m
+CONFIG_NVME_TARGET_TCP=m
+CONFIG_EEPROM_AT24=m
+CONFIG_PVPANIC=y
+CONFIG_PVPANIC_MMIO=m
+CONFIG_PVPANIC_PCI=m
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=m
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SPI_ATTRS=m
+CONFIG_SCSI_FC_ATTRS=m
+CONFIG_SCSI_SAS_ATA=y
+CONFIG_ISCSI_TCP=m
+CONFIG_SCSI_MVSAS=y
+# CONFIG_SCSI_MVSAS_DEBUG is not set
+CONFIG_SCSI_MVSAS_TASKLET=y
+CONFIG_SCSI_MVUMI=y
+CONFIG_MEGARAID_NEWGEN=y
+CONFIG_MEGARAID_MM=y
+CONFIG_MEGARAID_MAILBOX=y
+CONFIG_MEGARAID_LEGACY=y
+CONFIG_MEGARAID_SAS=y
+CONFIG_SCSI_MPT2SAS=y
+CONFIG_LIBFC=m
+CONFIG_LIBFCOE=m
+CONFIG_FCOE=m
+CONFIG_SCSI_QLOGIC_1280=m
+CONFIG_SCSI_QLA_FC=m
+CONFIG_TCM_QLA2XXX=m
+CONFIG_SCSI_QLA_ISCSI=m
+CONFIG_SCSI_LPFC=m
+CONFIG_SCSI_VIRTIO=m
+CONFIG_ATA=y
+CONFIG_SATA_AHCI=y
+CONFIG_SATA_AHCI_PLATFORM=y
+CONFIG_AHCI_DWC=y
+CONFIG_PATA_ATIIXP=y
+CONFIG_PATA_PCMCIA=m
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LLBITMAP=y
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID10=m
+CONFIG_MD_RAID456=m
+CONFIG_BCACHE=m
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_THIN_PROVISIONING=m
+CONFIG_DM_CACHE=m
+CONFIG_DM_WRITECACHE=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_RAID=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+CONFIG_DM_MULTIPATH_QL=m
+CONFIG_DM_MULTIPATH_ST=m
+CONFIG_DM_MULTIPATH_HST=m
+CONFIG_DM_MULTIPATH_IOA=m
+CONFIG_DM_INIT=y
+CONFIG_DM_UEVENT=y
+CONFIG_DM_VERITY=m
+CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG=y
+CONFIG_DM_VERITY_FEC=y
+CONFIG_DM_INTEGRITY=m
+CONFIG_DM_ZONED=m
+CONFIG_DM_VDO=m
+CONFIG_TARGET_CORE=m
+CONFIG_TCM_IBLOCK=m
+CONFIG_TCM_FILEIO=m
+CONFIG_TCM_PSCSI=m
+CONFIG_TCM_USER2=m
+CONFIG_LOOPBACK_TARGET=m
+CONFIG_ISCSI_TARGET=m
+CONFIG_NETDEVICES=y
+CONFIG_BONDING=m
+CONFIG_DUMMY=y
+CONFIG_WIREGUARD=m
+CONFIG_IFB=m
+CONFIG_NET_TEAM=m
+CONFIG_NET_TEAM_MODE_BROADCAST=m
+CONFIG_NET_TEAM_MODE_ROUNDROBIN=m
+CONFIG_NET_TEAM_MODE_RANDOM=m
+CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=m
+CONFIG_NET_TEAM_MODE_LOADBALANCE=m
+CONFIG_MACVLAN=m
+CONFIG_MACVTAP=m
+CONFIG_IPVLAN=m
+CONFIG_VXLAN=y
+CONFIG_RIONET=m
+CONFIG_TUN=m
+CONFIG_VETH=m
+CONFIG_VIRTIO_NET=m
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_ADAPTEC is not set
+# CONFIG_NET_VENDOR_AGERE is not set
+# CONFIG_NET_VENDOR_ALACRITECH is not set
+# CONFIG_NET_VENDOR_ALTEON is not set
+# CONFIG_NET_VENDOR_AMAZON is not set
+# CONFIG_NET_VENDOR_AMD is not set
+# CONFIG_NET_VENDOR_AQUANTIA is not set
+# CONFIG_NET_VENDOR_ARC is not set
+# CONFIG_NET_VENDOR_ATHEROS is not set
+CONFIG_BNX2=y
+# CONFIG_NET_VENDOR_CAVIUM is not set
+CONFIG_CHELSIO_T1=m
+CONFIG_CHELSIO_T1_1G=y
+CONFIG_CHELSIO_T3=m
+CONFIG_CHELSIO_T4=m
+# CONFIG_NET_VENDOR_CISCO is not set
+# CONFIG_NET_VENDOR_DEC is not set
+# CONFIG_NET_VENDOR_DLINK is not set
+# CONFIG_NET_VENDOR_EMULEX is not set
+# CONFIG_NET_VENDOR_EZCHIP is not set
+# CONFIG_NET_VENDOR_I825XX is not set
+CONFIG_E1000=y
+CONFIG_E1000E=y
+CONFIG_IGB=y
+CONFIG_IXGBE=y
+CONFIG_I40E=y
+CONFIG_ICE=y
+CONFIG_FM10K=y
+CONFIG_IGC=y
+CONFIG_IDPF=y
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MELLANOX is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MYRI is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_NETRONOME is not set
+# CONFIG_NET_VENDOR_NVIDIA is not set
+# CONFIG_NET_VENDOR_OKI is not set
+# CONFIG_NET_VENDOR_QLOGIC is not set
+# CONFIG_NET_VENDOR_BROCADE is not set
+# CONFIG_NET_VENDOR_QUALCOMM is not set
+# CONFIG_NET_VENDOR_RDC is not set
+CONFIG_8139CP=m
+CONFIG_8139TOO=m
+CONFIG_R8169=y
+# CONFIG_NET_VENDOR_RENESAS is not set
+# CONFIG_NET_VENDOR_ROCKER is not set
+# CONFIG_NET_VENDOR_SAMSUNG is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SILAN is not set
+# CONFIG_NET_VENDOR_SIS is not set
+# CONFIG_NET_VENDOR_SOLARFLARE is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+CONFIG_STMMAC_ETH=y
+# CONFIG_NET_VENDOR_SUN is not set
+# CONFIG_NET_VENDOR_TEHUTI is not set
+# CONFIG_NET_VENDOR_TI is not set
+# CONFIG_NET_VENDOR_VIA is not set
+CONFIG_NGBE=y
+CONFIG_TXGBE=y
+# CONFIG_NET_VENDOR_WIZNET is not set
+# CONFIG_NET_VENDOR_XILINX is not set
+CONFIG_MOTORCOMM_PHY=y
+CONFIG_PPP=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_MPPE=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOE=m
+CONFIG_PPTP=m
+CONFIG_PPPOL2TP=m
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_RTL8152=m
+CONFIG_USB_USBNET=m
+# CONFIG_USB_NET_AX8817X is not set
+# CONFIG_USB_NET_AX88179_178A is not set
+CONFIG_USB_NET_CDC_EEM=m
+CONFIG_USB_NET_HUAWEI_CDC_NCM=m
+CONFIG_USB_NET_CDC_MBIM=m
+# CONFIG_USB_NET_NET1080 is not set
+CONFIG_USB_NET_RNDIS_HOST=m
+# CONFIG_USB_BELKIN is not set
+# CONFIG_USB_ARMLINUX is not set
+# CONFIG_USB_NET_ZAURUS is not set
+CONFIG_ATH9K=m
+CONFIG_ATH9K_HTC=m
+CONFIG_IWLWIFI=m
+CONFIG_IWLDVM=m
+CONFIG_IWLMVM=m
+CONFIG_MT7601U=m
+CONFIG_RT2X00=m
+CONFIG_RT2800USB=m
+CONFIG_RTL8180=m
+CONFIG_RTL8187=m
+CONFIG_RTL8192CE=m
+CONFIG_RTL8192SE=m
+CONFIG_RTL8192DE=m
+CONFIG_RTL8723AE=m
+CONFIG_RTL8723BE=m
+CONFIG_RTL8188EE=m
+CONFIG_RTL8192EE=m
+CONFIG_RTL8821AE=m
+CONFIG_RTL8192CU=m
+CONFIG_RTL8192DU=m
+# CONFIG_RTLWIFI_DEBUG is not set
+CONFIG_RTL8XXXU=m
+CONFIG_RTW88=m
+CONFIG_RTW88_8822BE=m
+CONFIG_RTW88_8822BU=m
+CONFIG_RTW88_8822CE=m
+CONFIG_RTW88_8822CU=m
+CONFIG_RTW88_8723DE=m
+CONFIG_RTW88_8723DU=m
+CONFIG_RTW88_8821CE=m
+CONFIG_RTW88_8821CU=m
+CONFIG_RTW88_8821AU=m
+CONFIG_RTW88_8812AU=m
+CONFIG_RTW88_8814AE=m
+CONFIG_RTW88_8814AU=m
+CONFIG_RTW89=m
+CONFIG_RTW89_8851BE=m
+CONFIG_RTW89_8852AE=m
+CONFIG_RTW89_8852BE=m
+CONFIG_RTW89_8852BTE=m
+CONFIG_RTW89_8852CE=m
+CONFIG_RTW89_8922AE=m
+CONFIG_ZD1211RW=m
+CONFIG_USB4_NET=m
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_KEYBOARD_GPIO=m
+CONFIG_KEYBOARD_GPIO_POLLED=m
+CONFIG_KEYBOARD_MATRIX=m
+CONFIG_KEYBOARD_XTKBD=m
+CONFIG_MOUSE_PS2_ELANTECH=y
+CONFIG_MOUSE_PS2_SENTELIC=y
+CONFIG_MOUSE_SERIAL=m
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=m
+CONFIG_SERIO_SERPORT=m
+CONFIG_SERIO_RAW=m
+CONFIG_LEGACY_PTY_COUNT=16
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=16
+CONFIG_SERIAL_8250_RUNTIME_UARTS=16
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+CONFIG_SERIAL_8250_LOONGSON=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SERIAL_NONSTANDARD=y
+CONFIG_PRINTER=m
+CONFIG_VIRTIO_CONSOLE=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_VIRTIO=m
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_PIIX4=y
+CONFIG_I2C_DESIGNWARE_CORE=y
+CONFIG_I2C_DESIGNWARE_SLAVE=y
+CONFIG_I2C_DESIGNWARE_PCI=y
+CONFIG_I2C_GPIO=y
+CONFIG_SPI=y
+CONFIG_SPI_LOONGSON_PCI=m
+CONFIG_SPI_LOONGSON_PLATFORM=m
+CONFIG_PINCTRL=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_LOONGSON1=y
+CONFIG_GPIO_PCA953X=m
+CONFIG_GPIO_PCA953X_IRQ=y
+CONFIG_GPIO_PCA9570=m
+CONFIG_GPIO_PCF857X=m
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_RESTART=y
+CONFIG_POWER_RESET_SYSCON=y
+CONFIG_POWER_RESET_SYSCON_POWEROFF=y
+CONFIG_SYSCON_REBOOT_MODE=y
+CONFIG_SENSORS_LM75=m
+CONFIG_SENSORS_LM93=m
+CONFIG_SENSORS_W83795=m
+CONFIG_SENSORS_W83627HF=m
+CONFIG_WATCHDOG=y
+CONFIG_LOONGSON1_WDT=m
+CONFIG_RC_CORE=m
+CONFIG_LIRC=y
+CONFIG_RC_DECODERS=y
+CONFIG_IR_IMON_DECODER=m
+CONFIG_IR_JVC_DECODER=m
+CONFIG_IR_MCE_KBD_DECODER=m
+CONFIG_IR_NEC_DECODER=m
+CONFIG_IR_RC5_DECODER=m
+CONFIG_IR_RC6_DECODER=m
+CONFIG_IR_SANYO_DECODER=m
+CONFIG_IR_SHARP_DECODER=m
+CONFIG_IR_SONY_DECODER=m
+CONFIG_IR_XMP_DECODER=m
+CONFIG_MEDIA_SUPPORT=m
+CONFIG_MEDIA_USB_SUPPORT=y
+CONFIG_USB_VIDEO_CLASS=m
+CONFIG_MEDIA_PCI_SUPPORT=y
+CONFIG_VIDEO_BT848=m
+CONFIG_DVB_BT8XX=m
+CONFIG_DRM=y
+CONFIG_DRM_LOAD_EDID_FIRMWARE=y
+CONFIG_DRM_EFIDRM=y
+CONFIG_DRM_SIMPLEDRM=y
+CONFIG_DRM_RADEON=m
+CONFIG_DRM_RADEON_USERPTR=y
+CONFIG_DRM_QXL=m
+CONFIG_DRM_VIRTIO_GPU=m
+CONFIG_DRM_LOONGSON=y
+CONFIG_FB=y
+CONFIG_FB_RADEON=y
+CONFIG_FIRMWARE_EDID=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_LCD_PLATFORM=m
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+CONFIG_LOGO=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_BT87X=m
+CONFIG_SND_BT87X_OVERCLOCK=y
+CONFIG_SND_HDA_INTEL=y
+CONFIG_SND_HDA_HWDEP=y
+CONFIG_SND_HDA_INPUT_BEEP=y
+CONFIG_SND_HDA_PATCH_LOADER=y
+CONFIG_SND_HDA_CODEC_REALTEK=y
+CONFIG_SND_HDA_CODEC_REALTEK_LIB=y
+CONFIG_SND_HDA_CODEC_ALC260=y
+CONFIG_SND_HDA_CODEC_ALC262=y
+CONFIG_SND_HDA_CODEC_ALC268=y
+CONFIG_SND_HDA_CODEC_ALC269=y
+CONFIG_SND_HDA_CODEC_ALC662=y
+CONFIG_SND_HDA_CODEC_ALC680=y
+CONFIG_SND_HDA_CODEC_ALC861=y
+CONFIG_SND_HDA_CODEC_ALC861VD=y
+CONFIG_SND_HDA_CODEC_ALC880=y
+CONFIG_SND_HDA_CODEC_ALC882=y
+CONFIG_SND_HDA_CODEC_SIGMATEL=y
+CONFIG_SND_HDA_CODEC_HDMI=y
+CONFIG_SND_HDA_CODEC_HDMI_GENERIC=y
+CONFIG_SND_HDA_CODEC_HDMI_INTEL=y
+CONFIG_SND_HDA_CODEC_HDMI_ATI=y
+CONFIG_SND_HDA_CODEC_HDMI_NVIDIA=y
+CONFIG_SND_HDA_CODEC_CONEXANT=y
+CONFIG_SND_USB_AUDIO=m
+CONFIG_SND_USB_AUDIO_MIDI_V2=y
+CONFIG_SND_SOC=m
+CONFIG_SND_SOC_LOONGSON_CARD=m
+CONFIG_SND_LOONGSON1_AC97=m
+CONFIG_SND_SOC_ES7134=m
+CONFIG_SND_SOC_ES7241=m
+CONFIG_SND_SOC_ES8311=m
+CONFIG_SND_SOC_ES8316=m
+CONFIG_SND_SOC_ES8323=m
+CONFIG_SND_SOC_ES8326=m
+CONFIG_SND_SOC_ES8328_I2C=m
+CONFIG_SND_SOC_ES8328_SPI=m
+CONFIG_SND_SOC_UDA1334=m
+CONFIG_SND_SOC_UDA1342=m
+CONFIG_SND_VIRTIO=m
+CONFIG_HIDRAW=y
+CONFIG_UHID=m
+CONFIG_HID_A4TECH=m
+CONFIG_HID_CHERRY=m
+CONFIG_HID_ELAN=m
+CONFIG_HID_LOGITECH=m
+CONFIG_HID_LOGITECH_DJ=m
+CONFIG_LOGITECH_FF=y
+CONFIG_LOGIRUMBLEPAD2_FF=y
+CONFIG_LOGIG940_FF=y
+CONFIG_HID_MICROSOFT=m
+CONFIG_HID_MULTITOUCH=m
+CONFIG_HID_SUNPLUS=m
+CONFIG_HID_WACOM=m
+CONFIG_USB_HIDDEV=y
+CONFIG_I2C_HID_ACPI=m
+CONFIG_I2C_HID_OF=m
+CONFIG_I2C_HID_OF_ELAN=m
+CONFIG_USB=y
+CONFIG_USB_OTG=y
+CONFIG_USB_MON=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_USB_UHCI_HCD=m
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+CONFIG_USB_STORAGE=m
+CONFIG_USB_STORAGE_REALTEK=m
+CONFIG_USB_UAS=m
+CONFIG_USB_DWC2=y
+CONFIG_USB_DWC2_HOST=y
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_CH341=m
+CONFIG_USB_SERIAL_CP210X=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_OPTION=m
+CONFIG_USB_GADGET=y
+CONFIG_TYPEC=m
+CONFIG_TYPEC_TCPM=m
+CONFIG_TYPEC_TCPCI=m
+CONFIG_TYPEC_UCSI=m
+CONFIG_UCSI_ACPI=m
+CONFIG_MMC=y
+CONFIG_INFINIBAND=m
+CONFIG_EDAC=y
+# CONFIG_EDAC_LEGACY_SYSFS is not set
+CONFIG_EDAC_LOONGSON=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_EFI=y
+CONFIG_RTC_DRV_LOONGSON=y
+CONFIG_DMADEVICES=y
+CONFIG_LOONGSON1_APB_DMA=y
+CONFIG_UDMABUF=y
+CONFIG_DMABUF_HEAPS=y
+CONFIG_DMABUF_HEAPS_SYSTEM=y
+CONFIG_DMABUF_HEAPS_CMA=y
+CONFIG_UIO=m
+CONFIG_UIO_PDRV_GENIRQ=m
+CONFIG_UIO_DMEM_GENIRQ=m
+CONFIG_UIO_PCI_GENERIC=m
+CONFIG_VFIO=m
+CONFIG_VFIO_PCI=m
+CONFIG_VIRTIO_PCI=y
+CONFIG_VIRTIO_BALLOON=m
+CONFIG_VIRTIO_INPUT=m
+CONFIG_VIRTIO_MMIO=m
+CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
+CONFIG_VHOST_NET=m
+CONFIG_VHOST_SCSI=m
+CONFIG_VHOST_VSOCK=m
+CONFIG_COMEDI=m
+CONFIG_COMEDI_PCI_DRIVERS=m
+CONFIG_COMEDI_8255_PCI=m
+CONFIG_COMEDI_ADL_PCI6208=m
+CONFIG_COMEDI_ADL_PCI7X3X=m
+CONFIG_COMEDI_ADL_PCI8164=m
+CONFIG_COMEDI_ADL_PCI9111=m
+CONFIG_COMEDI_ADL_PCI9118=m
+CONFIG_COMEDI_ADV_PCI1710=m
+CONFIG_COMEDI_ADV_PCI1720=m
+CONFIG_COMEDI_ADV_PCI1723=m
+CONFIG_COMEDI_ADV_PCI1724=m
+CONFIG_COMEDI_ADV_PCI1760=m
+CONFIG_COMEDI_ADV_PCI_DIO=m
+CONFIG_COMEDI_NI_LABPC_PCI=m
+CONFIG_COMEDI_NI_PCIDIO=m
+CONFIG_COMEDI_NI_PCIMIO=m
+CONFIG_STAGING=y
+CONFIG_CLKSRC_LOONGSON1_PWM=y
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_PM_DEVFREQ=y
+CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y
+CONFIG_DEVFREQ_GOV_PERFORMANCE=y
+CONFIG_DEVFREQ_GOV_POWERSAVE=y
+CONFIG_DEVFREQ_GOV_USERSPACE=y
+CONFIG_NTB=m
+CONFIG_NTB_MSI=y
+CONFIG_NTB_IDT=m
+CONFIG_NTB_EPF=m
+CONFIG_NTB_SWITCHTEC=m
+CONFIG_NTB_PERF=m
+CONFIG_NTB_TRANSPORT=m
+CONFIG_PWM=y
+CONFIG_GENERIC_PHY=y
+CONFIG_USB4=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_JFS_FS=m
+CONFIG_JFS_POSIX_ACL=y
+CONFIG_JFS_SECURITY=y
+CONFIG_XFS_FS=y
+CONFIG_XFS_SUPPORT_V4=y
+CONFIG_XFS_SUPPORT_ASCII_CI=y
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_GFS2_FS=m
+CONFIG_GFS2_FS_LOCKING_DLM=y
+CONFIG_OCFS2_FS=m
+CONFIG_BTRFS_FS=y
+CONFIG_BTRFS_FS_POSIX_ACL=y
+CONFIG_F2FS_FS=m
+CONFIG_F2FS_FS_SECURITY=y
+CONFIG_F2FS_CHECK_FS=y
+CONFIG_F2FS_FS_COMPRESSION=y
+CONFIG_FS_ENCRYPTION=y
+CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y
+CONFIG_FS_VERITY=y
+CONFIG_FANOTIFY=y
+CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y
+CONFIG_QUOTA=y
+# CONFIG_PRINT_QUOTA_WARNING is not set
+CONFIG_QFMT_V1=m
+CONFIG_QFMT_V2=m
+CONFIG_AUTOFS_FS=y
+CONFIG_FUSE_FS=m
+CONFIG_CUSE=m
+CONFIG_VIRTIO_FS=m
+CONFIG_OVERLAY_FS=y
+CONFIG_OVERLAY_FS_INDEX=y
+CONFIG_OVERLAY_FS_XINO_AUTO=y
+CONFIG_OVERLAY_FS_METACOPY=y
+CONFIG_FSCACHE=y
+CONFIG_CACHEFILES=m
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=y
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=936
+CONFIG_FAT_DEFAULT_IOCHARSET="gb2312"
+CONFIG_EXFAT_FS=m
+CONFIG_NTFS3_FS=m
+CONFIG_NTFS3_LZX_XPRESS=y
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_CONFIGFS_FS=y
+CONFIG_ORANGEFS_FS=m
+CONFIG_ECRYPT_FS=m
+CONFIG_ECRYPT_FS_MESSAGING=y
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+CONFIG_UBIFS_FS=m
+CONFIG_UBIFS_FS_ADVANCED_COMPR=y
+CONFIG_CRAMFS=m
+CONFIG_SQUASHFS=y
+CONFIG_SQUASHFS_FILE_DIRECT=y
+CONFIG_SQUASHFS_CHOICE_DECOMP_BY_MOUNT=y
+CONFIG_SQUASHFS_XATTR=y
+CONFIG_SQUASHFS_LZ4=y
+CONFIG_SQUASHFS_LZO=y
+CONFIG_SQUASHFS_XZ=y
+CONFIG_SQUASHFS_ZSTD=y
+CONFIG_MINIX_FS=m
+CONFIG_ROMFS_FS=m
+CONFIG_PSTORE=m
+CONFIG_PSTORE_COMPRESS=y
+CONFIG_UFS_FS=m
+CONFIG_EROFS_FS=m
+CONFIG_EROFS_FS_ZIP_LZMA=y
+CONFIG_EROFS_FS_ZIP_DEFLATE=y
+CONFIG_EROFS_FS_ZIP_ZSTD=y
+CONFIG_EROFS_FS_ONDEMAND=y
+CONFIG_EROFS_FS_PCPU_KTHREAD=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_V4_1=y
+CONFIG_NFS_V4_2=y
+CONFIG_ROOT_NFS=y
+CONFIG_NFSD=y
+CONFIG_NFSD_V3_ACL=y
+CONFIG_NFSD_V4=y
+CONFIG_NFSD_BLOCKLAYOUT=y
+CONFIG_CEPH_FS=m
+CONFIG_CEPH_FSCACHE=y
+CONFIG_CEPH_FS_POSIX_ACL=y
+CONFIG_CEPH_FS_SECURITY_LABEL=y
+CONFIG_CIFS=m
+# CONFIG_CIFS_DEBUG is not set
+CONFIG_9P_FS=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_936=y
+CONFIG_NLS_CODEPAGE_950=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_UTF8=y
+CONFIG_DLM=m
+CONFIG_KEY_DH_OPERATIONS=y
+CONFIG_SECURITY=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_APPARMOR=y
+CONFIG_SECURITY_YAMA=y
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_CRYPTO_USER=m
+CONFIG_CRYPTO_SELFTESTS=y
+CONFIG_CRYPTO_PCRYPT=m
+CONFIG_CRYPTO_CRYPTD=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_SEED=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_SM4_GENERIC=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_CHACHA20POLY1305=m
+CONFIG_CRYPTO_SM3_GENERIC=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_LZO=m
+CONFIG_CRYPTO_842=m
+CONFIG_CRYPTO_LZ4=m
+CONFIG_CRYPTO_LZ4HC=m
+CONFIG_CRYPTO_USER_API_HASH=m
+CONFIG_CRYPTO_USER_API_SKCIPHER=m
+CONFIG_CRYPTO_USER_API_RNG=m
+CONFIG_CRYPTO_USER_API_AEAD=m
+CONFIG_CRYPTO_DEV_VIRTIO=m
+CONFIG_CRYPTO_DEV_LOONGSON_RNG=m
+CONFIG_DMA_CMA=y
+CONFIG_CMA_SIZE_MBYTES=0
+CONFIG_PRINTK_TIME=y
+CONFIG_STRIP_ASM_SYMS=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_SCHEDSTATS=y
+# CONFIG_DEBUG_PREEMPT is not set
+# CONFIG_FTRACE is not set
diff --git a/arch/loongarch/configs/loongson3_defconfig b/arch/loongarch/configs/loongson64_defconfig
index 50e1304e7a6f..a14db1a95e7e 100644
--- a/arch/loongarch/configs/loongson3_defconfig
+++ b/arch/loongarch/configs/loongson64_defconfig
@@ -435,7 +435,6 @@ CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
CONFIG_FW_LOADER_COMPRESS=y
CONFIG_FW_LOADER_COMPRESS_ZSTD=y
-CONFIG_SYSFB_SIMPLEFB=y
CONFIG_EFI_ZBOOT=y
CONFIG_EFI_BOOTLOADER_CONTROL=m
CONFIG_EFI_CAPSULE_LOADER=m
@@ -530,6 +529,7 @@ CONFIG_PATA_ATIIXP=y
CONFIG_PATA_PCMCIA=m
CONFIG_MD=y
CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LLBITMAP=y
CONFIG_MD_RAID0=m
CONFIG_MD_RAID1=m
CONFIG_MD_RAID10=m
@@ -738,6 +738,7 @@ CONFIG_SERIAL_8250_EXTENDED=y
CONFIG_SERIAL_8250_MANY_PORTS=y
CONFIG_SERIAL_8250_SHARE_IRQ=y
CONFIG_SERIAL_8250_RSA=y
+CONFIG_SERIAL_8250_LOONGSON=y
CONFIG_SERIAL_OF_PLATFORM=y
CONFIG_SERIAL_NONSTANDARD=y
CONFIG_PRINTER=m
@@ -801,6 +802,8 @@ CONFIG_VIDEO_BT848=m
CONFIG_DVB_BT8XX=m
CONFIG_DRM=y
CONFIG_DRM_LOAD_EDID_FIRMWARE=y
+CONFIG_DRM_EFIDRM=y
+CONFIG_DRM_SIMPLEDRM=y
CONFIG_DRM_RADEON=m
CONFIG_DRM_RADEON_USERPTR=y
CONFIG_DRM_AMDGPU=m
@@ -811,9 +814,7 @@ CONFIG_DRM_AST=y
CONFIG_DRM_QXL=m
CONFIG_DRM_VIRTIO_GPU=m
CONFIG_DRM_LOONGSON=y
-CONFIG_DRM_SIMPLEDRM=y
CONFIG_FB=y
-CONFIG_FB_EFI=y
CONFIG_FB_RADEON=y
CONFIG_FIRMWARE_EDID=y
CONFIG_LCD_CLASS_DEVICE=y
diff --git a/arch/loongarch/include/asm/Kbuild b/arch/loongarch/include/asm/Kbuild
index b04d2cef935f..9034b583a88a 100644
--- a/arch/loongarch/include/asm/Kbuild
+++ b/arch/loongarch/include/asm/Kbuild
@@ -1,4 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
+syscall-y += syscall_table_32.h
syscall-y += syscall_table_64.h
generated-y += orc_hash.h
diff --git a/arch/loongarch/include/asm/addrspace.h b/arch/loongarch/include/asm/addrspace.h
index e739dbc6329d..d6472cafb32c 100644
--- a/arch/loongarch/include/asm/addrspace.h
+++ b/arch/loongarch/include/asm/addrspace.h
@@ -38,11 +38,20 @@ extern unsigned long vm_map_base;
#endif
#ifndef WRITECOMBINE_BASE
+#ifdef CONFIG_32BIT
+#define WRITECOMBINE_BASE CSR_DMW0_BASE
+#else
#define WRITECOMBINE_BASE CSR_DMW2_BASE
#endif
+#endif
+#ifdef CONFIG_32BIT
+#define DMW_PABITS 29
+#define TO_PHYS_MASK ((_UL(1) << _UL(DMW_PABITS)) - 1)
+#else
#define DMW_PABITS 48
-#define TO_PHYS_MASK ((1ULL << DMW_PABITS) - 1)
+#define TO_PHYS_MASK ((_ULL(1) << _ULL(DMW_PABITS)) - 1)
+#endif
/*
* Memory above this physical address will be considered highmem.
@@ -112,7 +121,11 @@ extern unsigned long vm_map_base;
/*
* Returns the physical address of a KPRANGEx / XKPRANGE address
*/
+#ifdef CONFIG_32BIT
+#define PHYSADDR(a) ((_ACAST32_(a)) & TO_PHYS_MASK)
+#else
#define PHYSADDR(a) ((_ACAST64_(a)) & TO_PHYS_MASK)
+#endif
/*
* On LoongArch, I/O ports mappring is following:
diff --git a/arch/loongarch/include/asm/asm.h b/arch/loongarch/include/asm/asm.h
index f018d26fc995..719cab1a0ad8 100644
--- a/arch/loongarch/include/asm/asm.h
+++ b/arch/loongarch/include/asm/asm.h
@@ -72,11 +72,11 @@
#define INT_SUB sub.w
#define INT_L ld.w
#define INT_S st.w
-#define INT_SLL slli.w
+#define INT_SLLI slli.w
#define INT_SLLV sll.w
-#define INT_SRL srli.w
+#define INT_SRLI srli.w
#define INT_SRLV srl.w
-#define INT_SRA srai.w
+#define INT_SRAI srai.w
#define INT_SRAV sra.w
#endif
@@ -86,11 +86,11 @@
#define INT_SUB sub.d
#define INT_L ld.d
#define INT_S st.d
-#define INT_SLL slli.d
+#define INT_SLLI slli.d
#define INT_SLLV sll.d
-#define INT_SRL srli.d
+#define INT_SRLI srli.d
#define INT_SRLV srl.d
-#define INT_SRA srai.d
+#define INT_SRAI srai.d
#define INT_SRAV sra.d
#endif
@@ -100,15 +100,23 @@
#if (__SIZEOF_LONG__ == 4)
#define LONG_ADD add.w
#define LONG_ADDI addi.w
+#define LONG_ALSL alsl.w
+#define LONG_BSTRINS bstrins.w
+#define LONG_BSTRPICK bstrpick.w
#define LONG_SUB sub.w
#define LONG_L ld.w
+#define LONG_LI li.w
+#define LONG_LPTR ld.w
#define LONG_S st.w
-#define LONG_SLL slli.w
+#define LONG_SPTR st.w
+#define LONG_SLLI slli.w
#define LONG_SLLV sll.w
-#define LONG_SRL srli.w
+#define LONG_SRLI srli.w
#define LONG_SRLV srl.w
-#define LONG_SRA srai.w
+#define LONG_SRAI srai.w
#define LONG_SRAV sra.w
+#define LONG_ROTR rotr.w
+#define LONG_ROTRI rotri.w
#ifdef __ASSEMBLER__
#define LONG .word
@@ -121,15 +129,23 @@
#if (__SIZEOF_LONG__ == 8)
#define LONG_ADD add.d
#define LONG_ADDI addi.d
+#define LONG_ALSL alsl.d
+#define LONG_BSTRINS bstrins.d
+#define LONG_BSTRPICK bstrpick.d
#define LONG_SUB sub.d
#define LONG_L ld.d
+#define LONG_LI li.d
+#define LONG_LPTR ldptr.d
#define LONG_S st.d
-#define LONG_SLL slli.d
+#define LONG_SPTR stptr.d
+#define LONG_SLLI slli.d
#define LONG_SLLV sll.d
-#define LONG_SRL srli.d
+#define LONG_SRLI srli.d
#define LONG_SRLV srl.d
-#define LONG_SRA srai.d
+#define LONG_SRAI srai.d
#define LONG_SRAV sra.d
+#define LONG_ROTR rotr.d
+#define LONG_ROTRI rotri.d
#ifdef __ASSEMBLER__
#define LONG .dword
@@ -145,16 +161,23 @@
#if (__SIZEOF_POINTER__ == 4)
#define PTR_ADD add.w
#define PTR_ADDI addi.w
+#define PTR_ALSL alsl.w
+#define PTR_BSTRINS bstrins.w
+#define PTR_BSTRPICK bstrpick.w
#define PTR_SUB sub.w
#define PTR_L ld.w
-#define PTR_S st.w
#define PTR_LI li.w
-#define PTR_SLL slli.w
+#define PTR_LPTR ld.w
+#define PTR_S st.w
+#define PTR_SPTR st.w
+#define PTR_SLLI slli.w
#define PTR_SLLV sll.w
-#define PTR_SRL srli.w
+#define PTR_SRLI srli.w
#define PTR_SRLV srl.w
-#define PTR_SRA srai.w
+#define PTR_SRAI srai.w
#define PTR_SRAV sra.w
+#define PTR_ROTR rotr.w
+#define PTR_ROTRI rotri.w
#define PTR_SCALESHIFT 2
@@ -168,16 +191,23 @@
#if (__SIZEOF_POINTER__ == 8)
#define PTR_ADD add.d
#define PTR_ADDI addi.d
+#define PTR_ALSL alsl.d
+#define PTR_BSTRINS bstrins.d
+#define PTR_BSTRPICK bstrpick.d
#define PTR_SUB sub.d
#define PTR_L ld.d
-#define PTR_S st.d
#define PTR_LI li.d
-#define PTR_SLL slli.d
+#define PTR_LPTR ldptr.d
+#define PTR_S st.d
+#define PTR_SPTR stptr.d
+#define PTR_SLLI slli.d
#define PTR_SLLV sll.d
-#define PTR_SRL srli.d
+#define PTR_SRLI srli.d
#define PTR_SRLV srl.d
-#define PTR_SRA srai.d
+#define PTR_SRAI srai.d
#define PTR_SRAV sra.d
+#define PTR_ROTR rotr.d
+#define PTR_ROTRI rotri.d
#define PTR_SCALESHIFT 3
@@ -190,10 +220,17 @@
/* Annotate a function as being unsuitable for kprobes. */
#ifdef CONFIG_KPROBES
+#ifdef CONFIG_32BIT
+#define _ASM_NOKPROBE(name) \
+ .pushsection "_kprobe_blacklist", "aw"; \
+ .long name; \
+ .popsection
+#else
#define _ASM_NOKPROBE(name) \
.pushsection "_kprobe_blacklist", "aw"; \
.quad name; \
.popsection
+#endif
#else
#define _ASM_NOKPROBE(name)
#endif
diff --git a/arch/loongarch/include/asm/asmmacro.h b/arch/loongarch/include/asm/asmmacro.h
index 8d7f501b0a12..a648be5f723f 100644
--- a/arch/loongarch/include/asm/asmmacro.h
+++ b/arch/loongarch/include/asm/asmmacro.h
@@ -5,43 +5,55 @@
#ifndef _ASM_ASMMACRO_H
#define _ASM_ASMMACRO_H
+#include <linux/sizes.h>
#include <asm/asm-offsets.h>
#include <asm/regdef.h>
#include <asm/fpregdef.h>
#include <asm/loongarch.h>
+#ifdef CONFIG_64BIT
+#define TASK_STRUCT_OFFSET 0
+#else
+#define TASK_STRUCT_OFFSET 2000
+#endif
+
.macro cpu_save_nonscratch thread
- stptr.d s0, \thread, THREAD_REG23
- stptr.d s1, \thread, THREAD_REG24
- stptr.d s2, \thread, THREAD_REG25
- stptr.d s3, \thread, THREAD_REG26
- stptr.d s4, \thread, THREAD_REG27
- stptr.d s5, \thread, THREAD_REG28
- stptr.d s6, \thread, THREAD_REG29
- stptr.d s7, \thread, THREAD_REG30
- stptr.d s8, \thread, THREAD_REG31
- stptr.d sp, \thread, THREAD_REG03
- stptr.d fp, \thread, THREAD_REG22
+ LONG_SPTR s0, \thread, (THREAD_REG23 - TASK_STRUCT_OFFSET)
+ LONG_SPTR s1, \thread, (THREAD_REG24 - TASK_STRUCT_OFFSET)
+ LONG_SPTR s2, \thread, (THREAD_REG25 - TASK_STRUCT_OFFSET)
+ LONG_SPTR s3, \thread, (THREAD_REG26 - TASK_STRUCT_OFFSET)
+ LONG_SPTR s4, \thread, (THREAD_REG27 - TASK_STRUCT_OFFSET)
+ LONG_SPTR s5, \thread, (THREAD_REG28 - TASK_STRUCT_OFFSET)
+ LONG_SPTR s6, \thread, (THREAD_REG29 - TASK_STRUCT_OFFSET)
+ LONG_SPTR s7, \thread, (THREAD_REG30 - TASK_STRUCT_OFFSET)
+ LONG_SPTR s8, \thread, (THREAD_REG31 - TASK_STRUCT_OFFSET)
+ LONG_SPTR ra, \thread, (THREAD_REG01 - TASK_STRUCT_OFFSET)
+ LONG_SPTR sp, \thread, (THREAD_REG03 - TASK_STRUCT_OFFSET)
+ LONG_SPTR fp, \thread, (THREAD_REG22 - TASK_STRUCT_OFFSET)
.endm
.macro cpu_restore_nonscratch thread
- ldptr.d s0, \thread, THREAD_REG23
- ldptr.d s1, \thread, THREAD_REG24
- ldptr.d s2, \thread, THREAD_REG25
- ldptr.d s3, \thread, THREAD_REG26
- ldptr.d s4, \thread, THREAD_REG27
- ldptr.d s5, \thread, THREAD_REG28
- ldptr.d s6, \thread, THREAD_REG29
- ldptr.d s7, \thread, THREAD_REG30
- ldptr.d s8, \thread, THREAD_REG31
- ldptr.d ra, \thread, THREAD_REG01
- ldptr.d sp, \thread, THREAD_REG03
- ldptr.d fp, \thread, THREAD_REG22
+ LONG_LPTR s0, \thread, (THREAD_REG23 - TASK_STRUCT_OFFSET)
+ LONG_LPTR s1, \thread, (THREAD_REG24 - TASK_STRUCT_OFFSET)
+ LONG_LPTR s2, \thread, (THREAD_REG25 - TASK_STRUCT_OFFSET)
+ LONG_LPTR s3, \thread, (THREAD_REG26 - TASK_STRUCT_OFFSET)
+ LONG_LPTR s4, \thread, (THREAD_REG27 - TASK_STRUCT_OFFSET)
+ LONG_LPTR s5, \thread, (THREAD_REG28 - TASK_STRUCT_OFFSET)
+ LONG_LPTR s6, \thread, (THREAD_REG29 - TASK_STRUCT_OFFSET)
+ LONG_LPTR s7, \thread, (THREAD_REG30 - TASK_STRUCT_OFFSET)
+ LONG_LPTR s8, \thread, (THREAD_REG31 - TASK_STRUCT_OFFSET)
+ LONG_LPTR ra, \thread, (THREAD_REG01 - TASK_STRUCT_OFFSET)
+ LONG_LPTR sp, \thread, (THREAD_REG03 - TASK_STRUCT_OFFSET)
+ LONG_LPTR fp, \thread, (THREAD_REG22 - TASK_STRUCT_OFFSET)
.endm
.macro fpu_save_csr thread tmp
movfcsr2gr \tmp, fcsr0
+#ifdef CONFIG_32BIT
+ st.w \tmp, \thread, THREAD_FCSR
+#else
stptr.w \tmp, \thread, THREAD_FCSR
+#endif
#ifdef CONFIG_CPU_HAS_LBT
/* TM bit is always 0 if LBT not supported */
andi \tmp, \tmp, FPU_CSR_TM
@@ -56,7 +68,11 @@
.endm
.macro fpu_restore_csr thread tmp0 tmp1
+#ifdef CONFIG_32BIT
+ ld.w \tmp0, \thread, THREAD_FCSR
+#else
ldptr.w \tmp0, \thread, THREAD_FCSR
+#endif
movgr2fcsr fcsr0, \tmp0
#ifdef CONFIG_CPU_HAS_LBT
/* TM bit is always 0 if LBT not supported */
@@ -88,9 +104,52 @@
#endif
.endm
+#ifdef CONFIG_32BIT
.macro fpu_save_cc thread tmp0 tmp1
movcf2gr \tmp0, $fcc0
- move \tmp1, \tmp0
+ move \tmp1, \tmp0
+ movcf2gr \tmp0, $fcc1
+ bstrins.w \tmp1, \tmp0, 15, 8
+ movcf2gr \tmp0, $fcc2
+ bstrins.w \tmp1, \tmp0, 23, 16
+ movcf2gr \tmp0, $fcc3
+ bstrins.w \tmp1, \tmp0, 31, 24
+ st.w \tmp1, \thread, THREAD_FCC
+ movcf2gr \tmp0, $fcc4
+ move \tmp1, \tmp0
+ movcf2gr \tmp0, $fcc5
+ bstrins.w \tmp1, \tmp0, 15, 8
+ movcf2gr \tmp0, $fcc6
+ bstrins.w \tmp1, \tmp0, 23, 16
+ movcf2gr \tmp0, $fcc7
+ bstrins.w \tmp1, \tmp0, 31, 24
+ st.w \tmp1, \thread, (THREAD_FCC + 4)
+ .endm
+
+ .macro fpu_restore_cc thread tmp0 tmp1
+ ld.w \tmp0, \thread, THREAD_FCC
+ bstrpick.w \tmp1, \tmp0, 7, 0
+ movgr2cf $fcc0, \tmp1
+ bstrpick.w \tmp1, \tmp0, 15, 8
+ movgr2cf $fcc1, \tmp1
+ bstrpick.w \tmp1, \tmp0, 23, 16
+ movgr2cf $fcc2, \tmp1
+ bstrpick.w \tmp1, \tmp0, 31, 24
+ movgr2cf $fcc3, \tmp1
+ ld.w \tmp0, \thread, (THREAD_FCC + 4)
+ bstrpick.w \tmp1, \tmp0, 7, 0
+ movgr2cf $fcc4, \tmp1
+ bstrpick.w \tmp1, \tmp0, 15, 8
+ movgr2cf $fcc5, \tmp1
+ bstrpick.w \tmp1, \tmp0, 23, 16
+ movgr2cf $fcc6, \tmp1
+ bstrpick.w \tmp1, \tmp0, 31, 24
+ movgr2cf $fcc7, \tmp1
+ .endm
+#else
+ .macro fpu_save_cc thread tmp0 tmp1
+ movcf2gr \tmp0, $fcc0
+ move \tmp1, \tmp0
movcf2gr \tmp0, $fcc1
bstrins.d \tmp1, \tmp0, 15, 8
movcf2gr \tmp0, $fcc2
@@ -109,7 +168,7 @@
.endm
.macro fpu_restore_cc thread tmp0 tmp1
- ldptr.d \tmp0, \thread, THREAD_FCC
+ ldptr.d \tmp0, \thread, THREAD_FCC
bstrpick.d \tmp1, \tmp0, 7, 0
movgr2cf $fcc0, \tmp1
bstrpick.d \tmp1, \tmp0, 15, 8
@@ -127,6 +186,7 @@
bstrpick.d \tmp1, \tmp0, 63, 56
movgr2cf $fcc7, \tmp1
.endm
+#endif
.macro fpu_save_double thread tmp
li.w \tmp, THREAD_FPR0
@@ -606,12 +666,14 @@
766:
lu12i.w \reg, 0
ori \reg, \reg, 0
+#ifdef CONFIG_64BIT
lu32i.d \reg, 0
lu52i.d \reg, \reg, 0
+#endif
.pushsection ".la_abs", "aw", %progbits
- .p2align 3
- .dword 766b
- .dword \sym
+ .p2align PTRLOG
+ PTR 766b
+ PTR \sym
.popsection
#endif
.endm
diff --git a/arch/loongarch/include/asm/atomic-amo.h b/arch/loongarch/include/asm/atomic-amo.h
new file mode 100644
index 000000000000..d5efa5252d56
--- /dev/null
+++ b/arch/loongarch/include/asm/atomic-amo.h
@@ -0,0 +1,206 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Atomic operations (AMO).
+ *
+ * Copyright (C) 2020-2025 Loongson Technology Corporation Limited
+ */
+
+#ifndef _ASM_ATOMIC_AMO_H
+#define _ASM_ATOMIC_AMO_H
+
+#include <linux/types.h>
+#include <asm/barrier.h>
+#include <asm/cmpxchg.h>
+
+#define ATOMIC_OP(op, I, asm_op) \
+static inline void arch_atomic_##op(int i, atomic_t *v) \
+{ \
+ __asm__ __volatile__( \
+ "am"#asm_op".w" " $zero, %1, %0 \n" \
+ : "+ZB" (v->counter) \
+ : "r" (I) \
+ : "memory"); \
+}
+
+#define ATOMIC_OP_RETURN(op, I, asm_op, c_op, mb, suffix) \
+static inline int arch_atomic_##op##_return##suffix(int i, atomic_t *v) \
+{ \
+ int result; \
+ \
+ __asm__ __volatile__( \
+ "am"#asm_op#mb".w" " %1, %2, %0 \n" \
+ : "+ZB" (v->counter), "=&r" (result) \
+ : "r" (I) \
+ : "memory"); \
+ \
+ return result c_op I; \
+}
+
+#define ATOMIC_FETCH_OP(op, I, asm_op, mb, suffix) \
+static inline int arch_atomic_fetch_##op##suffix(int i, atomic_t *v) \
+{ \
+ int result; \
+ \
+ __asm__ __volatile__( \
+ "am"#asm_op#mb".w" " %1, %2, %0 \n" \
+ : "+ZB" (v->counter), "=&r" (result) \
+ : "r" (I) \
+ : "memory"); \
+ \
+ return result; \
+}
+
+#define ATOMIC_OPS(op, I, asm_op, c_op) \
+ ATOMIC_OP(op, I, asm_op) \
+ ATOMIC_OP_RETURN(op, I, asm_op, c_op, _db, ) \
+ ATOMIC_OP_RETURN(op, I, asm_op, c_op, , _relaxed) \
+ ATOMIC_FETCH_OP(op, I, asm_op, _db, ) \
+ ATOMIC_FETCH_OP(op, I, asm_op, , _relaxed)
+
+ATOMIC_OPS(add, i, add, +)
+ATOMIC_OPS(sub, -i, add, +)
+
+#define arch_atomic_add_return arch_atomic_add_return
+#define arch_atomic_add_return_acquire arch_atomic_add_return
+#define arch_atomic_add_return_release arch_atomic_add_return
+#define arch_atomic_add_return_relaxed arch_atomic_add_return_relaxed
+#define arch_atomic_sub_return arch_atomic_sub_return
+#define arch_atomic_sub_return_acquire arch_atomic_sub_return
+#define arch_atomic_sub_return_release arch_atomic_sub_return
+#define arch_atomic_sub_return_relaxed arch_atomic_sub_return_relaxed
+#define arch_atomic_fetch_add arch_atomic_fetch_add
+#define arch_atomic_fetch_add_acquire arch_atomic_fetch_add
+#define arch_atomic_fetch_add_release arch_atomic_fetch_add
+#define arch_atomic_fetch_add_relaxed arch_atomic_fetch_add_relaxed
+#define arch_atomic_fetch_sub arch_atomic_fetch_sub
+#define arch_atomic_fetch_sub_acquire arch_atomic_fetch_sub
+#define arch_atomic_fetch_sub_release arch_atomic_fetch_sub
+#define arch_atomic_fetch_sub_relaxed arch_atomic_fetch_sub_relaxed
+
+#undef ATOMIC_OPS
+
+#define ATOMIC_OPS(op, I, asm_op) \
+ ATOMIC_OP(op, I, asm_op) \
+ ATOMIC_FETCH_OP(op, I, asm_op, _db, ) \
+ ATOMIC_FETCH_OP(op, I, asm_op, , _relaxed)
+
+ATOMIC_OPS(and, i, and)
+ATOMIC_OPS(or, i, or)
+ATOMIC_OPS(xor, i, xor)
+
+#define arch_atomic_fetch_and arch_atomic_fetch_and
+#define arch_atomic_fetch_and_acquire arch_atomic_fetch_and
+#define arch_atomic_fetch_and_release arch_atomic_fetch_and
+#define arch_atomic_fetch_and_relaxed arch_atomic_fetch_and_relaxed
+#define arch_atomic_fetch_or arch_atomic_fetch_or
+#define arch_atomic_fetch_or_acquire arch_atomic_fetch_or
+#define arch_atomic_fetch_or_release arch_atomic_fetch_or
+#define arch_atomic_fetch_or_relaxed arch_atomic_fetch_or_relaxed
+#define arch_atomic_fetch_xor arch_atomic_fetch_xor
+#define arch_atomic_fetch_xor_acquire arch_atomic_fetch_xor
+#define arch_atomic_fetch_xor_release arch_atomic_fetch_xor
+#define arch_atomic_fetch_xor_relaxed arch_atomic_fetch_xor_relaxed
+
+#undef ATOMIC_OPS
+#undef ATOMIC_FETCH_OP
+#undef ATOMIC_OP_RETURN
+#undef ATOMIC_OP
+
+#ifdef CONFIG_64BIT
+
+#define ATOMIC64_OP(op, I, asm_op) \
+static inline void arch_atomic64_##op(long i, atomic64_t *v) \
+{ \
+ __asm__ __volatile__( \
+ "am"#asm_op".d " " $zero, %1, %0 \n" \
+ : "+ZB" (v->counter) \
+ : "r" (I) \
+ : "memory"); \
+}
+
+#define ATOMIC64_OP_RETURN(op, I, asm_op, c_op, mb, suffix) \
+static inline long arch_atomic64_##op##_return##suffix(long i, atomic64_t *v) \
+{ \
+ long result; \
+ __asm__ __volatile__( \
+ "am"#asm_op#mb".d " " %1, %2, %0 \n" \
+ : "+ZB" (v->counter), "=&r" (result) \
+ : "r" (I) \
+ : "memory"); \
+ \
+ return result c_op I; \
+}
+
+#define ATOMIC64_FETCH_OP(op, I, asm_op, mb, suffix) \
+static inline long arch_atomic64_fetch_##op##suffix(long i, atomic64_t *v) \
+{ \
+ long result; \
+ \
+ __asm__ __volatile__( \
+ "am"#asm_op#mb".d " " %1, %2, %0 \n" \
+ : "+ZB" (v->counter), "=&r" (result) \
+ : "r" (I) \
+ : "memory"); \
+ \
+ return result; \
+}
+
+#define ATOMIC64_OPS(op, I, asm_op, c_op) \
+ ATOMIC64_OP(op, I, asm_op) \
+ ATOMIC64_OP_RETURN(op, I, asm_op, c_op, _db, ) \
+ ATOMIC64_OP_RETURN(op, I, asm_op, c_op, , _relaxed) \
+ ATOMIC64_FETCH_OP(op, I, asm_op, _db, ) \
+ ATOMIC64_FETCH_OP(op, I, asm_op, , _relaxed)
+
+ATOMIC64_OPS(add, i, add, +)
+ATOMIC64_OPS(sub, -i, add, +)
+
+#define arch_atomic64_add_return arch_atomic64_add_return
+#define arch_atomic64_add_return_acquire arch_atomic64_add_return
+#define arch_atomic64_add_return_release arch_atomic64_add_return
+#define arch_atomic64_add_return_relaxed arch_atomic64_add_return_relaxed
+#define arch_atomic64_sub_return arch_atomic64_sub_return
+#define arch_atomic64_sub_return_acquire arch_atomic64_sub_return
+#define arch_atomic64_sub_return_release arch_atomic64_sub_return
+#define arch_atomic64_sub_return_relaxed arch_atomic64_sub_return_relaxed
+#define arch_atomic64_fetch_add arch_atomic64_fetch_add
+#define arch_atomic64_fetch_add_acquire arch_atomic64_fetch_add
+#define arch_atomic64_fetch_add_release arch_atomic64_fetch_add
+#define arch_atomic64_fetch_add_relaxed arch_atomic64_fetch_add_relaxed
+#define arch_atomic64_fetch_sub arch_atomic64_fetch_sub
+#define arch_atomic64_fetch_sub_acquire arch_atomic64_fetch_sub
+#define arch_atomic64_fetch_sub_release arch_atomic64_fetch_sub
+#define arch_atomic64_fetch_sub_relaxed arch_atomic64_fetch_sub_relaxed
+
+#undef ATOMIC64_OPS
+
+#define ATOMIC64_OPS(op, I, asm_op) \
+ ATOMIC64_OP(op, I, asm_op) \
+ ATOMIC64_FETCH_OP(op, I, asm_op, _db, ) \
+ ATOMIC64_FETCH_OP(op, I, asm_op, , _relaxed)
+
+ATOMIC64_OPS(and, i, and)
+ATOMIC64_OPS(or, i, or)
+ATOMIC64_OPS(xor, i, xor)
+
+#define arch_atomic64_fetch_and arch_atomic64_fetch_and
+#define arch_atomic64_fetch_and_acquire arch_atomic64_fetch_and
+#define arch_atomic64_fetch_and_release arch_atomic64_fetch_and
+#define arch_atomic64_fetch_and_relaxed arch_atomic64_fetch_and_relaxed
+#define arch_atomic64_fetch_or arch_atomic64_fetch_or
+#define arch_atomic64_fetch_or_acquire arch_atomic64_fetch_or
+#define arch_atomic64_fetch_or_release arch_atomic64_fetch_or
+#define arch_atomic64_fetch_or_relaxed arch_atomic64_fetch_or_relaxed
+#define arch_atomic64_fetch_xor arch_atomic64_fetch_xor
+#define arch_atomic64_fetch_xor_acquire arch_atomic64_fetch_xor
+#define arch_atomic64_fetch_xor_release arch_atomic64_fetch_xor
+#define arch_atomic64_fetch_xor_relaxed arch_atomic64_fetch_xor_relaxed
+
+#undef ATOMIC64_OPS
+#undef ATOMIC64_FETCH_OP
+#undef ATOMIC64_OP_RETURN
+#undef ATOMIC64_OP
+
+#endif
+
+#endif /* _ASM_ATOMIC_AMO_H */
diff --git a/arch/loongarch/include/asm/atomic-llsc.h b/arch/loongarch/include/asm/atomic-llsc.h
new file mode 100644
index 000000000000..3ce500c88272
--- /dev/null
+++ b/arch/loongarch/include/asm/atomic-llsc.h
@@ -0,0 +1,100 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Atomic operations (LLSC).
+ *
+ * Copyright (C) 2024-2025 Loongson Technology Corporation Limited
+ */
+
+#ifndef _ASM_ATOMIC_LLSC_H
+#define _ASM_ATOMIC_LLSC_H
+
+#include <linux/types.h>
+#include <asm/barrier.h>
+#include <asm/cmpxchg.h>
+
+#define ATOMIC_OP(op, I, asm_op) \
+static inline void arch_atomic_##op(int i, atomic_t *v) \
+{ \
+ int temp; \
+ \
+ __asm__ __volatile__( \
+ "1: ll.w %0, %1 #atomic_" #op " \n" \
+ " " #asm_op " %0, %0, %2 \n" \
+ " sc.w %0, %1 \n" \
+ " beq %0, $r0, 1b \n" \
+ :"=&r" (temp) , "+ZC"(v->counter) \
+ :"r" (I) \
+ ); \
+}
+
+#define ATOMIC_OP_RETURN(op, I, asm_op) \
+static inline int arch_atomic_##op##_return_relaxed(int i, atomic_t *v) \
+{ \
+ int result, temp; \
+ \
+ __asm__ __volatile__( \
+ "1: ll.w %1, %2 # atomic_" #op "_return \n" \
+ " " #asm_op " %0, %1, %3 \n" \
+ " sc.w %0, %2 \n" \
+ " beq %0, $r0 ,1b \n" \
+ " " #asm_op " %0, %1, %3 \n" \
+ : "=&r" (result), "=&r" (temp), "+ZC"(v->counter) \
+ : "r" (I)); \
+ \
+ return result; \
+}
+
+#define ATOMIC_FETCH_OP(op, I, asm_op) \
+static inline int arch_atomic_fetch_##op##_relaxed(int i, atomic_t *v) \
+{ \
+ int result, temp; \
+ \
+ __asm__ __volatile__( \
+ "1: ll.w %1, %2 # atomic_fetch_" #op " \n" \
+ " " #asm_op " %0, %1, %3 \n" \
+ " sc.w %0, %2 \n" \
+ " beq %0, $r0 ,1b \n" \
+ " add.w %0, %1 ,$r0 \n" \
+ : "=&r" (result), "=&r" (temp), "+ZC" (v->counter) \
+ : "r" (I)); \
+ \
+ return result; \
+}
+
+#define ATOMIC_OPS(op,I ,asm_op, c_op) \
+ ATOMIC_OP(op, I, asm_op) \
+ ATOMIC_OP_RETURN(op, I , asm_op) \
+ ATOMIC_FETCH_OP(op, I, asm_op)
+
+ATOMIC_OPS(add, i , add.w ,+=)
+ATOMIC_OPS(sub, -i , add.w ,+=)
+
+#define arch_atomic_add_return_relaxed arch_atomic_add_return_relaxed
+#define arch_atomic_sub_return_relaxed arch_atomic_sub_return_relaxed
+#define arch_atomic_fetch_add_relaxed arch_atomic_fetch_add_relaxed
+#define arch_atomic_fetch_sub_relaxed arch_atomic_fetch_sub_relaxed
+
+#undef ATOMIC_OPS
+
+#define ATOMIC_OPS(op, I, asm_op) \
+ ATOMIC_OP(op, I, asm_op) \
+ ATOMIC_FETCH_OP(op, I, asm_op)
+
+ATOMIC_OPS(and, i, and)
+ATOMIC_OPS(or, i, or)
+ATOMIC_OPS(xor, i, xor)
+
+#define arch_atomic_fetch_and_relaxed arch_atomic_fetch_and_relaxed
+#define arch_atomic_fetch_or_relaxed arch_atomic_fetch_or_relaxed
+#define arch_atomic_fetch_xor_relaxed arch_atomic_fetch_xor_relaxed
+
+#undef ATOMIC_OPS
+#undef ATOMIC_FETCH_OP
+#undef ATOMIC_OP_RETURN
+#undef ATOMIC_OP
+
+#ifdef CONFIG_64BIT
+#error "64-bit LLSC atomic operations are not supported"
+#endif
+
+#endif /* _ASM_ATOMIC_LLSC_H */
diff --git a/arch/loongarch/include/asm/atomic.h b/arch/loongarch/include/asm/atomic.h
index c86f0ab922ec..444b9ddcd004 100644
--- a/arch/loongarch/include/asm/atomic.h
+++ b/arch/loongarch/include/asm/atomic.h
@@ -11,6 +11,16 @@
#include <asm/barrier.h>
#include <asm/cmpxchg.h>
+#ifdef CONFIG_CPU_HAS_AMO
+#include <asm/atomic-amo.h>
+#else
+#include <asm/atomic-llsc.h>
+#endif
+
+#ifdef CONFIG_GENERIC_ATOMIC64
+#include <asm-generic/atomic64.h>
+#endif
+
#if __SIZEOF_LONG__ == 4
#define __LL "ll.w "
#define __SC "sc.w "
@@ -34,100 +44,6 @@
#define arch_atomic_read(v) READ_ONCE((v)->counter)
#define arch_atomic_set(v, i) WRITE_ONCE((v)->counter, (i))
-#define ATOMIC_OP(op, I, asm_op) \
-static inline void arch_atomic_##op(int i, atomic_t *v) \
-{ \
- __asm__ __volatile__( \
- "am"#asm_op".w" " $zero, %1, %0 \n" \
- : "+ZB" (v->counter) \
- : "r" (I) \
- : "memory"); \
-}
-
-#define ATOMIC_OP_RETURN(op, I, asm_op, c_op, mb, suffix) \
-static inline int arch_atomic_##op##_return##suffix(int i, atomic_t *v) \
-{ \
- int result; \
- \
- __asm__ __volatile__( \
- "am"#asm_op#mb".w" " %1, %2, %0 \n" \
- : "+ZB" (v->counter), "=&r" (result) \
- : "r" (I) \
- : "memory"); \
- \
- return result c_op I; \
-}
-
-#define ATOMIC_FETCH_OP(op, I, asm_op, mb, suffix) \
-static inline int arch_atomic_fetch_##op##suffix(int i, atomic_t *v) \
-{ \
- int result; \
- \
- __asm__ __volatile__( \
- "am"#asm_op#mb".w" " %1, %2, %0 \n" \
- : "+ZB" (v->counter), "=&r" (result) \
- : "r" (I) \
- : "memory"); \
- \
- return result; \
-}
-
-#define ATOMIC_OPS(op, I, asm_op, c_op) \
- ATOMIC_OP(op, I, asm_op) \
- ATOMIC_OP_RETURN(op, I, asm_op, c_op, _db, ) \
- ATOMIC_OP_RETURN(op, I, asm_op, c_op, , _relaxed) \
- ATOMIC_FETCH_OP(op, I, asm_op, _db, ) \
- ATOMIC_FETCH_OP(op, I, asm_op, , _relaxed)
-
-ATOMIC_OPS(add, i, add, +)
-ATOMIC_OPS(sub, -i, add, +)
-
-#define arch_atomic_add_return arch_atomic_add_return
-#define arch_atomic_add_return_acquire arch_atomic_add_return
-#define arch_atomic_add_return_release arch_atomic_add_return
-#define arch_atomic_add_return_relaxed arch_atomic_add_return_relaxed
-#define arch_atomic_sub_return arch_atomic_sub_return
-#define arch_atomic_sub_return_acquire arch_atomic_sub_return
-#define arch_atomic_sub_return_release arch_atomic_sub_return
-#define arch_atomic_sub_return_relaxed arch_atomic_sub_return_relaxed
-#define arch_atomic_fetch_add arch_atomic_fetch_add
-#define arch_atomic_fetch_add_acquire arch_atomic_fetch_add
-#define arch_atomic_fetch_add_release arch_atomic_fetch_add
-#define arch_atomic_fetch_add_relaxed arch_atomic_fetch_add_relaxed
-#define arch_atomic_fetch_sub arch_atomic_fetch_sub
-#define arch_atomic_fetch_sub_acquire arch_atomic_fetch_sub
-#define arch_atomic_fetch_sub_release arch_atomic_fetch_sub
-#define arch_atomic_fetch_sub_relaxed arch_atomic_fetch_sub_relaxed
-
-#undef ATOMIC_OPS
-
-#define ATOMIC_OPS(op, I, asm_op) \
- ATOMIC_OP(op, I, asm_op) \
- ATOMIC_FETCH_OP(op, I, asm_op, _db, ) \
- ATOMIC_FETCH_OP(op, I, asm_op, , _relaxed)
-
-ATOMIC_OPS(and, i, and)
-ATOMIC_OPS(or, i, or)
-ATOMIC_OPS(xor, i, xor)
-
-#define arch_atomic_fetch_and arch_atomic_fetch_and
-#define arch_atomic_fetch_and_acquire arch_atomic_fetch_and
-#define arch_atomic_fetch_and_release arch_atomic_fetch_and
-#define arch_atomic_fetch_and_relaxed arch_atomic_fetch_and_relaxed
-#define arch_atomic_fetch_or arch_atomic_fetch_or
-#define arch_atomic_fetch_or_acquire arch_atomic_fetch_or
-#define arch_atomic_fetch_or_release arch_atomic_fetch_or
-#define arch_atomic_fetch_or_relaxed arch_atomic_fetch_or_relaxed
-#define arch_atomic_fetch_xor arch_atomic_fetch_xor
-#define arch_atomic_fetch_xor_acquire arch_atomic_fetch_xor
-#define arch_atomic_fetch_xor_release arch_atomic_fetch_xor
-#define arch_atomic_fetch_xor_relaxed arch_atomic_fetch_xor_relaxed
-
-#undef ATOMIC_OPS
-#undef ATOMIC_FETCH_OP
-#undef ATOMIC_OP_RETURN
-#undef ATOMIC_OP
-
static inline int arch_atomic_fetch_add_unless(atomic_t *v, int a, int u)
{
int prev, rc;
@@ -194,99 +110,6 @@ static inline int arch_atomic_sub_if_positive(int i, atomic_t *v)
#define arch_atomic64_read(v) READ_ONCE((v)->counter)
#define arch_atomic64_set(v, i) WRITE_ONCE((v)->counter, (i))
-#define ATOMIC64_OP(op, I, asm_op) \
-static inline void arch_atomic64_##op(long i, atomic64_t *v) \
-{ \
- __asm__ __volatile__( \
- "am"#asm_op".d " " $zero, %1, %0 \n" \
- : "+ZB" (v->counter) \
- : "r" (I) \
- : "memory"); \
-}
-
-#define ATOMIC64_OP_RETURN(op, I, asm_op, c_op, mb, suffix) \
-static inline long arch_atomic64_##op##_return##suffix(long i, atomic64_t *v) \
-{ \
- long result; \
- __asm__ __volatile__( \
- "am"#asm_op#mb".d " " %1, %2, %0 \n" \
- : "+ZB" (v->counter), "=&r" (result) \
- : "r" (I) \
- : "memory"); \
- \
- return result c_op I; \
-}
-
-#define ATOMIC64_FETCH_OP(op, I, asm_op, mb, suffix) \
-static inline long arch_atomic64_fetch_##op##suffix(long i, atomic64_t *v) \
-{ \
- long result; \
- \
- __asm__ __volatile__( \
- "am"#asm_op#mb".d " " %1, %2, %0 \n" \
- : "+ZB" (v->counter), "=&r" (result) \
- : "r" (I) \
- : "memory"); \
- \
- return result; \
-}
-
-#define ATOMIC64_OPS(op, I, asm_op, c_op) \
- ATOMIC64_OP(op, I, asm_op) \
- ATOMIC64_OP_RETURN(op, I, asm_op, c_op, _db, ) \
- ATOMIC64_OP_RETURN(op, I, asm_op, c_op, , _relaxed) \
- ATOMIC64_FETCH_OP(op, I, asm_op, _db, ) \
- ATOMIC64_FETCH_OP(op, I, asm_op, , _relaxed)
-
-ATOMIC64_OPS(add, i, add, +)
-ATOMIC64_OPS(sub, -i, add, +)
-
-#define arch_atomic64_add_return arch_atomic64_add_return
-#define arch_atomic64_add_return_acquire arch_atomic64_add_return
-#define arch_atomic64_add_return_release arch_atomic64_add_return
-#define arch_atomic64_add_return_relaxed arch_atomic64_add_return_relaxed
-#define arch_atomic64_sub_return arch_atomic64_sub_return
-#define arch_atomic64_sub_return_acquire arch_atomic64_sub_return
-#define arch_atomic64_sub_return_release arch_atomic64_sub_return
-#define arch_atomic64_sub_return_relaxed arch_atomic64_sub_return_relaxed
-#define arch_atomic64_fetch_add arch_atomic64_fetch_add
-#define arch_atomic64_fetch_add_acquire arch_atomic64_fetch_add
-#define arch_atomic64_fetch_add_release arch_atomic64_fetch_add
-#define arch_atomic64_fetch_add_relaxed arch_atomic64_fetch_add_relaxed
-#define arch_atomic64_fetch_sub arch_atomic64_fetch_sub
-#define arch_atomic64_fetch_sub_acquire arch_atomic64_fetch_sub
-#define arch_atomic64_fetch_sub_release arch_atomic64_fetch_sub
-#define arch_atomic64_fetch_sub_relaxed arch_atomic64_fetch_sub_relaxed
-
-#undef ATOMIC64_OPS
-
-#define ATOMIC64_OPS(op, I, asm_op) \
- ATOMIC64_OP(op, I, asm_op) \
- ATOMIC64_FETCH_OP(op, I, asm_op, _db, ) \
- ATOMIC64_FETCH_OP(op, I, asm_op, , _relaxed)
-
-ATOMIC64_OPS(and, i, and)
-ATOMIC64_OPS(or, i, or)
-ATOMIC64_OPS(xor, i, xor)
-
-#define arch_atomic64_fetch_and arch_atomic64_fetch_and
-#define arch_atomic64_fetch_and_acquire arch_atomic64_fetch_and
-#define arch_atomic64_fetch_and_release arch_atomic64_fetch_and
-#define arch_atomic64_fetch_and_relaxed arch_atomic64_fetch_and_relaxed
-#define arch_atomic64_fetch_or arch_atomic64_fetch_or
-#define arch_atomic64_fetch_or_acquire arch_atomic64_fetch_or
-#define arch_atomic64_fetch_or_release arch_atomic64_fetch_or
-#define arch_atomic64_fetch_or_relaxed arch_atomic64_fetch_or_relaxed
-#define arch_atomic64_fetch_xor arch_atomic64_fetch_xor
-#define arch_atomic64_fetch_xor_acquire arch_atomic64_fetch_xor
-#define arch_atomic64_fetch_xor_release arch_atomic64_fetch_xor
-#define arch_atomic64_fetch_xor_relaxed arch_atomic64_fetch_xor_relaxed
-
-#undef ATOMIC64_OPS
-#undef ATOMIC64_FETCH_OP
-#undef ATOMIC64_OP_RETURN
-#undef ATOMIC64_OP
-
static inline long arch_atomic64_fetch_add_unless(atomic64_t *v, long a, long u)
{
long prev, rc;
diff --git a/arch/loongarch/include/asm/bitops.h b/arch/loongarch/include/asm/bitops.h
index 69e00f8d8034..411106bf9902 100644
--- a/arch/loongarch/include/asm/bitops.h
+++ b/arch/loongarch/include/asm/bitops.h
@@ -13,11 +13,22 @@
#include <asm/barrier.h>
+#ifdef CONFIG_32BIT_REDUCED
+
+#include <asm-generic/bitops/ffs.h>
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/__ffs.h>
+#include <asm-generic/bitops/__fls.h>
+
+#else /* CONFIG_32BIT_STANDARD || CONFIG_64BIT */
+
#include <asm-generic/bitops/builtin-ffs.h>
#include <asm-generic/bitops/builtin-fls.h>
#include <asm-generic/bitops/builtin-__ffs.h>
#include <asm-generic/bitops/builtin-__fls.h>
+#endif
+
#include <asm-generic/bitops/ffz.h>
#include <asm-generic/bitops/fls64.h>
diff --git a/arch/loongarch/include/asm/bitrev.h b/arch/loongarch/include/asm/bitrev.h
index 46f275b9cdf7..757738ea38d7 100644
--- a/arch/loongarch/include/asm/bitrev.h
+++ b/arch/loongarch/include/asm/bitrev.h
@@ -11,7 +11,7 @@ static __always_inline __attribute_const__ u32 __arch_bitrev32(u32 x)
{
u32 ret;
- asm("bitrev.4b %0, %1" : "=r"(ret) : "r"(__swab32(x)));
+ asm("bitrev.w %0, %1" : "=r"(ret) : "r"(x));
return ret;
}
diff --git a/arch/loongarch/include/asm/checksum.h b/arch/loongarch/include/asm/checksum.h
index cabbf6af44c4..cc2754e0aa25 100644
--- a/arch/loongarch/include/asm/checksum.h
+++ b/arch/loongarch/include/asm/checksum.h
@@ -9,6 +9,8 @@
#include <linux/bitops.h>
#include <linux/in6.h>
+#ifdef CONFIG_64BIT
+
#define _HAVE_ARCH_IPV6_CSUM
__sum16 csum_ipv6_magic(const struct in6_addr *saddr,
const struct in6_addr *daddr,
@@ -61,6 +63,8 @@ static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
extern unsigned int do_csum(const unsigned char *buff, int len);
#define do_csum do_csum
+#endif
+
#include <asm-generic/checksum.h>
#endif /* __ASM_CHECKSUM_H */
diff --git a/arch/loongarch/include/asm/cmpxchg.h b/arch/loongarch/include/asm/cmpxchg.h
index 979fde61bba8..0494c2ab553e 100644
--- a/arch/loongarch/include/asm/cmpxchg.h
+++ b/arch/loongarch/include/asm/cmpxchg.h
@@ -9,17 +9,33 @@
#include <linux/build_bug.h>
#include <asm/barrier.h>
-#define __xchg_asm(amswap_db, m, val) \
+#define __xchg_amo_asm(amswap_db, m, val) \
({ \
- __typeof(val) __ret; \
+ __typeof(val) __ret; \
\
- __asm__ __volatile__ ( \
- " "amswap_db" %1, %z2, %0 \n" \
- : "+ZB" (*m), "=&r" (__ret) \
- : "Jr" (val) \
- : "memory"); \
+ __asm__ __volatile__ ( \
+ " "amswap_db" %1, %z2, %0 \n" \
+ : "+ZB" (*m), "=&r" (__ret) \
+ : "Jr" (val) \
+ : "memory"); \
\
- __ret; \
+ __ret; \
+})
+
+#define __xchg_llsc_asm(ld, st, m, val) \
+({ \
+ __typeof(val) __ret, __tmp; \
+ \
+ asm volatile ( \
+ "1: ll.w %0, %3 \n" \
+ " move %1, %z4 \n" \
+ " sc.w %1, %2 \n" \
+ " beqz %1, 1b \n" \
+ : "=&r" (__ret), "=&r" (__tmp), "=ZC" (*m) \
+ : "ZC" (*m), "Jr" (val) \
+ : "memory"); \
+ \
+ __ret; \
})
static inline unsigned int __xchg_small(volatile void *ptr, unsigned int val,
@@ -67,13 +83,23 @@ __arch_xchg(volatile void *ptr, unsigned long x, int size)
switch (size) {
case 1:
case 2:
- return __xchg_small(ptr, x, size);
+ return __xchg_small((volatile void *)ptr, x, size);
case 4:
- return __xchg_asm("amswap_db.w", (volatile u32 *)ptr, (u32)x);
+#ifdef CONFIG_CPU_HAS_AMO
+ return __xchg_amo_asm("amswap_db.w", (volatile u32 *)ptr, (u32)x);
+#else
+ return __xchg_llsc_asm("ll.w", "sc.w", (volatile u32 *)ptr, (u32)x);
+#endif /* CONFIG_CPU_HAS_AMO */
+#ifdef CONFIG_64BIT
case 8:
- return __xchg_asm("amswap_db.d", (volatile u64 *)ptr, (u64)x);
+#ifdef CONFIG_CPU_HAS_AMO
+ return __xchg_amo_asm("amswap_db.d", (volatile u64 *)ptr, (u64)x);
+#else
+ return __xchg_llsc_asm("ll.d", "sc.d", (volatile u64 *)ptr, (u64)x);
+#endif /* CONFIG_CPU_HAS_AMO */
+#endif /* CONFIG_64BIT */
default:
BUILD_BUG();
diff --git a/arch/loongarch/include/asm/cpu-features.h b/arch/loongarch/include/asm/cpu-features.h
index bd5f0457ad21..3745d991a99a 100644
--- a/arch/loongarch/include/asm/cpu-features.h
+++ b/arch/loongarch/include/asm/cpu-features.h
@@ -20,16 +20,13 @@
#define cpu_has_loongarch64 (cpu_data[0].isa_level & LOONGARCH_CPU_ISA_64BIT)
#ifdef CONFIG_32BIT
-# define cpu_has_64bits (cpu_data[0].isa_level & LOONGARCH_CPU_ISA_64BIT)
# define cpu_vabits 31
# define cpu_pabits 31
#endif
#ifdef CONFIG_64BIT
-# define cpu_has_64bits 1
# define cpu_vabits cpu_data[0].vabits
# define cpu_pabits cpu_data[0].pabits
-# define __NEED_ADDRBITS_PROBE
#endif
/*
diff --git a/arch/loongarch/include/asm/dmi.h b/arch/loongarch/include/asm/dmi.h
index 605493417753..11bb3c8a7179 100644
--- a/arch/loongarch/include/asm/dmi.h
+++ b/arch/loongarch/include/asm/dmi.h
@@ -12,7 +12,7 @@
#define dmi_early_unmap(x, l) dmi_unmap(x)
#define dmi_alloc(l) memblock_alloc(l, PAGE_SIZE)
-static inline void *dmi_remap(u64 phys_addr, unsigned long size)
+static inline void *dmi_remap(phys_addr_t phys_addr, unsigned long size)
{
return ((void *)TO_CACHE(phys_addr));
}
diff --git a/arch/loongarch/include/asm/elf.h b/arch/loongarch/include/asm/elf.h
index f16bd42456e4..912c50cdd6b7 100644
--- a/arch/loongarch/include/asm/elf.h
+++ b/arch/loongarch/include/asm/elf.h
@@ -120,6 +120,36 @@
#define R_LARCH_ADD_ULEB128 107
#define R_LARCH_SUB_ULEB128 108
#define R_LARCH_64_PCREL 109
+#define R_LARCH_CALL36 110
+#define R_LARCH_TLS_DESC_PC_HI20 111
+#define R_LARCH_TLS_DESC_PC_LO12 112
+#define R_LARCH_TLS_DESC64_PC_LO20 113
+#define R_LARCH_TLS_DESC64_PC_HI12 114
+#define R_LARCH_TLS_DESC_HI20 115
+#define R_LARCH_TLS_DESC_LO12 116
+#define R_LARCH_TLS_DESC64_LO20 117
+#define R_LARCH_TLS_DESC64_HI12 118
+#define R_LARCH_TLS_DESC_LD 119
+#define R_LARCH_TLS_DESC_CALL 120
+#define R_LARCH_TLS_LE_HI20_R 121
+#define R_LARCH_TLS_LE_ADD_R 122
+#define R_LARCH_TLS_LE_LO12_R 123
+#define R_LARCH_TLS_LD_PCREL20_S2 124
+#define R_LARCH_TLS_GD_PCREL20_S2 125
+#define R_LARCH_TLS_DESC_PCREL20_S2 126
+#define R_LARCH_CALL30 127
+#define R_LARCH_PCADD_HI20 128
+#define R_LARCH_PCADD_LO12 129
+#define R_LARCH_GOT_PCADD_HI20 130
+#define R_LARCH_GOT_PCADD_LO12 131
+#define R_LARCH_TLS_IE_PCADD_HI20 132
+#define R_LARCH_TLS_IE_PCADD_LO12 133
+#define R_LARCH_TLS_LD_PCADD_HI20 134
+#define R_LARCH_TLS_LD_PCADD_LO12 135
+#define R_LARCH_TLS_GD_PCADD_HI20 136
+#define R_LARCH_TLS_GD_PCADD_LO12 137
+#define R_LARCH_TLS_DESC_PCADD_HI20 138
+#define R_LARCH_TLS_DESC_PCADD_LO12 139
#ifndef ELF_ARCH
@@ -156,6 +186,7 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG];
typedef double elf_fpreg_t;
typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
+void loongarch_dump_regs32(u32 *uregs, const struct pt_regs *regs);
void loongarch_dump_regs64(u64 *uregs, const struct pt_regs *regs);
#ifdef CONFIG_32BIT
diff --git a/arch/loongarch/include/asm/inst.h b/arch/loongarch/include/asm/inst.h
index 55e64a12a124..f9f207082d0e 100644
--- a/arch/loongarch/include/asm/inst.h
+++ b/arch/loongarch/include/asm/inst.h
@@ -438,8 +438,10 @@ static inline bool is_branch_ins(union loongarch_instruction *ip)
static inline bool is_ra_save_ins(union loongarch_instruction *ip)
{
- /* st.d $ra, $sp, offset */
- return ip->reg2i12_format.opcode == std_op &&
+ const u32 opcode = IS_ENABLED(CONFIG_32BIT) ? stw_op : std_op;
+
+ /* st.w / st.d $ra, $sp, offset */
+ return ip->reg2i12_format.opcode == opcode &&
ip->reg2i12_format.rj == LOONGARCH_GPR_SP &&
ip->reg2i12_format.rd == LOONGARCH_GPR_RA &&
!is_imm12_negative(ip->reg2i12_format.immediate);
@@ -447,8 +449,10 @@ static inline bool is_ra_save_ins(union loongarch_instruction *ip)
static inline bool is_stack_alloc_ins(union loongarch_instruction *ip)
{
- /* addi.d $sp, $sp, -imm */
- return ip->reg2i12_format.opcode == addid_op &&
+ const u32 opcode = IS_ENABLED(CONFIG_32BIT) ? addiw_op : addid_op;
+
+ /* addi.w / addi.d $sp, $sp, -imm */
+ return ip->reg2i12_format.opcode == opcode &&
ip->reg2i12_format.rj == LOONGARCH_GPR_SP &&
ip->reg2i12_format.rd == LOONGARCH_GPR_SP &&
is_imm12_negative(ip->reg2i12_format.immediate);
diff --git a/arch/loongarch/include/asm/irq.h b/arch/loongarch/include/asm/irq.h
index 12bd15578c33..3943647503a9 100644
--- a/arch/loongarch/include/asm/irq.h
+++ b/arch/loongarch/include/asm/irq.h
@@ -50,10 +50,22 @@ void spurious_interrupt(void);
#define NR_LEGACY_VECTORS 16
#define IRQ_MATRIX_BITS NR_VECTORS
+#define AVEC_IRQ_SHIFT 4
+#define AVEC_IRQ_BIT 8
+#define AVEC_IRQ_MASK GENMASK(AVEC_IRQ_BIT - 1, 0)
+#define AVEC_CPU_SHIFT 12
+#define AVEC_CPU_BIT 16
+#define AVEC_CPU_MASK GENMASK(AVEC_CPU_BIT - 1, 0)
+
#define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace
void arch_trigger_cpumask_backtrace(const struct cpumask *mask, int exclude_cpu);
+#ifdef CONFIG_32BIT
+#define MAX_IO_PICS 1
+#else
#define MAX_IO_PICS 8
+#endif
+
#define NR_IRQS (64 + NR_VECTORS * (NR_CPUS + MAX_IO_PICS))
struct acpi_vector_group {
diff --git a/arch/loongarch/include/asm/jump_label.h b/arch/loongarch/include/asm/jump_label.h
index 4000c7603d8e..dcaecf69ea5a 100644
--- a/arch/loongarch/include/asm/jump_label.h
+++ b/arch/loongarch/include/asm/jump_label.h
@@ -10,15 +10,23 @@
#ifndef __ASSEMBLER__
#include <linux/types.h>
+#include <linux/stringify.h>
+#include <asm/asm.h>
#define JUMP_LABEL_NOP_SIZE 4
+#ifdef CONFIG_32BIT
+#define JUMP_LABEL_TYPE ".long "
+#else
+#define JUMP_LABEL_TYPE ".quad "
+#endif
+
/* This macro is also expanded on the Rust side. */
#define JUMP_TABLE_ENTRY(key, label) \
".pushsection __jump_table, \"aw\" \n\t" \
- ".align 3 \n\t" \
+ ".align " __stringify(PTRLOG) " \n\t" \
".long 1b - ., " label " - . \n\t" \
- ".quad " key " - . \n\t" \
+ JUMP_LABEL_TYPE key " - . \n\t" \
".popsection \n\t"
#define ARCH_STATIC_BRANCH_ASM(key, label) \
diff --git a/arch/loongarch/include/asm/local.h b/arch/loongarch/include/asm/local.h
index f53ea653af76..2d118b1a060e 100644
--- a/arch/loongarch/include/asm/local.h
+++ b/arch/loongarch/include/asm/local.h
@@ -8,6 +8,7 @@
#include <linux/percpu.h>
#include <linux/bitops.h>
#include <linux/atomic.h>
+#include <asm/asm.h>
#include <asm/cmpxchg.h>
typedef struct {
@@ -27,6 +28,7 @@ typedef struct {
/*
* Same as above, but return the result value
*/
+#ifdef CONFIG_CPU_HAS_AMO
static inline long local_add_return(long i, local_t *l)
{
unsigned long result;
@@ -55,6 +57,41 @@ static inline long local_sub_return(long i, local_t *l)
return result;
}
+#else
+static inline long local_add_return(long i, local_t *l)
+{
+ unsigned long result, temp;
+
+ __asm__ __volatile__(
+ "1:" __LL "%1, %2 # local_add_return \n"
+ __stringify(LONG_ADD) " %0, %1, %3 \n"
+ __SC "%0, %2 \n"
+ " beq %0, $r0, 1b \n"
+ __stringify(LONG_ADD) " %0, %1, %3 \n"
+ : "=&r" (result), "=&r" (temp), "=ZC" (l->a.counter)
+ : "r" (i), "ZC" (l->a.counter)
+ : "memory");
+
+ return result;
+}
+
+static inline long local_sub_return(long i, local_t *l)
+{
+ unsigned long result, temp;
+
+ __asm__ __volatile__(
+ "1:" __LL "%1, %2 # local_sub_return \n"
+ __stringify(LONG_SUB) " %0, %1, %3 \n"
+ __SC "%0, %2 \n"
+ " beq %0, $r0, 1b \n"
+ __stringify(LONG_SUB) " %0, %1, %3 \n"
+ : "=&r" (result), "=&r" (temp), "=ZC" (l->a.counter)
+ : "r" (i), "ZC" (l->a.counter)
+ : "memory");
+
+ return result;
+}
+#endif
static inline long local_cmpxchg(local_t *l, long old, long new)
{
diff --git a/arch/loongarch/include/asm/loongarch.h b/arch/loongarch/include/asm/loongarch.h
index 58a4a3b6b035..e6b8ff61c8cc 100644
--- a/arch/loongarch/include/asm/loongarch.h
+++ b/arch/loongarch/include/asm/loongarch.h
@@ -182,6 +182,16 @@
#define csr_xchg32(val, mask, reg) __csrxchg_w(val, mask, reg)
#define csr_xchg64(val, mask, reg) __csrxchg_d(val, mask, reg)
+#ifdef CONFIG_32BIT
+#define csr_read(reg) csr_read32(reg)
+#define csr_write(val, reg) csr_write32(val, reg)
+#define csr_xchg(val, mask, reg) csr_xchg32(val, mask, reg)
+#else
+#define csr_read(reg) csr_read64(reg)
+#define csr_write(val, reg) csr_write64(val, reg)
+#define csr_xchg(val, mask, reg) csr_xchg64(val, mask, reg)
+#endif
+
/* IOCSR */
#define iocsr_read32(reg) __iocsrrd_w(reg)
#define iocsr_read64(reg) __iocsrrd_d(reg)
@@ -904,6 +914,26 @@
#define LOONGARCH_CSR_DMWIN3 0x183 /* 64 direct map win3: MEM */
/* Direct Map window 0/1/2/3 */
+
+#ifdef CONFIG_32BIT
+
+#define CSR_DMW0_PLV0 (1 << 0)
+#define CSR_DMW0_VSEG (0x4)
+#define CSR_DMW0_BASE (CSR_DMW0_VSEG << DMW_PABITS)
+#define CSR_DMW0_INIT (CSR_DMW0_BASE | CSR_DMW0_PLV0)
+
+#define CSR_DMW1_PLV0 (1 << 0)
+#define CSR_DMW1_MAT (1 << 4)
+#define CSR_DMW1_VSEG (0x5)
+#define CSR_DMW1_BASE (CSR_DMW1_VSEG << DMW_PABITS)
+#define CSR_DMW1_INIT (CSR_DMW1_BASE | CSR_DMW1_MAT | CSR_DMW1_PLV0)
+
+#define CSR_DMW2_INIT 0x0
+
+#define CSR_DMW3_INIT 0x0
+
+#else
+
#define CSR_DMW0_PLV0 _CONST64_(1 << 0)
#define CSR_DMW0_VSEG _CONST64_(0x8000)
#define CSR_DMW0_BASE (CSR_DMW0_VSEG << DMW_PABITS)
@@ -923,6 +953,8 @@
#define CSR_DMW3_INIT 0x0
+#endif
+
/* Performance Counter registers */
#define LOONGARCH_CSR_PERFCTRL0 0x200 /* 32 perf event 0 config */
#define LOONGARCH_CSR_PERFCNTR0 0x201 /* 64 perf event 0 count value */
@@ -1208,7 +1240,35 @@
#ifndef __ASSEMBLER__
-static __always_inline u64 drdtime(void)
+#ifdef CONFIG_32BIT
+
+static __always_inline u32 rdtime_h(void)
+{
+ u32 val = 0;
+
+ __asm__ __volatile__(
+ "rdtimeh.w %0, $zero\n\t"
+ : "=r"(val)
+ :
+ );
+ return val;
+}
+
+static __always_inline u32 rdtime_l(void)
+{
+ u32 val = 0;
+
+ __asm__ __volatile__(
+ "rdtimel.w %0, $zero\n\t"
+ : "=r"(val)
+ :
+ );
+ return val;
+}
+
+#else
+
+static __always_inline u64 rdtime_d(void)
{
u64 val = 0;
@@ -1220,11 +1280,14 @@ static __always_inline u64 drdtime(void)
return val;
}
+#endif
+
static inline unsigned int get_csr_cpuid(void)
{
return csr_read32(LOONGARCH_CSR_CPUID);
}
+#ifdef CONFIG_64BIT
static inline void csr_any_send(unsigned int addr, unsigned int data,
unsigned int data_mask, unsigned int cpu)
{
@@ -1236,6 +1299,7 @@ static inline void csr_any_send(unsigned int addr, unsigned int data,
val |= ((uint64_t)data << IOCSR_ANY_SEND_BUF_SHIFT);
iocsr_write64(val, LOONGARCH_IOCSR_ANY_SEND);
}
+#endif
static inline unsigned int read_csr_excode(void)
{
@@ -1259,22 +1323,22 @@ static inline void write_csr_pagesize(unsigned int size)
static inline unsigned int read_csr_tlbrefill_pagesize(void)
{
- return (csr_read64(LOONGARCH_CSR_TLBREHI) & CSR_TLBREHI_PS) >> CSR_TLBREHI_PS_SHIFT;
+ return (csr_read(LOONGARCH_CSR_TLBREHI) & CSR_TLBREHI_PS) >> CSR_TLBREHI_PS_SHIFT;
}
static inline void write_csr_tlbrefill_pagesize(unsigned int size)
{
- csr_xchg64(size << CSR_TLBREHI_PS_SHIFT, CSR_TLBREHI_PS, LOONGARCH_CSR_TLBREHI);
+ csr_xchg(size << CSR_TLBREHI_PS_SHIFT, CSR_TLBREHI_PS, LOONGARCH_CSR_TLBREHI);
}
#define read_csr_asid() csr_read32(LOONGARCH_CSR_ASID)
#define write_csr_asid(val) csr_write32(val, LOONGARCH_CSR_ASID)
-#define read_csr_entryhi() csr_read64(LOONGARCH_CSR_TLBEHI)
-#define write_csr_entryhi(val) csr_write64(val, LOONGARCH_CSR_TLBEHI)
-#define read_csr_entrylo0() csr_read64(LOONGARCH_CSR_TLBELO0)
-#define write_csr_entrylo0(val) csr_write64(val, LOONGARCH_CSR_TLBELO0)
-#define read_csr_entrylo1() csr_read64(LOONGARCH_CSR_TLBELO1)
-#define write_csr_entrylo1(val) csr_write64(val, LOONGARCH_CSR_TLBELO1)
+#define read_csr_entryhi() csr_read(LOONGARCH_CSR_TLBEHI)
+#define write_csr_entryhi(val) csr_write(val, LOONGARCH_CSR_TLBEHI)
+#define read_csr_entrylo0() csr_read(LOONGARCH_CSR_TLBELO0)
+#define write_csr_entrylo0(val) csr_write(val, LOONGARCH_CSR_TLBELO0)
+#define read_csr_entrylo1() csr_read(LOONGARCH_CSR_TLBELO1)
+#define write_csr_entrylo1(val) csr_write(val, LOONGARCH_CSR_TLBELO1)
#define read_csr_ecfg() csr_read32(LOONGARCH_CSR_ECFG)
#define write_csr_ecfg(val) csr_write32(val, LOONGARCH_CSR_ECFG)
#define read_csr_estat() csr_read32(LOONGARCH_CSR_ESTAT)
@@ -1284,20 +1348,20 @@ static inline void write_csr_tlbrefill_pagesize(unsigned int size)
#define read_csr_euen() csr_read32(LOONGARCH_CSR_EUEN)
#define write_csr_euen(val) csr_write32(val, LOONGARCH_CSR_EUEN)
#define read_csr_cpuid() csr_read32(LOONGARCH_CSR_CPUID)
-#define read_csr_prcfg1() csr_read64(LOONGARCH_CSR_PRCFG1)
-#define write_csr_prcfg1(val) csr_write64(val, LOONGARCH_CSR_PRCFG1)
-#define read_csr_prcfg2() csr_read64(LOONGARCH_CSR_PRCFG2)
-#define write_csr_prcfg2(val) csr_write64(val, LOONGARCH_CSR_PRCFG2)
-#define read_csr_prcfg3() csr_read64(LOONGARCH_CSR_PRCFG3)
-#define write_csr_prcfg3(val) csr_write64(val, LOONGARCH_CSR_PRCFG3)
+#define read_csr_prcfg1() csr_read(LOONGARCH_CSR_PRCFG1)
+#define write_csr_prcfg1(val) csr_write(val, LOONGARCH_CSR_PRCFG1)
+#define read_csr_prcfg2() csr_read(LOONGARCH_CSR_PRCFG2)
+#define write_csr_prcfg2(val) csr_write(val, LOONGARCH_CSR_PRCFG2)
+#define read_csr_prcfg3() csr_read(LOONGARCH_CSR_PRCFG3)
+#define write_csr_prcfg3(val) csr_write(val, LOONGARCH_CSR_PRCFG3)
#define read_csr_stlbpgsize() csr_read32(LOONGARCH_CSR_STLBPGSIZE)
#define write_csr_stlbpgsize(val) csr_write32(val, LOONGARCH_CSR_STLBPGSIZE)
#define read_csr_rvacfg() csr_read32(LOONGARCH_CSR_RVACFG)
#define write_csr_rvacfg(val) csr_write32(val, LOONGARCH_CSR_RVACFG)
#define write_csr_tintclear(val) csr_write32(val, LOONGARCH_CSR_TINTCLR)
-#define read_csr_impctl1() csr_read64(LOONGARCH_CSR_IMPCTL1)
-#define write_csr_impctl1(val) csr_write64(val, LOONGARCH_CSR_IMPCTL1)
-#define write_csr_impctl2(val) csr_write64(val, LOONGARCH_CSR_IMPCTL2)
+#define read_csr_impctl1() csr_read(LOONGARCH_CSR_IMPCTL1)
+#define write_csr_impctl1(val) csr_write(val, LOONGARCH_CSR_IMPCTL1)
+#define write_csr_impctl2(val) csr_write(val, LOONGARCH_CSR_IMPCTL2)
#define read_csr_perfctrl0() csr_read64(LOONGARCH_CSR_PERFCTRL0)
#define read_csr_perfcntr0() csr_read64(LOONGARCH_CSR_PERFCNTR0)
@@ -1378,8 +1442,10 @@ __BUILD_CSR_OP(tlbidx)
#define ENTRYLO_C_SHIFT 4
#define ENTRYLO_C (_ULCAST_(3) << ENTRYLO_C_SHIFT)
#define ENTRYLO_G (_ULCAST_(1) << 6)
+#ifdef CONFIG_64BIT
#define ENTRYLO_NR (_ULCAST_(1) << 61)
#define ENTRYLO_NX (_ULCAST_(1) << 62)
+#endif
/* Values for PageSize register */
#define PS_4K 0x0000000c
diff --git a/arch/loongarch/include/asm/module.h b/arch/loongarch/include/asm/module.h
index f33f3fd32ecc..d56a968273de 100644
--- a/arch/loongarch/include/asm/module.h
+++ b/arch/loongarch/include/asm/module.h
@@ -38,8 +38,10 @@ struct got_entry {
struct plt_entry {
u32 inst_lu12iw;
+#ifdef CONFIG_64BIT
u32 inst_lu32id;
u32 inst_lu52id;
+#endif
u32 inst_jirl;
};
@@ -57,6 +59,14 @@ static inline struct got_entry emit_got_entry(Elf_Addr val)
static inline struct plt_entry emit_plt_entry(unsigned long val)
{
+#ifdef CONFIG_32BIT
+ u32 lu12iw, jirl;
+
+ lu12iw = larch_insn_gen_lu12iw(LOONGARCH_GPR_T1, ADDR_IMM(val, LU12IW));
+ jirl = larch_insn_gen_jirl(0, LOONGARCH_GPR_T1, ADDR_IMM(val, ORI));
+
+ return (struct plt_entry) { lu12iw, jirl };
+#else
u32 lu12iw, lu32id, lu52id, jirl;
lu12iw = larch_insn_gen_lu12iw(LOONGARCH_GPR_T1, ADDR_IMM(val, LU12IW));
@@ -65,6 +75,7 @@ static inline struct plt_entry emit_plt_entry(unsigned long val)
jirl = larch_insn_gen_jirl(0, LOONGARCH_GPR_T1, ADDR_IMM(val, ORI));
return (struct plt_entry) { lu12iw, lu32id, lu52id, jirl };
+#endif
}
static inline struct plt_idx_entry emit_plt_idx_entry(unsigned long val)
diff --git a/arch/loongarch/include/asm/page.h b/arch/loongarch/include/asm/page.h
index a3aaf34fba16..256d1ff7a1e3 100644
--- a/arch/loongarch/include/asm/page.h
+++ b/arch/loongarch/include/asm/page.h
@@ -10,7 +10,7 @@
#include <vdso/page.h>
-#define HPAGE_SHIFT (PAGE_SHIFT + PAGE_SHIFT - 3)
+#define HPAGE_SHIFT (PAGE_SHIFT + PAGE_SHIFT - PTRLOG)
#define HPAGE_SIZE (_AC(1, UL) << HPAGE_SHIFT)
#define HPAGE_MASK (~(HPAGE_SIZE - 1))
#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
diff --git a/arch/loongarch/include/asm/percpu.h b/arch/loongarch/include/asm/percpu.h
index 87be9b14e9da..583f2466262f 100644
--- a/arch/loongarch/include/asm/percpu.h
+++ b/arch/loongarch/include/asm/percpu.h
@@ -13,7 +13,7 @@
* the loading address of main kernel image, but far from where the modules are
* loaded. Tell the compiler this fact when using explicit relocs.
*/
-#if defined(MODULE) && defined(CONFIG_AS_HAS_EXPLICIT_RELOCS)
+#if defined(MODULE) && defined(CONFIG_AS_HAS_EXPLICIT_RELOCS) && defined(CONFIG_64BIT)
# if __has_attribute(model)
# define PER_CPU_ATTRIBUTES __attribute__((model("extreme")))
# else
@@ -27,7 +27,7 @@ register unsigned long __my_cpu_offset __asm__("$r21");
static inline void set_my_cpu_offset(unsigned long off)
{
__my_cpu_offset = off;
- csr_write64(off, PERCPU_BASE_KS);
+ csr_write(off, PERCPU_BASE_KS);
}
#define __my_cpu_offset \
@@ -36,6 +36,8 @@ static inline void set_my_cpu_offset(unsigned long off)
__my_cpu_offset; \
})
+#ifdef CONFIG_CPU_HAS_AMO
+
#define PERCPU_OP(op, asm_op, c_op) \
static __always_inline unsigned long __percpu_##op(void *ptr, \
unsigned long val, int size) \
@@ -68,25 +70,9 @@ PERCPU_OP(and, and, &)
PERCPU_OP(or, or, |)
#undef PERCPU_OP
-static __always_inline unsigned long __percpu_xchg(void *ptr, unsigned long val, int size)
-{
- switch (size) {
- case 1:
- case 2:
- return __xchg_small((volatile void *)ptr, val, size);
-
- case 4:
- return __xchg_asm("amswap.w", (volatile u32 *)ptr, (u32)val);
-
- case 8:
- return __xchg_asm("amswap.d", (volatile u64 *)ptr, (u64)val);
+#endif
- default:
- BUILD_BUG();
- }
-
- return 0;
-}
+#ifdef CONFIG_64BIT
#define __pcpu_op_1(op) op ".b "
#define __pcpu_op_2(op) op ".h "
@@ -115,6 +101,10 @@ do { \
: "memory"); \
} while (0)
+#endif
+
+#define __percpu_xchg __arch_xchg
+
/* this_cpu_cmpxchg */
#define _protect_cmpxchg_local(pcp, o, n) \
({ \
@@ -135,6 +125,8 @@ do { \
__retval; \
})
+#ifdef CONFIG_CPU_HAS_AMO
+
#define _percpu_add(pcp, val) \
_pcp_protect(__percpu_add, pcp, val)
@@ -146,9 +138,6 @@ do { \
#define _percpu_or(pcp, val) \
_pcp_protect(__percpu_or, pcp, val)
-#define _percpu_xchg(pcp, val) ((typeof(pcp)) \
- _pcp_protect(__percpu_xchg, pcp, (unsigned long)(val)))
-
#define this_cpu_add_4(pcp, val) _percpu_add(pcp, val)
#define this_cpu_add_8(pcp, val) _percpu_add(pcp, val)
@@ -161,6 +150,10 @@ do { \
#define this_cpu_or_4(pcp, val) _percpu_or(pcp, val)
#define this_cpu_or_8(pcp, val) _percpu_or(pcp, val)
+#endif
+
+#ifdef CONFIG_64BIT
+
#define this_cpu_read_1(pcp) _percpu_read(1, pcp)
#define this_cpu_read_2(pcp) _percpu_read(2, pcp)
#define this_cpu_read_4(pcp) _percpu_read(4, pcp)
@@ -171,6 +164,11 @@ do { \
#define this_cpu_write_4(pcp, val) _percpu_write(4, pcp, val)
#define this_cpu_write_8(pcp, val) _percpu_write(8, pcp, val)
+#endif
+
+#define _percpu_xchg(pcp, val) ((typeof(pcp)) \
+ _pcp_protect(__percpu_xchg, pcp, (unsigned long)(val)))
+
#define this_cpu_xchg_1(pcp, val) _percpu_xchg(pcp, val)
#define this_cpu_xchg_2(pcp, val) _percpu_xchg(pcp, val)
#define this_cpu_xchg_4(pcp, val) _percpu_xchg(pcp, val)
diff --git a/arch/loongarch/include/asm/pgtable-bits.h b/arch/loongarch/include/asm/pgtable-bits.h
index 2fc3789220ac..b565573cd82e 100644
--- a/arch/loongarch/include/asm/pgtable-bits.h
+++ b/arch/loongarch/include/asm/pgtable-bits.h
@@ -6,6 +6,26 @@
#define _ASM_PGTABLE_BITS_H
/* Page table bits */
+
+#ifdef CONFIG_32BIT
+#define _PAGE_VALID_SHIFT 0
+#define _PAGE_ACCESSED_SHIFT 0 /* Reuse Valid for Accessed */
+#define _PAGE_DIRTY_SHIFT 1
+#define _PAGE_PLV_SHIFT 2 /* 2~3, two bits */
+#define _CACHE_SHIFT 4 /* 4~5, two bits */
+#define _PAGE_GLOBAL_SHIFT 6
+#define _PAGE_HUGE_SHIFT 6 /* HUGE is a PMD bit */
+#define _PAGE_PRESENT_SHIFT 7
+#define _PAGE_PFN_SHIFT 8
+#define _PAGE_HGLOBAL_SHIFT 12 /* HGlobal is a PMD bit */
+#define _PAGE_SWP_EXCLUSIVE_SHIFT 13
+#define _PAGE_PFN_END_SHIFT 28
+#define _PAGE_WRITE_SHIFT 29
+#define _PAGE_MODIFIED_SHIFT 30
+#define _PAGE_PRESENT_INVALID_SHIFT 31
+#endif
+
+#ifdef CONFIG_64BIT
#define _PAGE_VALID_SHIFT 0
#define _PAGE_ACCESSED_SHIFT 0 /* Reuse Valid for Accessed */
#define _PAGE_DIRTY_SHIFT 1
@@ -18,14 +38,15 @@
#define _PAGE_MODIFIED_SHIFT 9
#define _PAGE_PROTNONE_SHIFT 10
#define _PAGE_SPECIAL_SHIFT 11
-#define _PAGE_HGLOBAL_SHIFT 12 /* HGlobal is a PMD bit */
#define _PAGE_PFN_SHIFT 12
+#define _PAGE_HGLOBAL_SHIFT 12 /* HGlobal is a PMD bit */
#define _PAGE_SWP_EXCLUSIVE_SHIFT 23
#define _PAGE_PFN_END_SHIFT 48
#define _PAGE_PRESENT_INVALID_SHIFT 60
#define _PAGE_NO_READ_SHIFT 61
#define _PAGE_NO_EXEC_SHIFT 62
#define _PAGE_RPLV_SHIFT 63
+#endif
/* Used by software */
#define _PAGE_PRESENT (_ULCAST_(1) << _PAGE_PRESENT_SHIFT)
@@ -33,10 +54,15 @@
#define _PAGE_WRITE (_ULCAST_(1) << _PAGE_WRITE_SHIFT)
#define _PAGE_ACCESSED (_ULCAST_(1) << _PAGE_ACCESSED_SHIFT)
#define _PAGE_MODIFIED (_ULCAST_(1) << _PAGE_MODIFIED_SHIFT)
+#ifdef CONFIG_32BIT
+#define _PAGE_PROTNONE 0
+#define _PAGE_SPECIAL 0
+#else
#define _PAGE_PROTNONE (_ULCAST_(1) << _PAGE_PROTNONE_SHIFT)
#define _PAGE_SPECIAL (_ULCAST_(1) << _PAGE_SPECIAL_SHIFT)
+#endif
-/* We borrow bit 23 to store the exclusive marker in swap PTEs. */
+/* We borrow bit 13/23 to store the exclusive marker in swap PTEs. */
#define _PAGE_SWP_EXCLUSIVE (_ULCAST_(1) << _PAGE_SWP_EXCLUSIVE_SHIFT)
/* Used by TLB hardware (placed in EntryLo*) */
@@ -46,9 +72,15 @@
#define _PAGE_GLOBAL (_ULCAST_(1) << _PAGE_GLOBAL_SHIFT)
#define _PAGE_HUGE (_ULCAST_(1) << _PAGE_HUGE_SHIFT)
#define _PAGE_HGLOBAL (_ULCAST_(1) << _PAGE_HGLOBAL_SHIFT)
+#ifdef CONFIG_32BIT
+#define _PAGE_NO_READ 0
+#define _PAGE_NO_EXEC 0
+#define _PAGE_RPLV 0
+#else
#define _PAGE_NO_READ (_ULCAST_(1) << _PAGE_NO_READ_SHIFT)
#define _PAGE_NO_EXEC (_ULCAST_(1) << _PAGE_NO_EXEC_SHIFT)
#define _PAGE_RPLV (_ULCAST_(1) << _PAGE_RPLV_SHIFT)
+#endif
#define _CACHE_MASK (_ULCAST_(3) << _CACHE_SHIFT)
#define PFN_PTE_SHIFT (PAGE_SHIFT - 12 + _PAGE_PFN_SHIFT)
diff --git a/arch/loongarch/include/asm/pgtable.h b/arch/loongarch/include/asm/pgtable.h
index 03fb60432fde..f41a648a3d9e 100644
--- a/arch/loongarch/include/asm/pgtable.h
+++ b/arch/loongarch/include/asm/pgtable.h
@@ -11,6 +11,7 @@
#include <linux/compiler.h>
#include <asm/addrspace.h>
+#include <asm/asm.h>
#include <asm/page.h>
#include <asm/pgtable-bits.h>
@@ -23,37 +24,45 @@
#endif
#if CONFIG_PGTABLE_LEVELS == 2
-#define PGDIR_SHIFT (PAGE_SHIFT + (PAGE_SHIFT - 3))
+#define PGDIR_SHIFT (PAGE_SHIFT + (PAGE_SHIFT - PTRLOG))
#elif CONFIG_PGTABLE_LEVELS == 3
-#define PMD_SHIFT (PAGE_SHIFT + (PAGE_SHIFT - 3))
+#define PMD_SHIFT (PAGE_SHIFT + (PAGE_SHIFT - PTRLOG))
#define PMD_SIZE (1UL << PMD_SHIFT)
#define PMD_MASK (~(PMD_SIZE-1))
-#define PGDIR_SHIFT (PMD_SHIFT + (PAGE_SHIFT - 3))
+#define PGDIR_SHIFT (PMD_SHIFT + (PAGE_SHIFT - PTRLOG))
#elif CONFIG_PGTABLE_LEVELS == 4
-#define PMD_SHIFT (PAGE_SHIFT + (PAGE_SHIFT - 3))
+#define PMD_SHIFT (PAGE_SHIFT + (PAGE_SHIFT - PTRLOG))
#define PMD_SIZE (1UL << PMD_SHIFT)
#define PMD_MASK (~(PMD_SIZE-1))
-#define PUD_SHIFT (PMD_SHIFT + (PAGE_SHIFT - 3))
+#define PUD_SHIFT (PMD_SHIFT + (PAGE_SHIFT - PTRLOG))
#define PUD_SIZE (1UL << PUD_SHIFT)
#define PUD_MASK (~(PUD_SIZE-1))
-#define PGDIR_SHIFT (PUD_SHIFT + (PAGE_SHIFT - 3))
+#define PGDIR_SHIFT (PUD_SHIFT + (PAGE_SHIFT - PTRLOG))
#endif
#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
#define PGDIR_MASK (~(PGDIR_SIZE-1))
-#define VA_BITS (PGDIR_SHIFT + (PAGE_SHIFT - 3))
+#ifdef CONFIG_32BIT
+#define VA_BITS 32
+#else
+#define VA_BITS (PGDIR_SHIFT + (PAGE_SHIFT - PTRLOG))
+#endif
-#define PTRS_PER_PGD (PAGE_SIZE >> 3)
+#define PTRS_PER_PGD (PAGE_SIZE >> PTRLOG)
#if CONFIG_PGTABLE_LEVELS > 3
-#define PTRS_PER_PUD (PAGE_SIZE >> 3)
+#define PTRS_PER_PUD (PAGE_SIZE >> PTRLOG)
#endif
#if CONFIG_PGTABLE_LEVELS > 2
-#define PTRS_PER_PMD (PAGE_SIZE >> 3)
+#define PTRS_PER_PMD (PAGE_SIZE >> PTRLOG)
#endif
-#define PTRS_PER_PTE (PAGE_SIZE >> 3)
+#define PTRS_PER_PTE (PAGE_SIZE >> PTRLOG)
+#ifdef CONFIG_32BIT
+#define USER_PTRS_PER_PGD (TASK_SIZE / PGDIR_SIZE)
+#else
#define USER_PTRS_PER_PGD ((TASK_SIZE64 / PGDIR_SIZE)?(TASK_SIZE64 / PGDIR_SIZE):1)
+#endif
#ifndef __ASSEMBLER__
@@ -74,11 +83,15 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
#define ZERO_PAGE(vaddr) virt_to_page(empty_zero_page)
-/*
- * TLB refill handlers may also map the vmalloc area into xkvrange.
- * Avoid the first couple of pages so NULL pointer dereferences will
- * still reliably trap.
- */
+#ifdef CONFIG_32BIT
+
+#define VMALLOC_START (vm_map_base + PCI_IOSIZE + (2 * PAGE_SIZE))
+#define VMALLOC_END (FIXADDR_START - (2 * PAGE_SIZE))
+
+#endif
+
+#ifdef CONFIG_64BIT
+
#define MODULES_VADDR (vm_map_base + PCI_IOSIZE + (2 * PAGE_SIZE))
#define MODULES_END (MODULES_VADDR + SZ_256M)
@@ -106,6 +119,8 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
#define KFENCE_AREA_START (VMEMMAP_END + 1)
#define KFENCE_AREA_END (KFENCE_AREA_START + KFENCE_AREA_SIZE - 1)
+#endif
+
#define ptep_get(ptep) READ_ONCE(*(ptep))
#define pmdp_get(pmdp) READ_ONCE(*(pmdp))
@@ -277,7 +292,16 @@ extern void kernel_pte_init(void *addr);
* Encode/decode swap entries and swap PTEs. Swap PTEs are all PTEs that
* are !pte_none() && !pte_present().
*
- * Format of swap PTEs:
+ * Format of 32bit swap PTEs:
+ *
+ * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * <------------ offset -------------> E <- type -> <-- zeroes -->
+ *
+ * E is the exclusive marker that is not stored in swap entries.
+ * The zero'ed bits include _PAGE_PRESENT.
+ *
+ * Format of 64bit swap PTEs:
*
* 6 6 6 6 5 5 5 5 5 5 5 5 5 5 4 4 4 4 4 4 4 4 4 4 3 3 3 3 3 3 3 3
* 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2
@@ -290,16 +314,27 @@ extern void kernel_pte_init(void *addr);
* E is the exclusive marker that is not stored in swap entries.
* The zero'ed bits include _PAGE_PRESENT and _PAGE_PROTNONE.
*/
+
+#define __SWP_TYPE_BITS (IS_ENABLED(CONFIG_32BIT) ? 5 : 7)
+#define __SWP_TYPE_MASK ((1UL << __SWP_TYPE_BITS) - 1)
+#define __SWP_TYPE_SHIFT (IS_ENABLED(CONFIG_32BIT) ? 8 : 16)
+#define __SWP_OFFSET_SHIFT (__SWP_TYPE_BITS + __SWP_TYPE_SHIFT + 1)
+
static inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
-{ pte_t pte; pte_val(pte) = ((type & 0x7f) << 16) | (offset << 24); return pte; }
+{
+ pte_t pte;
+ pte_val(pte) = ((type & __SWP_TYPE_MASK) << __SWP_TYPE_SHIFT) | (offset << __SWP_OFFSET_SHIFT);
+ return pte;
+}
-#define __swp_type(x) (((x).val >> 16) & 0x7f)
-#define __swp_offset(x) ((x).val >> 24)
+#define __swp_type(x) (((x).val >> __SWP_TYPE_SHIFT) & __SWP_TYPE_MASK)
+#define __swp_offset(x) ((x).val >> __SWP_OFFSET_SHIFT)
#define __swp_entry(type, offset) ((swp_entry_t) { pte_val(mk_swap_pte((type), (offset))) })
+
+#define __swp_entry_to_pte(x) __pte((x).val)
+#define __swp_entry_to_pmd(x) __pmd((x).val | _PAGE_HUGE)
#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
-#define __swp_entry_to_pte(x) ((pte_t) { (x).val })
#define __pmd_to_swp_entry(pmd) ((swp_entry_t) { pmd_val(pmd) })
-#define __swp_entry_to_pmd(x) ((pmd_t) { (x).val | _PAGE_HUGE })
static inline bool pte_swp_exclusive(pte_t pte)
{
diff --git a/arch/loongarch/include/asm/stackframe.h b/arch/loongarch/include/asm/stackframe.h
index 5cb568a60cf8..ecc8e50fffa8 100644
--- a/arch/loongarch/include/asm/stackframe.h
+++ b/arch/loongarch/include/asm/stackframe.h
@@ -38,22 +38,42 @@
cfi_restore \reg \offset \docfi
.endm
+ .macro SETUP_TWINS temp
+ pcaddi t0, 0
+ PTR_LI t1, ~TO_PHYS_MASK
+ and t0, t0, t1
+ ori t0, t0, (1 << 4 | 1)
+ csrwr t0, LOONGARCH_CSR_DMWIN0
+ PTR_LI t0, CSR_DMW1_INIT
+ csrwr t0, LOONGARCH_CSR_DMWIN1
+ .endm
+
+ .macro SETUP_MODES temp
+ /* Enable PG */
+ li.w \temp, 0xb0 # PLV=0, IE=0, PG=1
+ csrwr \temp, LOONGARCH_CSR_CRMD
+ li.w \temp, 0x04 # PLV=0, PIE=1, PWE=0
+ csrwr \temp, LOONGARCH_CSR_PRMD
+ li.w \temp, 0x00 # FPE=0, SXE=0, ASXE=0, BTE=0
+ csrwr \temp, LOONGARCH_CSR_EUEN
+ .endm
+
.macro SETUP_DMWINS temp
- li.d \temp, CSR_DMW0_INIT # WUC, PLV0, 0x8000 xxxx xxxx xxxx
+ PTR_LI \temp, CSR_DMW0_INIT # SUC, PLV0, LA32: 0x8xxx xxxx, LA64: 0x8000 xxxx xxxx xxxx
csrwr \temp, LOONGARCH_CSR_DMWIN0
- li.d \temp, CSR_DMW1_INIT # CAC, PLV0, 0x9000 xxxx xxxx xxxx
+ PTR_LI \temp, CSR_DMW1_INIT # CAC, PLV0, LA32: 0xaxxx xxxx, LA64: 0x9000 xxxx xxxx xxxx
csrwr \temp, LOONGARCH_CSR_DMWIN1
- li.d \temp, CSR_DMW2_INIT # WUC, PLV0, 0xa000 xxxx xxxx xxxx
+ PTR_LI \temp, CSR_DMW2_INIT # WUC, PLV0, LA32: unavailable, LA64: 0xa000 xxxx xxxx xxxx
csrwr \temp, LOONGARCH_CSR_DMWIN2
- li.d \temp, CSR_DMW3_INIT # 0x0, unused
+ PTR_LI \temp, CSR_DMW3_INIT # 0x0, unused
csrwr \temp, LOONGARCH_CSR_DMWIN3
.endm
/* Jump to the runtime virtual address. */
.macro JUMP_VIRT_ADDR temp1 temp2
- li.d \temp1, CACHE_BASE
+ PTR_LI \temp1, CACHE_BASE
pcaddi \temp2, 0
- bstrins.d \temp1, \temp2, (DMW_PABITS - 1), 0
+ PTR_BSTRINS \temp1, \temp2, (DMW_PABITS - 1), 0
jirl zero, \temp1, 0xc
.endm
@@ -171,7 +191,7 @@
andi t0, t0, 0x3 /* extract pplv bit */
beqz t0, 9f
- li.d tp, ~_THREAD_MASK
+ LONG_LI tp, ~_THREAD_MASK
and tp, tp, sp
cfi_st u0, PT_R21, \docfi
csrrd u0, PERCPU_BASE_KS
diff --git a/arch/loongarch/include/asm/string.h b/arch/loongarch/include/asm/string.h
index 5bb5a90d2681..bfa3fd879c7f 100644
--- a/arch/loongarch/include/asm/string.h
+++ b/arch/loongarch/include/asm/string.h
@@ -5,6 +5,7 @@
#ifndef _ASM_STRING_H
#define _ASM_STRING_H
+#ifdef CONFIG_64BIT
#define __HAVE_ARCH_MEMSET
extern void *memset(void *__s, int __c, size_t __count);
extern void *__memset(void *__s, int __c, size_t __count);
@@ -16,6 +17,7 @@ extern void *__memcpy(void *__to, __const__ void *__from, size_t __n);
#define __HAVE_ARCH_MEMMOVE
extern void *memmove(void *__dest, __const__ void *__src, size_t __n);
extern void *__memmove(void *__dest, __const__ void *__src, size_t __n);
+#endif
#if defined(CONFIG_KASAN) && !defined(__SANITIZE_ADDRESS__)
diff --git a/arch/loongarch/include/asm/timex.h b/arch/loongarch/include/asm/timex.h
index fb41e9e7a222..9ea52fad9690 100644
--- a/arch/loongarch/include/asm/timex.h
+++ b/arch/loongarch/include/asm/timex.h
@@ -18,7 +18,38 @@ typedef unsigned long cycles_t;
static inline cycles_t get_cycles(void)
{
- return drdtime();
+#ifdef CONFIG_32BIT
+ return rdtime_l();
+#else
+ return rdtime_d();
+#endif
+}
+
+#ifdef CONFIG_32BIT
+
+#define get_cycles_hi get_cycles_hi
+
+static inline cycles_t get_cycles_hi(void)
+{
+ return rdtime_h();
+}
+
+#endif
+
+static inline u64 get_cycles64(void)
+{
+#ifdef CONFIG_32BIT
+ u32 hi, lo;
+
+ do {
+ hi = rdtime_h();
+ lo = rdtime_l();
+ } while (hi != rdtime_h());
+
+ return ((u64)hi << 32) | lo;
+#else
+ return rdtime_d();
+#endif
}
#endif /* __KERNEL__ */
diff --git a/arch/loongarch/include/asm/uaccess.h b/arch/loongarch/include/asm/uaccess.h
index 0d22991ae430..4e259d490e45 100644
--- a/arch/loongarch/include/asm/uaccess.h
+++ b/arch/loongarch/include/asm/uaccess.h
@@ -19,10 +19,16 @@
#include <asm/asm-extable.h>
#include <asm-generic/access_ok.h>
+#define __LSW 0
+#define __MSW 1
+
extern u64 __ua_limit;
-#define __UA_ADDR ".dword"
+#ifdef CONFIG_64BIT
#define __UA_LIMIT __ua_limit
+#else
+#define __UA_LIMIT 0x80000000UL
+#endif
/*
* get_user: - Get a simple variable from user space.
@@ -126,6 +132,7 @@ extern u64 __ua_limit;
*
* Returns zero on success, or -EFAULT on error.
*/
+
#define __put_user(x, ptr) \
({ \
int __pu_err = 0; \
@@ -146,7 +153,7 @@ do { \
case 1: __get_data_asm(val, "ld.b", ptr); break; \
case 2: __get_data_asm(val, "ld.h", ptr); break; \
case 4: __get_data_asm(val, "ld.w", ptr); break; \
- case 8: __get_data_asm(val, "ld.d", ptr); break; \
+ case 8: __get_data_asm_8(val, ptr); break; \
default: BUILD_BUG(); break; \
} \
} while (0)
@@ -167,13 +174,39 @@ do { \
(val) = (__typeof__(*(ptr))) __gu_tmp; \
}
+#ifdef CONFIG_64BIT
+#define __get_data_asm_8(val, ptr) \
+ __get_data_asm(val, "ld.d", ptr)
+#else /* !CONFIG_64BIT */
+#define __get_data_asm_8(val, ptr) \
+{ \
+ u32 __lo, __hi; \
+ u32 __user *__ptr = (u32 __user *)(ptr); \
+ \
+ __asm__ __volatile__ ( \
+ "1:\n" \
+ " ld.w %1, %3 \n" \
+ "2:\n" \
+ " ld.w %2, %4 \n" \
+ "3:\n" \
+ _ASM_EXTABLE_UACCESS_ERR_ZERO(1b, 3b, %0, %1) \
+ _ASM_EXTABLE_UACCESS_ERR_ZERO(2b, 3b, %0, %1) \
+ : "+r" (__gu_err), "=&r" (__lo), "=r" (__hi) \
+ : "m" (__ptr[__LSW]), "m" (__ptr[__MSW])); \
+ if (__gu_err) \
+ __hi = 0; \
+ (val) = (__typeof__(val))((__typeof__((val)-(val))) \
+ ((((u64)__hi << 32) | __lo))); \
+}
+#endif /* CONFIG_64BIT */
+
#define __put_user_common(ptr, size) \
do { \
switch (size) { \
case 1: __put_data_asm("st.b", ptr); break; \
case 2: __put_data_asm("st.h", ptr); break; \
case 4: __put_data_asm("st.w", ptr); break; \
- case 8: __put_data_asm("st.d", ptr); break; \
+ case 8: __put_data_asm_8(ptr); break; \
default: BUILD_BUG(); break; \
} \
} while (0)
@@ -190,6 +223,30 @@ do { \
: "Jr" (__pu_val)); \
}
+#ifdef CONFIG_64BIT
+#define __put_data_asm_8(ptr) \
+ __put_data_asm("st.d", ptr)
+#else /* !CONFIG_64BIT */
+#define __put_data_asm_8(ptr) \
+{ \
+ u32 __user *__ptr = (u32 __user *)(ptr); \
+ u64 __x = (__typeof__((__pu_val)-(__pu_val)))(__pu_val); \
+ \
+ __asm__ __volatile__ ( \
+ "1:\n" \
+ " st.w %z3, %1 \n" \
+ "2:\n" \
+ " st.w %z4, %2 \n" \
+ "3:\n" \
+ _ASM_EXTABLE_UACCESS_ERR(1b, 3b, %0) \
+ _ASM_EXTABLE_UACCESS_ERR(2b, 3b, %0) \
+ : "+r" (__pu_err), \
+ "=m" (__ptr[__LSW]), \
+ "=m" (__ptr[__MSW]) \
+ : "rJ" (__x), "rJ" (__x >> 32)); \
+}
+#endif /* CONFIG_64BIT */
+
#define __get_kernel_nofault(dst, src, type, err_label) \
do { \
int __gu_err = 0; \
diff --git a/arch/loongarch/include/asm/vdso/gettimeofday.h b/arch/loongarch/include/asm/vdso/gettimeofday.h
index dcafabca9bb6..bae76767c693 100644
--- a/arch/loongarch/include/asm/vdso/gettimeofday.h
+++ b/arch/loongarch/include/asm/vdso/gettimeofday.h
@@ -12,6 +12,8 @@
#include <asm/unistd.h>
#include <asm/vdso/vdso.h>
+#ifdef CONFIG_GENERIC_GETTIMEOFDAY
+
#define VDSO_HAS_CLOCK_GETRES 1
static __always_inline long gettimeofday_fallback(
@@ -89,6 +91,8 @@ static inline bool loongarch_vdso_hres_capable(void)
}
#define __arch_vdso_hres_capable loongarch_vdso_hres_capable
+#endif /* CONFIG_GENERIC_GETTIMEOFDAY */
+
#endif /* !__ASSEMBLER__ */
#endif /* __ASM_VDSO_GETTIMEOFDAY_H */
diff --git a/arch/loongarch/include/uapi/asm/Kbuild b/arch/loongarch/include/uapi/asm/Kbuild
index 517761419999..89ac01faa5ae 100644
--- a/arch/loongarch/include/uapi/asm/Kbuild
+++ b/arch/loongarch/include/uapi/asm/Kbuild
@@ -1,2 +1,3 @@
# SPDX-License-Identifier: GPL-2.0
+syscall-y += unistd_32.h
syscall-y += unistd_64.h
diff --git a/arch/loongarch/include/uapi/asm/ptrace.h b/arch/loongarch/include/uapi/asm/ptrace.h
index 215e0f9e8aa3..b35c794323bc 100644
--- a/arch/loongarch/include/uapi/asm/ptrace.h
+++ b/arch/loongarch/include/uapi/asm/ptrace.h
@@ -61,8 +61,13 @@ struct user_lbt_state {
struct user_watch_state {
__u64 dbg_info;
struct {
+#if __BITS_PER_LONG == 32
+ __u32 addr;
+ __u32 mask;
+#else
__u64 addr;
__u64 mask;
+#endif
__u32 ctrl;
__u32 pad;
} dbg_regs[8];
@@ -71,8 +76,13 @@ struct user_watch_state {
struct user_watch_state_v2 {
__u64 dbg_info;
struct {
+#if __BITS_PER_LONG == 32
+ __u32 addr;
+ __u32 mask;
+#else
__u64 addr;
__u64 mask;
+#endif
__u32 ctrl;
__u32 pad;
} dbg_regs[14];
diff --git a/arch/loongarch/include/uapi/asm/unistd.h b/arch/loongarch/include/uapi/asm/unistd.h
index 1f01980f9c94..e19c7f2f9f87 100644
--- a/arch/loongarch/include/uapi/asm/unistd.h
+++ b/arch/loongarch/include/uapi/asm/unistd.h
@@ -1,3 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#include <asm/bitsperlong.h>
+
+#if __BITS_PER_LONG == 32
+#include <asm/unistd_32.h>
+#else
#include <asm/unistd_64.h>
+#endif
diff --git a/arch/loongarch/kernel/Makefile.syscalls b/arch/loongarch/kernel/Makefile.syscalls
index ab7d9baa2915..cd46c2b69c7f 100644
--- a/arch/loongarch/kernel/Makefile.syscalls
+++ b/arch/loongarch/kernel/Makefile.syscalls
@@ -1,4 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
# No special ABIs on loongarch so far
+syscall_abis_32 +=
syscall_abis_64 +=
diff --git a/arch/loongarch/kernel/cpu-probe.c b/arch/loongarch/kernel/cpu-probe.c
index a2060a24b39f..08a227034042 100644
--- a/arch/loongarch/kernel/cpu-probe.c
+++ b/arch/loongarch/kernel/cpu-probe.c
@@ -106,7 +106,11 @@ EXPORT_SYMBOL(vm_map_base);
static void cpu_probe_addrbits(struct cpuinfo_loongarch *c)
{
-#ifdef __NEED_ADDRBITS_PROBE
+#ifdef CONFIG_32BIT
+ c->pabits = cpu_pabits;
+ c->vabits = cpu_vabits;
+ vm_map_base = KVRANGE;
+#else
c->pabits = (read_cpucfg(LOONGARCH_CPUCFG1) & CPUCFG1_PABITS) >> 4;
c->vabits = (read_cpucfg(LOONGARCH_CPUCFG1) & CPUCFG1_VABITS) >> 12;
vm_map_base = 0UL - (1UL << c->vabits);
@@ -298,8 +302,15 @@ static inline void cpu_probe_loongson(struct cpuinfo_loongarch *c, unsigned int
return;
}
+#ifdef CONFIG_64BIT
*vendor = iocsr_read64(LOONGARCH_IOCSR_VENDOR);
*cpuname = iocsr_read64(LOONGARCH_IOCSR_CPUNAME);
+#else
+ *vendor = iocsr_read32(LOONGARCH_IOCSR_VENDOR) |
+ (u64)iocsr_read32(LOONGARCH_IOCSR_VENDOR + 4) << 32;
+ *cpuname = iocsr_read32(LOONGARCH_IOCSR_CPUNAME) |
+ (u64)iocsr_read32(LOONGARCH_IOCSR_CPUNAME + 4) << 32;
+#endif
if (!__cpu_full_name[cpu]) {
if (((char *)vendor)[0] == 0)
diff --git a/arch/loongarch/kernel/efi-header.S b/arch/loongarch/kernel/efi-header.S
index ba0bdbf86aa8..6df56241cb95 100644
--- a/arch/loongarch/kernel/efi-header.S
+++ b/arch/loongarch/kernel/efi-header.S
@@ -9,7 +9,11 @@
.macro __EFI_PE_HEADER
.long IMAGE_NT_SIGNATURE
.Lcoff_header:
+#ifdef CONFIG_32BIT
+ .short IMAGE_FILE_MACHINE_LOONGARCH32 /* Machine */
+#else
.short IMAGE_FILE_MACHINE_LOONGARCH64 /* Machine */
+#endif
.short .Lsection_count /* NumberOfSections */
.long 0 /* TimeDateStamp */
.long 0 /* PointerToSymbolTable */
diff --git a/arch/loongarch/kernel/efi.c b/arch/loongarch/kernel/efi.c
index 860a3bc030e0..52c21c895318 100644
--- a/arch/loongarch/kernel/efi.c
+++ b/arch/loongarch/kernel/efi.c
@@ -115,7 +115,9 @@ void __init efi_init(void)
efi_systab_report_header(&efi_systab->hdr, efi_systab->fw_vendor);
- set_bit(EFI_64BIT, &efi.flags);
+ if (IS_ENABLED(CONFIG_64BIT))
+ set_bit(EFI_64BIT, &efi.flags);
+
efi_nr_tables = efi_systab->nr_tables;
efi_config_table = (unsigned long)efi_systab->tables;
diff --git a/arch/loongarch/kernel/entry.S b/arch/loongarch/kernel/entry.S
index 47e1db9a1ce4..b53d333a7c42 100644
--- a/arch/loongarch/kernel/entry.S
+++ b/arch/loongarch/kernel/entry.S
@@ -23,24 +23,24 @@ SYM_CODE_START(handle_syscall)
UNWIND_HINT_UNDEFINED
csrrd t0, PERCPU_BASE_KS
la.pcrel t1, kernelsp
- add.d t1, t1, t0
+ PTR_ADD t1, t1, t0
move t2, sp
- ld.d sp, t1, 0
+ PTR_L sp, t1, 0
- addi.d sp, sp, -PT_SIZE
+ PTR_ADDI sp, sp, -PT_SIZE
cfi_st t2, PT_R3
cfi_rel_offset sp, PT_R3
- st.d zero, sp, PT_R0
+ LONG_S zero, sp, PT_R0
csrrd t2, LOONGARCH_CSR_PRMD
- st.d t2, sp, PT_PRMD
+ LONG_S t2, sp, PT_PRMD
csrrd t2, LOONGARCH_CSR_CRMD
- st.d t2, sp, PT_CRMD
+ LONG_S t2, sp, PT_CRMD
csrrd t2, LOONGARCH_CSR_EUEN
- st.d t2, sp, PT_EUEN
+ LONG_S t2, sp, PT_EUEN
csrrd t2, LOONGARCH_CSR_ECFG
- st.d t2, sp, PT_ECFG
+ LONG_S t2, sp, PT_ECFG
csrrd t2, LOONGARCH_CSR_ESTAT
- st.d t2, sp, PT_ESTAT
+ LONG_S t2, sp, PT_ESTAT
cfi_st ra, PT_R1
cfi_st a0, PT_R4
cfi_st a1, PT_R5
@@ -51,7 +51,7 @@ SYM_CODE_START(handle_syscall)
cfi_st a6, PT_R10
cfi_st a7, PT_R11
csrrd ra, LOONGARCH_CSR_ERA
- st.d ra, sp, PT_ERA
+ LONG_S ra, sp, PT_ERA
cfi_rel_offset ra, PT_ERA
cfi_st tp, PT_R2
@@ -67,7 +67,7 @@ SYM_CODE_START(handle_syscall)
#endif
move u0, t0
- li.d tp, ~_THREAD_MASK
+ LONG_LI tp, ~_THREAD_MASK
and tp, tp, sp
move a0, sp
diff --git a/arch/loongarch/kernel/env.c b/arch/loongarch/kernel/env.c
index 23bd5ae2212c..841206fde3ab 100644
--- a/arch/loongarch/kernel/env.c
+++ b/arch/loongarch/kernel/env.c
@@ -72,9 +72,12 @@ static int __init fdt_cpu_clk_init(void)
clk = of_clk_get(np, 0);
of_node_put(np);
+ cpu_clock_freq = 200 * 1000 * 1000;
- if (IS_ERR(clk))
+ if (IS_ERR(clk)) {
+ pr_warn("No valid CPU clock freq, assume 200MHz.\n");
return -ENODEV;
+ }
cpu_clock_freq = clk_get_rate(clk);
clk_put(clk);
diff --git a/arch/loongarch/kernel/fpu.S b/arch/loongarch/kernel/fpu.S
index 28caf416ae36..f225dcc5b530 100644
--- a/arch/loongarch/kernel/fpu.S
+++ b/arch/loongarch/kernel/fpu.S
@@ -96,6 +96,49 @@
EX fld.d $f31, \base, (31 * FPU_REG_WIDTH)
.endm
+#ifdef CONFIG_32BIT
+ .macro sc_save_fcc thread tmp0 tmp1
+ movcf2gr \tmp0, $fcc0
+ move \tmp1, \tmp0
+ movcf2gr \tmp0, $fcc1
+ bstrins.w \tmp1, \tmp0, 15, 8
+ movcf2gr \tmp0, $fcc2
+ bstrins.w \tmp1, \tmp0, 23, 16
+ movcf2gr \tmp0, $fcc3
+ bstrins.w \tmp1, \tmp0, 31, 24
+ EX st.w \tmp1, \thread, THREAD_FCC
+ movcf2gr \tmp0, $fcc4
+ move \tmp1, \tmp0
+ movcf2gr \tmp0, $fcc5
+ bstrins.w \tmp1, \tmp0, 15, 8
+ movcf2gr \tmp0, $fcc6
+ bstrins.w \tmp1, \tmp0, 23, 16
+ movcf2gr \tmp0, $fcc7
+ bstrins.w \tmp1, \tmp0, 31, 24
+ EX st.w \tmp1, \thread, (THREAD_FCC + 4)
+ .endm
+
+ .macro sc_restore_fcc thread tmp0 tmp1
+ EX ld.w \tmp0, \thread, THREAD_FCC
+ bstrpick.w \tmp1, \tmp0, 7, 0
+ movgr2cf $fcc0, \tmp1
+ bstrpick.w \tmp1, \tmp0, 15, 8
+ movgr2cf $fcc1, \tmp1
+ bstrpick.w \tmp1, \tmp0, 23, 16
+ movgr2cf $fcc2, \tmp1
+ bstrpick.w \tmp1, \tmp0, 31, 24
+ movgr2cf $fcc3, \tmp1
+ EX ld.w \tmp0, \thread, (THREAD_FCC + 4)
+ bstrpick.w \tmp1, \tmp0, 7, 0
+ movgr2cf $fcc4, \tmp1
+ bstrpick.w \tmp1, \tmp0, 15, 8
+ movgr2cf $fcc5, \tmp1
+ bstrpick.w \tmp1, \tmp0, 23, 16
+ movgr2cf $fcc6, \tmp1
+ bstrpick.w \tmp1, \tmp0, 31, 24
+ movgr2cf $fcc7, \tmp1
+ .endm
+#else
.macro sc_save_fcc base, tmp0, tmp1
movcf2gr \tmp0, $fcc0
move \tmp1, \tmp0
@@ -135,6 +178,7 @@
bstrpick.d \tmp1, \tmp0, 63, 56
movgr2cf $fcc7, \tmp1
.endm
+#endif
.macro sc_save_fcsr base, tmp0
movfcsr2gr \tmp0, fcsr0
@@ -410,6 +454,72 @@ SYM_FUNC_START(_init_fpu)
li.w t1, -1 # SNaN
+#ifdef CONFIG_32BIT
+ movgr2fr.w $f0, t1
+ movgr2frh.w $f0, t1
+ movgr2fr.w $f1, t1
+ movgr2frh.w $f1, t1
+ movgr2fr.w $f2, t1
+ movgr2frh.w $f2, t1
+ movgr2fr.w $f3, t1
+ movgr2frh.w $f3, t1
+ movgr2fr.w $f4, t1
+ movgr2frh.w $f4, t1
+ movgr2fr.w $f5, t1
+ movgr2frh.w $f5, t1
+ movgr2fr.w $f6, t1
+ movgr2frh.w $f6, t1
+ movgr2fr.w $f7, t1
+ movgr2frh.w $f7, t1
+ movgr2fr.w $f8, t1
+ movgr2frh.w $f8, t1
+ movgr2fr.w $f9, t1
+ movgr2frh.w $f9, t1
+ movgr2fr.w $f10, t1
+ movgr2frh.w $f10, t1
+ movgr2fr.w $f11, t1
+ movgr2frh.w $f11, t1
+ movgr2fr.w $f12, t1
+ movgr2frh.w $f12, t1
+ movgr2fr.w $f13, t1
+ movgr2frh.w $f13, t1
+ movgr2fr.w $f14, t1
+ movgr2frh.w $f14, t1
+ movgr2fr.w $f15, t1
+ movgr2frh.w $f15, t1
+ movgr2fr.w $f16, t1
+ movgr2frh.w $f16, t1
+ movgr2fr.w $f17, t1
+ movgr2frh.w $f17, t1
+ movgr2fr.w $f18, t1
+ movgr2frh.w $f18, t1
+ movgr2fr.w $f19, t1
+ movgr2frh.w $f19, t1
+ movgr2fr.w $f20, t1
+ movgr2frh.w $f20, t1
+ movgr2fr.w $f21, t1
+ movgr2frh.w $f21, t1
+ movgr2fr.w $f22, t1
+ movgr2frh.w $f22, t1
+ movgr2fr.w $f23, t1
+ movgr2frh.w $f23, t1
+ movgr2fr.w $f24, t1
+ movgr2frh.w $f24, t1
+ movgr2fr.w $f25, t1
+ movgr2frh.w $f25, t1
+ movgr2fr.w $f26, t1
+ movgr2frh.w $f26, t1
+ movgr2fr.w $f27, t1
+ movgr2frh.w $f27, t1
+ movgr2fr.w $f28, t1
+ movgr2frh.w $f28, t1
+ movgr2fr.w $f29, t1
+ movgr2frh.w $f29, t1
+ movgr2fr.w $f30, t1
+ movgr2frh.w $f30, t1
+ movgr2fr.w $f31, t1
+ movgr2frh.w $f31, t1
+#else
movgr2fr.d $f0, t1
movgr2fr.d $f1, t1
movgr2fr.d $f2, t1
@@ -442,6 +552,7 @@ SYM_FUNC_START(_init_fpu)
movgr2fr.d $f29, t1
movgr2fr.d $f30, t1
movgr2fr.d $f31, t1
+#endif
jr ra
SYM_FUNC_END(_init_fpu)
diff --git a/arch/loongarch/kernel/head.S b/arch/loongarch/kernel/head.S
index e3865e92a917..aba548db2446 100644
--- a/arch/loongarch/kernel/head.S
+++ b/arch/loongarch/kernel/head.S
@@ -43,36 +43,29 @@ SYM_DATA(kernel_fsize, .long _kernel_fsize);
SYM_CODE_START(kernel_entry) # kernel entry point
- /* Config direct window and set PG */
- SETUP_DMWINS t0
+ SETUP_TWINS
+ SETUP_MODES t0
JUMP_VIRT_ADDR t0, t1
-
- /* Enable PG */
- li.w t0, 0xb0 # PLV=0, IE=0, PG=1
- csrwr t0, LOONGARCH_CSR_CRMD
- li.w t0, 0x04 # PLV=0, PIE=1, PWE=0
- csrwr t0, LOONGARCH_CSR_PRMD
- li.w t0, 0x00 # FPE=0, SXE=0, ASXE=0, BTE=0
- csrwr t0, LOONGARCH_CSR_EUEN
+ SETUP_DMWINS t0
la.pcrel t0, __bss_start # clear .bss
- st.d zero, t0, 0
+ LONG_S zero, t0, 0
la.pcrel t1, __bss_stop - LONGSIZE
1:
- addi.d t0, t0, LONGSIZE
- st.d zero, t0, 0
+ PTR_ADDI t0, t0, LONGSIZE
+ LONG_S zero, t0, 0
bne t0, t1, 1b
la.pcrel t0, fw_arg0
- st.d a0, t0, 0 # firmware arguments
+ PTR_S a0, t0, 0 # firmware arguments
la.pcrel t0, fw_arg1
- st.d a1, t0, 0
+ PTR_S a1, t0, 0
la.pcrel t0, fw_arg2
- st.d a2, t0, 0
+ PTR_S a2, t0, 0
#ifdef CONFIG_PAGE_SIZE_4KB
- li.d t0, 0
- li.d t1, CSR_STFILL
+ LONG_LI t0, 0
+ LONG_LI t1, CSR_STFILL
csrxchg t0, t1, LOONGARCH_CSR_IMPCTL1
#endif
/* KSave3 used for percpu base, initialized as 0 */
@@ -98,7 +91,7 @@ SYM_CODE_START(kernel_entry) # kernel entry point
/* Jump to the new kernel: new_pc = current_pc + random_offset */
pcaddi t0, 0
- add.d t0, t0, a0
+ PTR_ADD t0, t0, a0
jirl zero, t0, 0xc
#endif /* CONFIG_RANDOMIZE_BASE */
@@ -121,12 +114,14 @@ SYM_CODE_END(kernel_entry)
*/
SYM_CODE_START(smpboot_entry)
- SETUP_DMWINS t0
+ SETUP_TWINS
+ SETUP_MODES t0
JUMP_VIRT_ADDR t0, t1
+ SETUP_DMWINS t0
#ifdef CONFIG_PAGE_SIZE_4KB
- li.d t0, 0
- li.d t1, CSR_STFILL
+ LONG_LI t0, 0
+ LONG_LI t1, CSR_STFILL
csrxchg t0, t1, LOONGARCH_CSR_IMPCTL1
#endif
/* Enable PG */
diff --git a/arch/loongarch/kernel/module-sections.c b/arch/loongarch/kernel/module-sections.c
index a43ba7f9f987..9fa1c9814fcc 100644
--- a/arch/loongarch/kernel/module-sections.c
+++ b/arch/loongarch/kernel/module-sections.c
@@ -93,6 +93,7 @@ static void count_max_entries(Elf_Rela *relas, int num,
(*plts)++;
break;
case R_LARCH_GOT_PC_HI20:
+ case R_LARCH_GOT_PCADD_HI20:
(*gots)++;
break;
default:
diff --git a/arch/loongarch/kernel/module.c b/arch/loongarch/kernel/module.c
index 36d6d9eeb7c7..7d4d571ee55e 100644
--- a/arch/loongarch/kernel/module.c
+++ b/arch/loongarch/kernel/module.c
@@ -22,72 +22,89 @@
#include <asm/inst.h>
#include <asm/unwind.h>
-static int rela_stack_push(s64 stack_value, s64 *rela_stack, size_t *rela_stack_top)
+/*
+ * reloc_rela_handler() - Apply a particular relocation to a module
+ * @mod: the module to apply the reloc to
+ * @location: the address at which the reloc is to be applied
+ * @v: the value of the reloc, with addend for RELA-style
+ * @rela_stack: the stack used for store relocation info, LOCAL to THIS module
+ * @rela_stac_top: where the stack operation(pop/push) applies to
+ *
+ * Return: 0 upon success, else -ERRNO
+ */
+typedef int (*reloc_rela_handler)(struct module *mod, u32 *location, Elf_Addr v,
+ long *rela_stack, size_t *rela_stack_top, unsigned int type);
+
+static int rela_stack_push(long stack_value, long *rela_stack, size_t *rela_stack_top)
{
if (*rela_stack_top >= RELA_STACK_DEPTH)
return -ENOEXEC;
rela_stack[(*rela_stack_top)++] = stack_value;
- pr_debug("%s stack_value = 0x%llx\n", __func__, stack_value);
+ pr_debug("%s stack_value = 0x%lx\n", __func__, stack_value);
return 0;
}
-static int rela_stack_pop(s64 *stack_value, s64 *rela_stack, size_t *rela_stack_top)
+static int rela_stack_pop(long *stack_value, long *rela_stack, size_t *rela_stack_top)
{
if (*rela_stack_top == 0)
return -ENOEXEC;
*stack_value = rela_stack[--(*rela_stack_top)];
- pr_debug("%s stack_value = 0x%llx\n", __func__, *stack_value);
+ pr_debug("%s stack_value = 0x%lx\n", __func__, *stack_value);
return 0;
}
static int apply_r_larch_none(struct module *mod, u32 *location, Elf_Addr v,
- s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
+ long *rela_stack, size_t *rela_stack_top, unsigned int type)
{
return 0;
}
static int apply_r_larch_error(struct module *me, u32 *location, Elf_Addr v,
- s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
+ long *rela_stack, size_t *rela_stack_top, unsigned int type)
{
pr_err("%s: Unsupport relocation type %u, please add its support.\n", me->name, type);
return -EINVAL;
}
static int apply_r_larch_32(struct module *mod, u32 *location, Elf_Addr v,
- s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
+ long *rela_stack, size_t *rela_stack_top, unsigned int type)
{
*location = v;
return 0;
}
+#ifdef CONFIG_32BIT
+#define apply_r_larch_64 apply_r_larch_error
+#else
static int apply_r_larch_64(struct module *mod, u32 *location, Elf_Addr v,
- s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
+ long *rela_stack, size_t *rela_stack_top, unsigned int type)
{
*(Elf_Addr *)location = v;
return 0;
}
+#endif
static int apply_r_larch_sop_push_pcrel(struct module *mod, u32 *location, Elf_Addr v,
- s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
+ long *rela_stack, size_t *rela_stack_top, unsigned int type)
{
- return rela_stack_push(v - (u64)location, rela_stack, rela_stack_top);
+ return rela_stack_push(v - (unsigned long)location, rela_stack, rela_stack_top);
}
static int apply_r_larch_sop_push_absolute(struct module *mod, u32 *location, Elf_Addr v,
- s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
+ long *rela_stack, size_t *rela_stack_top, unsigned int type)
{
return rela_stack_push(v, rela_stack, rela_stack_top);
}
static int apply_r_larch_sop_push_dup(struct module *mod, u32 *location, Elf_Addr v,
- s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
+ long *rela_stack, size_t *rela_stack_top, unsigned int type)
{
int err = 0;
- s64 opr1;
+ long opr1;
err = rela_stack_pop(&opr1, rela_stack, rela_stack_top);
if (err)
@@ -104,7 +121,7 @@ static int apply_r_larch_sop_push_dup(struct module *mod, u32 *location, Elf_Add
static int apply_r_larch_sop_push_plt_pcrel(struct module *mod,
Elf_Shdr *sechdrs, u32 *location, Elf_Addr v,
- s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
+ long *rela_stack, size_t *rela_stack_top, unsigned int type)
{
ptrdiff_t offset = (void *)v - (void *)location;
@@ -118,10 +135,10 @@ static int apply_r_larch_sop_push_plt_pcrel(struct module *mod,
}
static int apply_r_larch_sop(struct module *mod, u32 *location, Elf_Addr v,
- s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
+ long *rela_stack, size_t *rela_stack_top, unsigned int type)
{
int err = 0;
- s64 opr1, opr2, opr3;
+ long opr1, opr2, opr3;
if (type == R_LARCH_SOP_IF_ELSE) {
err = rela_stack_pop(&opr3, rela_stack, rela_stack_top);
@@ -164,10 +181,10 @@ static int apply_r_larch_sop(struct module *mod, u32 *location, Elf_Addr v,
}
static int apply_r_larch_sop_imm_field(struct module *mod, u32 *location, Elf_Addr v,
- s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
+ long *rela_stack, size_t *rela_stack_top, unsigned int type)
{
int err = 0;
- s64 opr1;
+ long opr1;
union loongarch_instruction *insn = (union loongarch_instruction *)location;
err = rela_stack_pop(&opr1, rela_stack, rela_stack_top);
@@ -244,31 +261,33 @@ static int apply_r_larch_sop_imm_field(struct module *mod, u32 *location, Elf_Ad
}
overflow:
- pr_err("module %s: opr1 = 0x%llx overflow! dangerous %s (%u) relocation\n",
+ pr_err("module %s: opr1 = 0x%lx overflow! dangerous %s (%u) relocation\n",
mod->name, opr1, __func__, type);
return -ENOEXEC;
unaligned:
- pr_err("module %s: opr1 = 0x%llx unaligned! dangerous %s (%u) relocation\n",
+ pr_err("module %s: opr1 = 0x%lx unaligned! dangerous %s (%u) relocation\n",
mod->name, opr1, __func__, type);
return -ENOEXEC;
}
static int apply_r_larch_add_sub(struct module *mod, u32 *location, Elf_Addr v,
- s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
+ long *rela_stack, size_t *rela_stack_top, unsigned int type)
{
switch (type) {
case R_LARCH_ADD32:
*(s32 *)location += v;
return 0;
- case R_LARCH_ADD64:
- *(s64 *)location += v;
- return 0;
case R_LARCH_SUB32:
*(s32 *)location -= v;
return 0;
+#ifdef CONFIG_64BIT
+ case R_LARCH_ADD64:
+ *(s64 *)location += v;
+ return 0;
case R_LARCH_SUB64:
*(s64 *)location -= v;
+#endif
return 0;
default:
pr_err("%s: Unsupport relocation type %u\n", mod->name, type);
@@ -278,7 +297,7 @@ static int apply_r_larch_add_sub(struct module *mod, u32 *location, Elf_Addr v,
static int apply_r_larch_b26(struct module *mod,
Elf_Shdr *sechdrs, u32 *location, Elf_Addr v,
- s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
+ long *rela_stack, size_t *rela_stack_top, unsigned int type)
{
ptrdiff_t offset = (void *)v - (void *)location;
union loongarch_instruction *insn = (union loongarch_instruction *)location;
@@ -310,15 +329,40 @@ static int apply_r_larch_b26(struct module *mod,
return 0;
}
+static int apply_r_larch_pcadd(struct module *mod, u32 *location, Elf_Addr v,
+ long *rela_stack, size_t *rela_stack_top, unsigned int type)
+{
+ union loongarch_instruction *insn = (union loongarch_instruction *)location;
+ /* Use s32 for a sign-extension deliberately. */
+ s32 offset_hi20 = (void *)((v + 0x800)) - (void *)((Elf_Addr)location);
+
+ switch (type) {
+ case R_LARCH_PCADD_LO12:
+ insn->reg2i12_format.immediate = v & 0xfff;
+ break;
+ case R_LARCH_PCADD_HI20:
+ v = offset_hi20 >> 12;
+ insn->reg1i20_format.immediate = v & 0xfffff;
+ break;
+ default:
+ pr_err("%s: Unsupport relocation type %u\n", mod->name, type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int apply_r_larch_pcala(struct module *mod, u32 *location, Elf_Addr v,
- s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
+ long *rela_stack, size_t *rela_stack_top, unsigned int type)
{
union loongarch_instruction *insn = (union loongarch_instruction *)location;
/* Use s32 for a sign-extension deliberately. */
s32 offset_hi20 = (void *)((v + 0x800) & ~0xfff) -
(void *)((Elf_Addr)location & ~0xfff);
+#ifdef CONFIG_64BIT
Elf_Addr anchor = (((Elf_Addr)location) & ~0xfff) + offset_hi20;
ptrdiff_t offset_rem = (void *)v - (void *)anchor;
+#endif
switch (type) {
case R_LARCH_PCALA_LO12:
@@ -328,6 +372,7 @@ static int apply_r_larch_pcala(struct module *mod, u32 *location, Elf_Addr v,
v = offset_hi20 >> 12;
insn->reg1i20_format.immediate = v & 0xfffff;
break;
+#ifdef CONFIG_64BIT
case R_LARCH_PCALA64_LO20:
v = offset_rem >> 32;
insn->reg1i20_format.immediate = v & 0xfffff;
@@ -336,6 +381,7 @@ static int apply_r_larch_pcala(struct module *mod, u32 *location, Elf_Addr v,
v = offset_rem >> 52;
insn->reg2i12_format.immediate = v & 0xfff;
break;
+#endif
default:
pr_err("%s: Unsupport relocation type %u\n", mod->name, type);
return -EINVAL;
@@ -346,30 +392,43 @@ static int apply_r_larch_pcala(struct module *mod, u32 *location, Elf_Addr v,
static int apply_r_larch_got_pc(struct module *mod,
Elf_Shdr *sechdrs, u32 *location, Elf_Addr v,
- s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
+ long *rela_stack, size_t *rela_stack_top, unsigned int type)
{
- Elf_Addr got = module_emit_got_entry(mod, sechdrs, v);
+ reloc_rela_handler got_handler;
- if (!got)
- return -EINVAL;
+ if (type != R_LARCH_GOT_PCADD_LO12) {
+ v = module_emit_got_entry(mod, sechdrs, v);
+ if (!v)
+ return -EINVAL;
+ }
switch (type) {
case R_LARCH_GOT_PC_LO12:
type = R_LARCH_PCALA_LO12;
+ got_handler = apply_r_larch_pcala;
break;
case R_LARCH_GOT_PC_HI20:
type = R_LARCH_PCALA_HI20;
+ got_handler = apply_r_larch_pcala;
+ break;
+ case R_LARCH_GOT_PCADD_LO12:
+ type = R_LARCH_PCADD_LO12;
+ got_handler = apply_r_larch_pcadd;
+ break;
+ case R_LARCH_GOT_PCADD_HI20:
+ type = R_LARCH_PCADD_HI20;
+ got_handler = apply_r_larch_pcadd;
break;
default:
pr_err("%s: Unsupport relocation type %u\n", mod->name, type);
return -EINVAL;
}
- return apply_r_larch_pcala(mod, location, got, rela_stack, rela_stack_top, type);
+ return got_handler(mod, location, v, rela_stack, rela_stack_top, type);
}
static int apply_r_larch_32_pcrel(struct module *mod, u32 *location, Elf_Addr v,
- s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
+ long *rela_stack, size_t *rela_stack_top, unsigned int type)
{
ptrdiff_t offset = (void *)v - (void *)location;
@@ -377,31 +436,22 @@ static int apply_r_larch_32_pcrel(struct module *mod, u32 *location, Elf_Addr v,
return 0;
}
+#ifdef CONFIG_32BIT
+#define apply_r_larch_64_pcrel apply_r_larch_error
+#else
static int apply_r_larch_64_pcrel(struct module *mod, u32 *location, Elf_Addr v,
- s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
+ long *rela_stack, size_t *rela_stack_top, unsigned int type)
{
ptrdiff_t offset = (void *)v - (void *)location;
*(u64 *)location = offset;
return 0;
}
-
-/*
- * reloc_handlers_rela() - Apply a particular relocation to a module
- * @mod: the module to apply the reloc to
- * @location: the address at which the reloc is to be applied
- * @v: the value of the reloc, with addend for RELA-style
- * @rela_stack: the stack used for store relocation info, LOCAL to THIS module
- * @rela_stac_top: where the stack operation(pop/push) applies to
- *
- * Return: 0 upon success, else -ERRNO
- */
-typedef int (*reloc_rela_handler)(struct module *mod, u32 *location, Elf_Addr v,
- s64 *rela_stack, size_t *rela_stack_top, unsigned int type);
+#endif
/* The handlers for known reloc types */
static reloc_rela_handler reloc_rela_handlers[] = {
- [R_LARCH_NONE ... R_LARCH_64_PCREL] = apply_r_larch_error,
+ [R_LARCH_NONE ... R_LARCH_TLS_DESC_PCADD_LO12] = apply_r_larch_error,
[R_LARCH_NONE] = apply_r_larch_none,
[R_LARCH_32] = apply_r_larch_32,
@@ -414,7 +464,8 @@ static reloc_rela_handler reloc_rela_handlers[] = {
[R_LARCH_SOP_SUB ... R_LARCH_SOP_IF_ELSE] = apply_r_larch_sop,
[R_LARCH_SOP_POP_32_S_10_5 ... R_LARCH_SOP_POP_32_U] = apply_r_larch_sop_imm_field,
[R_LARCH_ADD32 ... R_LARCH_SUB64] = apply_r_larch_add_sub,
- [R_LARCH_PCALA_HI20...R_LARCH_PCALA64_HI12] = apply_r_larch_pcala,
+ [R_LARCH_PCADD_HI20 ... R_LARCH_PCADD_LO12] = apply_r_larch_pcadd,
+ [R_LARCH_PCALA_HI20 ... R_LARCH_PCALA64_HI12] = apply_r_larch_pcala,
[R_LARCH_32_PCREL] = apply_r_larch_32_pcrel,
[R_LARCH_64_PCREL] = apply_r_larch_64_pcrel,
};
@@ -423,9 +474,10 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
unsigned int symindex, unsigned int relsec,
struct module *mod)
{
- int i, err;
- unsigned int type;
- s64 rela_stack[RELA_STACK_DEPTH];
+ int err;
+ unsigned int i, idx, type;
+ unsigned int num_relocations;
+ long rela_stack[RELA_STACK_DEPTH];
size_t rela_stack_top = 0;
reloc_rela_handler handler;
void *location;
@@ -436,8 +488,10 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
pr_debug("%s: Applying relocate section %u to %u\n", __func__, relsec,
sechdrs[relsec].sh_info);
+ idx = 0;
rela_stack_top = 0;
- for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
+ num_relocations = sechdrs[relsec].sh_size / sizeof(*rel);
+ for (i = 0; i < num_relocations; i++) {
/* This is where to make the change */
location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr + rel[i].r_offset;
/* This is the symbol it is referring to */
@@ -462,17 +516,59 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
return -EINVAL;
}
- pr_debug("type %d st_value %llx r_addend %llx loc %llx\n",
+ pr_debug("type %d st_value %lx r_addend %lx loc %lx\n",
(int)ELF_R_TYPE(rel[i].r_info),
- sym->st_value, rel[i].r_addend, (u64)location);
+ (unsigned long)sym->st_value, (unsigned long)rel[i].r_addend, (unsigned long)location);
v = sym->st_value + rel[i].r_addend;
+
+ if (type == R_LARCH_PCADD_LO12 || type == R_LARCH_GOT_PCADD_LO12) {
+ bool found = false;
+ unsigned int j = idx;
+
+ do {
+ u32 hi20_type = ELF_R_TYPE(rel[j].r_info);
+ unsigned long hi20_location =
+ sechdrs[sechdrs[relsec].sh_info].sh_addr + rel[j].r_offset;
+
+ /* Find the corresponding HI20 relocation entry */
+ if ((hi20_location == sym->st_value) && (hi20_type == type - 1)) {
+ s32 hi20, lo12;
+ Elf_Sym *hi20_sym =
+ (Elf_Sym *)sechdrs[symindex].sh_addr + ELF_R_SYM(rel[j].r_info);
+ unsigned long hi20_sym_val = hi20_sym->st_value + rel[j].r_addend;
+
+ /* Calculate LO12 offset */
+ size_t offset = hi20_sym_val - hi20_location;
+ if (hi20_type == R_LARCH_GOT_PCADD_HI20) {
+ offset = module_emit_got_entry(mod, sechdrs, hi20_sym_val);
+ offset = offset - hi20_location;
+ }
+ hi20 = (offset + 0x800) & 0xfffff000;
+ v = lo12 = offset - hi20;
+ found = true;
+ break;
+ }
+
+ j = (j + 1) % num_relocations;
+
+ } while (idx != j);
+
+ if (!found) {
+ pr_err("%s: Can not find HI20 relocation information\n", mod->name);
+ return -EINVAL;
+ }
+
+ idx = j; /* Record the previous j-loop end index */
+ }
+
switch (type) {
case R_LARCH_B26:
err = apply_r_larch_b26(mod, sechdrs, location,
v, rela_stack, &rela_stack_top, type);
break;
case R_LARCH_GOT_PC_HI20...R_LARCH_GOT_PC_LO12:
+ case R_LARCH_GOT_PCADD_HI20...R_LARCH_GOT_PCADD_LO12:
err = apply_r_larch_got_pc(mod, sechdrs, location,
v, rela_stack, &rela_stack_top, type);
break;
diff --git a/arch/loongarch/kernel/proc.c b/arch/loongarch/kernel/proc.c
index 63d2b7e7e844..a8800d20e11b 100644
--- a/arch/loongarch/kernel/proc.c
+++ b/arch/loongarch/kernel/proc.c
@@ -20,11 +20,14 @@ static int show_cpuinfo(struct seq_file *m, void *v)
unsigned int prid = cpu_data[n].processor_id;
unsigned int version = cpu_data[n].processor_id & 0xff;
unsigned int fp_version = cpu_data[n].fpu_vers;
+ u64 freq = cpu_clock_freq, bogomips = lpj_fine * cpu_clock_freq;
#ifdef CONFIG_SMP
if (!cpu_online(n))
return 0;
#endif
+ do_div(freq, 10000);
+ do_div(bogomips, const_clock_freq * (5000/HZ));
/*
* For the first processor also print the system type
@@ -41,11 +44,8 @@ static int show_cpuinfo(struct seq_file *m, void *v)
seq_printf(m, "PRID\t\t\t: %s (%08x)\n", id_to_core_name(prid), prid);
seq_printf(m, "CPU Revision\t\t: 0x%02x\n", version);
seq_printf(m, "FPU Revision\t\t: 0x%02x\n", fp_version);
- seq_printf(m, "CPU MHz\t\t\t: %llu.%02llu\n",
- cpu_clock_freq / 1000000, (cpu_clock_freq / 10000) % 100);
- seq_printf(m, "BogoMIPS\t\t: %llu.%02llu\n",
- (lpj_fine * cpu_clock_freq / const_clock_freq) / (500000/HZ),
- ((lpj_fine * cpu_clock_freq / const_clock_freq) / (5000/HZ)) % 100);
+ seq_printf(m, "CPU MHz\t\t\t: %u.%02u\n", (u32)freq / 100, (u32)freq % 100);
+ seq_printf(m, "BogoMIPS\t\t: %u.%02u\n", (u32)bogomips / 100, (u32)bogomips % 100);
seq_printf(m, "TLB Entries\t\t: %d\n", cpu_data[n].tlbsize);
seq_printf(m, "Address Sizes\t\t: %d bits physical, %d bits virtual\n",
cpu_pabits + 1, cpu_vabits + 1);
diff --git a/arch/loongarch/kernel/process.c b/arch/loongarch/kernel/process.c
index efd9edf65603..4ac1c3086152 100644
--- a/arch/loongarch/kernel/process.c
+++ b/arch/loongarch/kernel/process.c
@@ -130,6 +130,11 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
preempt_enable();
+ if (IS_ENABLED(CONFIG_RANDSTRUCT)) {
+ memcpy(dst, src, sizeof(struct task_struct));
+ return 0;
+ }
+
if (!used_math())
memcpy(dst, src, offsetof(struct task_struct, thread.fpu.fpr));
else
@@ -377,8 +382,11 @@ void arch_trigger_cpumask_backtrace(const cpumask_t *mask, int exclude_cpu)
nmi_trigger_cpumask_backtrace(mask, exclude_cpu, raise_backtrace);
}
-#ifdef CONFIG_64BIT
+#ifdef CONFIG_32BIT
+void loongarch_dump_regs32(u32 *uregs, const struct pt_regs *regs)
+#else
void loongarch_dump_regs64(u64 *uregs, const struct pt_regs *regs)
+#endif
{
unsigned int i;
@@ -395,4 +403,3 @@ void loongarch_dump_regs64(u64 *uregs, const struct pt_regs *regs)
uregs[LOONGARCH_EF_CSR_ECFG] = regs->csr_ecfg;
uregs[LOONGARCH_EF_CSR_ESTAT] = regs->csr_estat;
}
-#endif /* CONFIG_64BIT */
diff --git a/arch/loongarch/kernel/ptrace.c b/arch/loongarch/kernel/ptrace.c
index 8edd0954e55a..be38430f7e28 100644
--- a/arch/loongarch/kernel/ptrace.c
+++ b/arch/loongarch/kernel/ptrace.c
@@ -650,8 +650,13 @@ static int ptrace_hbp_set_addr(unsigned int note_type,
struct perf_event_attr attr;
/* Kernel-space address cannot be monitored by user-space */
+#ifdef CONFIG_32BIT
+ if ((unsigned long)addr >= KPRANGE0)
+ return -EINVAL;
+#else
if ((unsigned long)addr >= XKPRANGE)
return -EINVAL;
+#endif
bp = ptrace_hbp_get_initialised_bp(note_type, tsk, idx);
if (IS_ERR(bp))
diff --git a/arch/loongarch/kernel/relocate.c b/arch/loongarch/kernel/relocate.c
index b5e2312a2fca..82aa3f035927 100644
--- a/arch/loongarch/kernel/relocate.c
+++ b/arch/loongarch/kernel/relocate.c
@@ -68,18 +68,25 @@ static inline void __init relocate_absolute(long random_offset)
for (p = begin; (void *)p < end; p++) {
long v = p->symvalue;
- uint32_t lu12iw, ori, lu32id, lu52id;
+ uint32_t lu12iw, ori;
+#ifdef CONFIG_64BIT
+ uint32_t lu32id, lu52id;
+#endif
union loongarch_instruction *insn = (void *)p->pc;
lu12iw = (v >> 12) & 0xfffff;
ori = v & 0xfff;
+#ifdef CONFIG_64BIT
lu32id = (v >> 32) & 0xfffff;
lu52id = v >> 52;
+#endif
insn[0].reg1i20_format.immediate = lu12iw;
insn[1].reg2i12_format.immediate = ori;
+#ifdef CONFIG_64BIT
insn[2].reg1i20_format.immediate = lu32id;
insn[3].reg2i12_format.immediate = lu52id;
+#endif
}
}
@@ -183,7 +190,7 @@ static inline void __init *determine_relocation_address(void)
if (kaslr_disabled())
return destination;
- kernel_length = (long)_end - (long)_text;
+ kernel_length = (unsigned long)_end - (unsigned long)_text;
random_offset = get_random_boot() << 16;
random_offset &= (CONFIG_RANDOMIZE_BASE_MAX_OFFSET - 1);
@@ -232,7 +239,7 @@ unsigned long __init relocate_kernel(void)
early_memunmap(cmdline, COMMAND_LINE_SIZE);
if (random_offset) {
- kernel_length = (long)(_end) - (long)(_text);
+ kernel_length = (unsigned long)(_end) - (unsigned long)(_text);
/* Copy the kernel to it's new location */
memcpy(location_new, _text, kernel_length);
diff --git a/arch/loongarch/kernel/setup.c b/arch/loongarch/kernel/setup.c
index 25a87378e48e..20cb6f306456 100644
--- a/arch/loongarch/kernel/setup.c
+++ b/arch/loongarch/kernel/setup.c
@@ -56,6 +56,7 @@
#define SMBIOS_FREQLOW_MASK 0xFF
#define SMBIOS_CORE_PACKAGE_OFFSET 0x23
#define SMBIOS_THREAD_PACKAGE_OFFSET 0x25
+#define SMBIOS_THREAD_PACKAGE_2_OFFSET 0x2E
#define LOONGSON_EFI_ENABLE (1 << 3)
unsigned long fw_arg0, fw_arg1, fw_arg2;
@@ -126,7 +127,12 @@ static void __init parse_cpu_table(const struct dmi_header *dm)
cpu_clock_freq = freq_temp * 1000000;
loongson_sysconf.cpuname = (void *)dmi_string_parse(dm, dmi_data[16]);
- loongson_sysconf.cores_per_package = *(dmi_data + SMBIOS_THREAD_PACKAGE_OFFSET);
+ loongson_sysconf.cores_per_package = *(u8 *)(dmi_data + SMBIOS_THREAD_PACKAGE_OFFSET);
+ if (dm->length >= 0x30 && loongson_sysconf.cores_per_package == 0xff) {
+ /* SMBIOS 3.0+ has ThreadCount2 for more than 255 threads */
+ loongson_sysconf.cores_per_package =
+ *(u16 *)(dmi_data + SMBIOS_THREAD_PACKAGE_2_OFFSET);
+ }
pr_info("CpuClock = %llu\n", cpu_clock_freq);
}
diff --git a/arch/loongarch/kernel/switch.S b/arch/loongarch/kernel/switch.S
index 9c23cb7e432f..f377d8f5c51a 100644
--- a/arch/loongarch/kernel/switch.S
+++ b/arch/loongarch/kernel/switch.S
@@ -16,18 +16,23 @@
*/
.align 5
SYM_FUNC_START(__switch_to)
- csrrd t1, LOONGARCH_CSR_PRMD
- stptr.d t1, a0, THREAD_CSRPRMD
+#ifdef CONFIG_32BIT
+ PTR_ADDI a0, a0, TASK_STRUCT_OFFSET
+ PTR_ADDI a1, a1, TASK_STRUCT_OFFSET
+#endif
+ csrrd t1, LOONGARCH_CSR_PRMD
+ LONG_SPTR t1, a0, (THREAD_CSRPRMD - TASK_STRUCT_OFFSET)
cpu_save_nonscratch a0
- stptr.d ra, a0, THREAD_REG01
- stptr.d a3, a0, THREAD_SCHED_RA
- stptr.d a4, a0, THREAD_SCHED_CFA
+ LONG_SPTR a3, a0, (THREAD_SCHED_RA - TASK_STRUCT_OFFSET)
+ LONG_SPTR a4, a0, (THREAD_SCHED_CFA - TASK_STRUCT_OFFSET)
+
#if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_SMP)
- la t7, __stack_chk_guard
- LONG_L t8, a1, TASK_STACK_CANARY
- LONG_S t8, t7, 0
+ la t7, __stack_chk_guard
+ LONG_LPTR t8, a1, (TASK_STACK_CANARY - TASK_STRUCT_OFFSET)
+ LONG_SPTR t8, t7, 0
#endif
+
move tp, a2
cpu_restore_nonscratch a1
@@ -35,8 +40,11 @@ SYM_FUNC_START(__switch_to)
PTR_ADD t0, t0, tp
set_saved_sp t0, t1, t2
- ldptr.d t1, a1, THREAD_CSRPRMD
- csrwr t1, LOONGARCH_CSR_PRMD
+ LONG_LPTR t1, a1, (THREAD_CSRPRMD - TASK_STRUCT_OFFSET)
+ csrwr t1, LOONGARCH_CSR_PRMD
+#ifdef CONFIG_32BIT
+ PTR_ADDI a0, a0, -TASK_STRUCT_OFFSET
+#endif
jr ra
SYM_FUNC_END(__switch_to)
diff --git a/arch/loongarch/kernel/syscall.c b/arch/loongarch/kernel/syscall.c
index 168bd97540f8..1249d82c1cd0 100644
--- a/arch/loongarch/kernel/syscall.c
+++ b/arch/loongarch/kernel/syscall.c
@@ -34,9 +34,22 @@ SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len, unsigned long,
return ksys_mmap_pgoff(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
}
+SYSCALL_DEFINE6(mmap2, unsigned long, addr, unsigned long, len, unsigned long,
+ prot, unsigned long, flags, unsigned long, fd, unsigned long, offset)
+{
+ if (offset & (~PAGE_MASK >> 12))
+ return -EINVAL;
+
+ return ksys_mmap_pgoff(addr, len, prot, flags, fd, offset >> (PAGE_SHIFT - 12));
+}
+
void *sys_call_table[__NR_syscalls] = {
[0 ... __NR_syscalls - 1] = sys_ni_syscall,
+#ifdef CONFIG_32BIT
+#include <asm/syscall_table_32.h>
+#else
#include <asm/syscall_table_64.h>
+#endif
};
typedef long (*sys_call_fn)(unsigned long, unsigned long,
@@ -75,7 +88,7 @@ void noinstr __no_stack_protector do_syscall(struct pt_regs *regs)
*
* The resulting 6 bits of entropy is seen in SP[9:4].
*/
- choose_random_kstack_offset(drdtime());
+ choose_random_kstack_offset(get_cycles());
syscall_exit_to_user_mode(regs);
}
diff --git a/arch/loongarch/kernel/time.c b/arch/loongarch/kernel/time.c
index 6fb92cc1a4c9..dbaaabcaf6f0 100644
--- a/arch/loongarch/kernel/time.c
+++ b/arch/loongarch/kernel/time.c
@@ -18,6 +18,7 @@
#include <asm/loongarch.h>
#include <asm/paravirt.h>
#include <asm/time.h>
+#include <asm/timex.h>
u64 cpu_clock_freq;
EXPORT_SYMBOL(cpu_clock_freq);
@@ -50,10 +51,10 @@ static int constant_set_state_oneshot(struct clock_event_device *evt)
raw_spin_lock(&state_lock);
- timer_config = csr_read64(LOONGARCH_CSR_TCFG);
+ timer_config = csr_read(LOONGARCH_CSR_TCFG);
timer_config |= CSR_TCFG_EN;
timer_config &= ~CSR_TCFG_PERIOD;
- csr_write64(timer_config, LOONGARCH_CSR_TCFG);
+ csr_write(timer_config, LOONGARCH_CSR_TCFG);
raw_spin_unlock(&state_lock);
@@ -62,15 +63,15 @@ static int constant_set_state_oneshot(struct clock_event_device *evt)
static int constant_set_state_periodic(struct clock_event_device *evt)
{
- unsigned long period;
unsigned long timer_config;
+ u64 period = const_clock_freq;
raw_spin_lock(&state_lock);
- period = const_clock_freq / HZ;
+ do_div(period, HZ);
timer_config = period & CSR_TCFG_VAL;
timer_config |= (CSR_TCFG_PERIOD | CSR_TCFG_EN);
- csr_write64(timer_config, LOONGARCH_CSR_TCFG);
+ csr_write(timer_config, LOONGARCH_CSR_TCFG);
raw_spin_unlock(&state_lock);
@@ -83,9 +84,9 @@ static int constant_set_state_shutdown(struct clock_event_device *evt)
raw_spin_lock(&state_lock);
- timer_config = csr_read64(LOONGARCH_CSR_TCFG);
+ timer_config = csr_read(LOONGARCH_CSR_TCFG);
timer_config &= ~CSR_TCFG_EN;
- csr_write64(timer_config, LOONGARCH_CSR_TCFG);
+ csr_write(timer_config, LOONGARCH_CSR_TCFG);
raw_spin_unlock(&state_lock);
@@ -98,7 +99,7 @@ static int constant_timer_next_event(unsigned long delta, struct clock_event_dev
delta &= CSR_TCFG_VAL;
timer_config = delta | CSR_TCFG_EN;
- csr_write64(timer_config, LOONGARCH_CSR_TCFG);
+ csr_write(timer_config, LOONGARCH_CSR_TCFG);
return 0;
}
@@ -120,7 +121,7 @@ static int arch_timer_dying(unsigned int cpu)
static unsigned long get_loops_per_jiffy(void)
{
- unsigned long lpj = (unsigned long)const_clock_freq;
+ u64 lpj = const_clock_freq;
do_div(lpj, HZ);
@@ -131,13 +132,13 @@ static long init_offset;
void save_counter(void)
{
- init_offset = drdtime();
+ init_offset = get_cycles();
}
void sync_counter(void)
{
/* Ensure counter begin at 0 */
- csr_write64(init_offset, LOONGARCH_CSR_CNTC);
+ csr_write(init_offset, LOONGARCH_CSR_CNTC);
}
int constant_clockevent_init(void)
@@ -197,12 +198,12 @@ int constant_clockevent_init(void)
static u64 read_const_counter(struct clocksource *clk)
{
- return drdtime();
+ return get_cycles64();
}
static noinstr u64 sched_clock_read(void)
{
- return drdtime();
+ return get_cycles64();
}
static struct clocksource clocksource_const = {
@@ -211,7 +212,9 @@ static struct clocksource clocksource_const = {
.read = read_const_counter,
.mask = CLOCKSOURCE_MASK(64),
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
+#ifdef CONFIG_GENERIC_GETTIMEOFDAY
.vdso_clock_mode = VDSO_CLOCKMODE_CPU,
+#endif
};
int __init constant_clocksource_init(void)
@@ -235,7 +238,7 @@ void __init time_init(void)
else
const_clock_freq = calc_const_freq();
- init_offset = -(drdtime() - csr_read64(LOONGARCH_CSR_CNTC));
+ init_offset = -(get_cycles() - csr_read(LOONGARCH_CSR_CNTC));
constant_clockevent_init();
constant_clocksource_init();
diff --git a/arch/loongarch/kernel/traps.c b/arch/loongarch/kernel/traps.c
index da5926fead4a..004b8ebf0051 100644
--- a/arch/loongarch/kernel/traps.c
+++ b/arch/loongarch/kernel/traps.c
@@ -625,7 +625,7 @@ asmlinkage void noinstr do_bce(struct pt_regs *regs)
bool user = user_mode(regs);
bool pie = regs_irqs_disabled(regs);
unsigned long era = exception_era(regs);
- u64 badv = 0, lower = 0, upper = ULONG_MAX;
+ unsigned long badv = 0, lower = 0, upper = ULONG_MAX;
union loongarch_instruction insn;
irqentry_state_t state = irqentry_enter(regs);
@@ -1070,10 +1070,13 @@ asmlinkage void noinstr do_reserved(struct pt_regs *regs)
asmlinkage void cache_parity_error(void)
{
+ u32 merrctl = csr_read32(LOONGARCH_CSR_MERRCTL);
+ unsigned long merrera = csr_read(LOONGARCH_CSR_MERRERA);
+
/* For the moment, report the problem and hang. */
pr_err("Cache error exception:\n");
- pr_err("csr_merrctl == %08x\n", csr_read32(LOONGARCH_CSR_MERRCTL));
- pr_err("csr_merrera == %016lx\n", csr_read64(LOONGARCH_CSR_MERRERA));
+ pr_err("csr_merrctl == %08x\n", merrctl);
+ pr_err("csr_merrera == %016lx\n", merrera);
panic("Can't handle the cache error!");
}
@@ -1130,9 +1133,9 @@ static void configure_exception_vector(void)
eentry = (unsigned long)exception_handlers;
tlbrentry = (unsigned long)exception_handlers + 80*VECSIZE;
- csr_write64(eentry, LOONGARCH_CSR_EENTRY);
- csr_write64(__pa(eentry), LOONGARCH_CSR_MERRENTRY);
- csr_write64(__pa(tlbrentry), LOONGARCH_CSR_TLBRENTRY);
+ csr_write(eentry, LOONGARCH_CSR_EENTRY);
+ csr_write(__pa(eentry), LOONGARCH_CSR_MERRENTRY);
+ csr_write(__pa(tlbrentry), LOONGARCH_CSR_TLBRENTRY);
}
void per_cpu_trap_init(int cpu)
diff --git a/arch/loongarch/kernel/unaligned.c b/arch/loongarch/kernel/unaligned.c
index 487be604b96a..cc929c9fe7e9 100644
--- a/arch/loongarch/kernel/unaligned.c
+++ b/arch/loongarch/kernel/unaligned.c
@@ -27,12 +27,21 @@ static u32 unaligned_instructions_user;
static u32 unaligned_instructions_kernel;
#endif
-static inline unsigned long read_fpr(unsigned int idx)
+static inline u64 read_fpr(unsigned int idx)
{
+#ifdef CONFIG_64BIT
#define READ_FPR(idx, __value) \
__asm__ __volatile__("movfr2gr.d %0, $f"#idx"\n\t" : "=r"(__value));
-
- unsigned long __value;
+#else
+#define READ_FPR(idx, __value) \
+{ \
+ u32 __value_lo, __value_hi; \
+ __asm__ __volatile__("movfr2gr.s %0, $f"#idx"\n\t" : "=r"(__value_lo)); \
+ __asm__ __volatile__("movfrh2gr.s %0, $f"#idx"\n\t" : "=r"(__value_hi)); \
+ __value = (__value_lo | ((u64)__value_hi << 32)); \
+}
+#endif
+ u64 __value;
switch (idx) {
case 0:
@@ -138,11 +147,20 @@ static inline unsigned long read_fpr(unsigned int idx)
return __value;
}
-static inline void write_fpr(unsigned int idx, unsigned long value)
+static inline void write_fpr(unsigned int idx, u64 value)
{
+#ifdef CONFIG_64BIT
#define WRITE_FPR(idx, value) \
__asm__ __volatile__("movgr2fr.d $f"#idx", %0\n\t" :: "r"(value));
-
+#else
+#define WRITE_FPR(idx, value) \
+{ \
+ u32 value_lo = value; \
+ u32 value_hi = value >> 32; \
+ __asm__ __volatile__("movgr2fr.w $f"#idx", %0\n\t" :: "r"(value_lo)); \
+ __asm__ __volatile__("movgr2frh.w $f"#idx", %0\n\t" :: "r"(value_hi)); \
+}
+#endif
switch (idx) {
case 0:
WRITE_FPR(0, value);
@@ -252,7 +270,7 @@ void emulate_load_store_insn(struct pt_regs *regs, void __user *addr, unsigned i
bool sign, write;
bool user = user_mode(regs);
unsigned int res, size = 0;
- unsigned long value = 0;
+ u64 value = 0;
union loongarch_instruction insn;
perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0);
diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c
index 6d833599ef2e..656b954c1134 100644
--- a/arch/loongarch/kvm/vcpu.c
+++ b/arch/loongarch/kvm/vcpu.c
@@ -9,6 +9,7 @@
#include <asm/loongarch.h>
#include <asm/setup.h>
#include <asm/time.h>
+#include <asm/timex.h>
#define CREATE_TRACE_POINTS
#include "trace.h"
@@ -814,7 +815,7 @@ static int kvm_get_one_reg(struct kvm_vcpu *vcpu,
case KVM_REG_LOONGARCH_KVM:
switch (reg->id) {
case KVM_REG_LOONGARCH_COUNTER:
- *v = drdtime() + vcpu->kvm->arch.time_offset;
+ *v = get_cycles() + vcpu->kvm->arch.time_offset;
break;
case KVM_REG_LOONGARCH_DEBUG_INST:
*v = INSN_HVCL | KVM_HCALL_SWDBG;
@@ -909,7 +910,7 @@ static int kvm_set_one_reg(struct kvm_vcpu *vcpu,
* only set for the first time for smp system
*/
if (vcpu->vcpu_id == 0)
- vcpu->kvm->arch.time_offset = (signed long)(v - drdtime());
+ vcpu->kvm->arch.time_offset = (signed long)(v - get_cycles());
break;
case KVM_REG_LOONGARCH_VCPU_RESET:
vcpu->arch.st.guest_addr = 0;
diff --git a/arch/loongarch/lib/bswapdi.c b/arch/loongarch/lib/bswapdi.c
new file mode 100644
index 000000000000..88242dc7de17
--- /dev/null
+++ b/arch/loongarch/lib/bswapdi.c
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/export.h>
+#include <linux/compiler.h>
+#include <uapi/linux/swab.h>
+
+/* To silence -Wmissing-prototypes. */
+unsigned long long __bswapdi2(unsigned long long u);
+
+unsigned long long notrace __bswapdi2(unsigned long long u)
+{
+ return ___constant_swab64(u);
+}
+EXPORT_SYMBOL(__bswapdi2);
diff --git a/arch/loongarch/lib/bswapsi.c b/arch/loongarch/lib/bswapsi.c
new file mode 100644
index 000000000000..2ed655497de5
--- /dev/null
+++ b/arch/loongarch/lib/bswapsi.c
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/export.h>
+#include <linux/compiler.h>
+#include <uapi/linux/swab.h>
+
+/* To silence -Wmissing-prototypes. */
+unsigned int __bswapsi2(unsigned int u);
+
+unsigned int notrace __bswapsi2(unsigned int u)
+{
+ return ___constant_swab32(u);
+}
+EXPORT_SYMBOL(__bswapsi2);
diff --git a/arch/loongarch/lib/clear_user.S b/arch/loongarch/lib/clear_user.S
index 7a0db643b286..58c667dde882 100644
--- a/arch/loongarch/lib/clear_user.S
+++ b/arch/loongarch/lib/clear_user.S
@@ -13,11 +13,15 @@
#include <asm/unwind_hints.h>
SYM_FUNC_START(__clear_user)
+#ifdef CONFIG_32BIT
+ b __clear_user_generic
+#else
/*
* Some CPUs support hardware unaligned access
*/
ALTERNATIVE "b __clear_user_generic", \
"b __clear_user_fast", CPU_FEATURE_UAL
+#endif
SYM_FUNC_END(__clear_user)
EXPORT_SYMBOL(__clear_user)
@@ -29,19 +33,20 @@ EXPORT_SYMBOL(__clear_user)
* a1: size
*/
SYM_FUNC_START(__clear_user_generic)
- beqz a1, 2f
+ beqz a1, 2f
-1: st.b zero, a0, 0
- addi.d a0, a0, 1
- addi.d a1, a1, -1
- bgtz a1, 1b
+1: st.b zero, a0, 0
+ PTR_ADDI a0, a0, 1
+ PTR_ADDI a1, a1, -1
+ bgtz a1, 1b
-2: move a0, a1
- jr ra
+2: move a0, a1
+ jr ra
- _asm_extable 1b, 2b
+ _asm_extable 1b, 2b
SYM_FUNC_END(__clear_user_generic)
+#ifdef CONFIG_64BIT
/*
* unsigned long __clear_user_fast(void *addr, unsigned long size)
*
@@ -207,3 +212,4 @@ SYM_FUNC_START(__clear_user_fast)
SYM_FUNC_END(__clear_user_fast)
STACK_FRAME_NON_STANDARD __clear_user_fast
+#endif
diff --git a/arch/loongarch/lib/copy_user.S b/arch/loongarch/lib/copy_user.S
index 095ce9181c6c..c7264b779f6e 100644
--- a/arch/loongarch/lib/copy_user.S
+++ b/arch/loongarch/lib/copy_user.S
@@ -13,11 +13,15 @@
#include <asm/unwind_hints.h>
SYM_FUNC_START(__copy_user)
+#ifdef CONFIG_32BIT
+ b __copy_user_generic
+#else
/*
* Some CPUs support hardware unaligned access
*/
ALTERNATIVE "b __copy_user_generic", \
"b __copy_user_fast", CPU_FEATURE_UAL
+#endif
SYM_FUNC_END(__copy_user)
EXPORT_SYMBOL(__copy_user)
@@ -30,22 +34,23 @@ EXPORT_SYMBOL(__copy_user)
* a2: n
*/
SYM_FUNC_START(__copy_user_generic)
- beqz a2, 3f
+ beqz a2, 3f
-1: ld.b t0, a1, 0
-2: st.b t0, a0, 0
- addi.d a0, a0, 1
- addi.d a1, a1, 1
- addi.d a2, a2, -1
- bgtz a2, 1b
+1: ld.b t0, a1, 0
+2: st.b t0, a0, 0
+ PTR_ADDI a0, a0, 1
+ PTR_ADDI a1, a1, 1
+ PTR_ADDI a2, a2, -1
+ bgtz a2, 1b
-3: move a0, a2
- jr ra
+3: move a0, a2
+ jr ra
- _asm_extable 1b, 3b
- _asm_extable 2b, 3b
+ _asm_extable 1b, 3b
+ _asm_extable 2b, 3b
SYM_FUNC_END(__copy_user_generic)
+#ifdef CONFIG_64BIT
/*
* unsigned long __copy_user_fast(void *to, const void *from, unsigned long n)
*
@@ -281,3 +286,4 @@ SYM_FUNC_START(__copy_user_fast)
SYM_FUNC_END(__copy_user_fast)
STACK_FRAME_NON_STANDARD __copy_user_fast
+#endif
diff --git a/arch/loongarch/lib/dump_tlb.c b/arch/loongarch/lib/dump_tlb.c
index 0b886a6e260f..e1cdad7a676e 100644
--- a/arch/loongarch/lib/dump_tlb.c
+++ b/arch/loongarch/lib/dump_tlb.c
@@ -20,9 +20,9 @@ void dump_tlb_regs(void)
pr_info("Index : 0x%0x\n", read_csr_tlbidx());
pr_info("PageSize : 0x%0x\n", read_csr_pagesize());
- pr_info("EntryHi : 0x%0*lx\n", field, read_csr_entryhi());
- pr_info("EntryLo0 : 0x%0*lx\n", field, read_csr_entrylo0());
- pr_info("EntryLo1 : 0x%0*lx\n", field, read_csr_entrylo1());
+ pr_info("EntryHi : 0x%0*lx\n", field, (unsigned long)read_csr_entryhi());
+ pr_info("EntryLo0 : 0x%0*lx\n", field, (unsigned long)read_csr_entrylo0());
+ pr_info("EntryLo1 : 0x%0*lx\n", field, (unsigned long)read_csr_entrylo1());
}
static void dump_tlb(int first, int last)
@@ -73,12 +73,16 @@ static void dump_tlb(int first, int last)
vwidth, (entryhi & ~0x1fffUL), asidwidth, asid & asidmask);
/* NR/NX are in awkward places, so mask them off separately */
+#ifdef CONFIG_64BIT
pa = entrylo0 & ~(ENTRYLO_NR | ENTRYLO_NX);
+#endif
pa = pa & PAGE_MASK;
pr_cont("\n\t[");
+#ifdef CONFIG_64BIT
pr_cont("nr=%d nx=%d ",
(entrylo0 & ENTRYLO_NR) ? 1 : 0,
(entrylo0 & ENTRYLO_NX) ? 1 : 0);
+#endif
pr_cont("pa=0x%0*llx c=%d d=%d v=%d g=%d plv=%lld] [",
pwidth, pa, c0,
(entrylo0 & ENTRYLO_D) ? 1 : 0,
@@ -86,11 +90,15 @@ static void dump_tlb(int first, int last)
(entrylo0 & ENTRYLO_G) ? 1 : 0,
(entrylo0 & ENTRYLO_PLV) >> ENTRYLO_PLV_SHIFT);
/* NR/NX are in awkward places, so mask them off separately */
+#ifdef CONFIG_64BIT
pa = entrylo1 & ~(ENTRYLO_NR | ENTRYLO_NX);
+#endif
pa = pa & PAGE_MASK;
+#ifdef CONFIG_64BIT
pr_cont("nr=%d nx=%d ",
(entrylo1 & ENTRYLO_NR) ? 1 : 0,
(entrylo1 & ENTRYLO_NX) ? 1 : 0);
+#endif
pr_cont("pa=0x%0*llx c=%d d=%d v=%d g=%d plv=%lld]\n",
pwidth, pa, c1,
(entrylo1 & ENTRYLO_D) ? 1 : 0,
diff --git a/arch/loongarch/lib/unaligned.S b/arch/loongarch/lib/unaligned.S
index 185f82d85810..470c0bfa3463 100644
--- a/arch/loongarch/lib/unaligned.S
+++ b/arch/loongarch/lib/unaligned.S
@@ -24,35 +24,35 @@
* a3: sign
*/
SYM_FUNC_START(unaligned_read)
- beqz a2, 5f
+ beqz a2, 5f
- li.w t2, 0
- addi.d t0, a2, -1
- slli.d t1, t0, 3
- add.d a0, a0, t0
+ li.w t2, 0
+ LONG_ADDI t0, a2, -1
+ PTR_SLLI t1, t0, LONGLOG
+ PTR_ADD a0, a0, t0
- beqz a3, 2f
-1: ld.b t3, a0, 0
- b 3f
+ beqz a3, 2f
+1: ld.b t3, a0, 0
+ b 3f
-2: ld.bu t3, a0, 0
-3: sll.d t3, t3, t1
- or t2, t2, t3
- addi.d t1, t1, -8
- addi.d a0, a0, -1
- addi.d a2, a2, -1
- bgtz a2, 2b
-4: st.d t2, a1, 0
+2: ld.bu t3, a0, 0
+3: LONG_SLLV t3, t3, t1
+ or t2, t2, t3
+ LONG_ADDI t1, t1, -8
+ PTR_ADDI a0, a0, -1
+ PTR_ADDI a2, a2, -1
+ bgtz a2, 2b
+4: LONG_S t2, a1, 0
- move a0, a2
- jr ra
+ move a0, a2
+ jr ra
-5: li.w a0, -EFAULT
- jr ra
+5: li.w a0, -EFAULT
+ jr ra
- _asm_extable 1b, .L_fixup_handle_unaligned
- _asm_extable 2b, .L_fixup_handle_unaligned
- _asm_extable 4b, .L_fixup_handle_unaligned
+ _asm_extable 1b, .L_fixup_handle_unaligned
+ _asm_extable 2b, .L_fixup_handle_unaligned
+ _asm_extable 4b, .L_fixup_handle_unaligned
SYM_FUNC_END(unaligned_read)
/*
@@ -63,21 +63,21 @@ SYM_FUNC_END(unaligned_read)
* a2: n
*/
SYM_FUNC_START(unaligned_write)
- beqz a2, 3f
+ beqz a2, 3f
- li.w t0, 0
-1: srl.d t1, a1, t0
-2: st.b t1, a0, 0
- addi.d t0, t0, 8
- addi.d a2, a2, -1
- addi.d a0, a0, 1
- bgtz a2, 1b
+ li.w t0, 0
+1: LONG_SRLV t1, a1, t0
+2: st.b t1, a0, 0
+ LONG_ADDI t0, t0, 8
+ PTR_ADDI a2, a2, -1
+ PTR_ADDI a0, a0, 1
+ bgtz a2, 1b
- move a0, a2
- jr ra
+ move a0, a2
+ jr ra
-3: li.w a0, -EFAULT
- jr ra
+3: li.w a0, -EFAULT
+ jr ra
- _asm_extable 2b, .L_fixup_handle_unaligned
+ _asm_extable 2b, .L_fixup_handle_unaligned
SYM_FUNC_END(unaligned_write)
diff --git a/arch/loongarch/mm/init.c b/arch/loongarch/mm/init.c
index 6bfd4b8dad1b..0946662afdd6 100644
--- a/arch/loongarch/mm/init.c
+++ b/arch/loongarch/mm/init.c
@@ -224,7 +224,7 @@ EXPORT_SYMBOL(invalid_pmd_table);
pte_t invalid_pte_table[PTRS_PER_PTE] __page_aligned_bss;
EXPORT_SYMBOL(invalid_pte_table);
-#ifdef CONFIG_EXECMEM
+#if defined(CONFIG_EXECMEM) && defined(MODULES_VADDR)
static struct execmem_info execmem_info __ro_after_init;
struct execmem_info __init *execmem_arch_setup(void)
@@ -242,4 +242,4 @@ struct execmem_info __init *execmem_arch_setup(void)
return &execmem_info;
}
-#endif /* CONFIG_EXECMEM */
+#endif /* CONFIG_EXECMEM && MODULES_VADDR */
diff --git a/arch/loongarch/mm/page.S b/arch/loongarch/mm/page.S
index 7ad76551d313..7286b804756d 100644
--- a/arch/loongarch/mm/page.S
+++ b/arch/loongarch/mm/page.S
@@ -10,75 +10,75 @@
.align 5
SYM_FUNC_START(clear_page)
- lu12i.w t0, 1 << (PAGE_SHIFT - 12)
- add.d t0, t0, a0
+ lu12i.w t0, 1 << (PAGE_SHIFT - 12)
+ PTR_ADD t0, t0, a0
1:
- st.d zero, a0, 0
- st.d zero, a0, 8
- st.d zero, a0, 16
- st.d zero, a0, 24
- st.d zero, a0, 32
- st.d zero, a0, 40
- st.d zero, a0, 48
- st.d zero, a0, 56
- addi.d a0, a0, 128
- st.d zero, a0, -64
- st.d zero, a0, -56
- st.d zero, a0, -48
- st.d zero, a0, -40
- st.d zero, a0, -32
- st.d zero, a0, -24
- st.d zero, a0, -16
- st.d zero, a0, -8
- bne t0, a0, 1b
+ LONG_S zero, a0, (LONGSIZE * 0)
+ LONG_S zero, a0, (LONGSIZE * 1)
+ LONG_S zero, a0, (LONGSIZE * 2)
+ LONG_S zero, a0, (LONGSIZE * 3)
+ LONG_S zero, a0, (LONGSIZE * 4)
+ LONG_S zero, a0, (LONGSIZE * 5)
+ LONG_S zero, a0, (LONGSIZE * 6)
+ LONG_S zero, a0, (LONGSIZE * 7)
+ PTR_ADDI a0, a0, (LONGSIZE * 16)
+ LONG_S zero, a0, -(LONGSIZE * 8)
+ LONG_S zero, a0, -(LONGSIZE * 7)
+ LONG_S zero, a0, -(LONGSIZE * 6)
+ LONG_S zero, a0, -(LONGSIZE * 5)
+ LONG_S zero, a0, -(LONGSIZE * 4)
+ LONG_S zero, a0, -(LONGSIZE * 3)
+ LONG_S zero, a0, -(LONGSIZE * 2)
+ LONG_S zero, a0, -(LONGSIZE * 1)
+ bne t0, a0, 1b
- jr ra
+ jr ra
SYM_FUNC_END(clear_page)
EXPORT_SYMBOL(clear_page)
.align 5
SYM_FUNC_START(copy_page)
- lu12i.w t8, 1 << (PAGE_SHIFT - 12)
- add.d t8, t8, a0
+ lu12i.w t8, 1 << (PAGE_SHIFT - 12)
+ PTR_ADD t8, t8, a0
1:
- ld.d t0, a1, 0
- ld.d t1, a1, 8
- ld.d t2, a1, 16
- ld.d t3, a1, 24
- ld.d t4, a1, 32
- ld.d t5, a1, 40
- ld.d t6, a1, 48
- ld.d t7, a1, 56
+ LONG_L t0, a1, (LONGSIZE * 0)
+ LONG_L t1, a1, (LONGSIZE * 1)
+ LONG_L t2, a1, (LONGSIZE * 2)
+ LONG_L t3, a1, (LONGSIZE * 3)
+ LONG_L t4, a1, (LONGSIZE * 4)
+ LONG_L t5, a1, (LONGSIZE * 5)
+ LONG_L t6, a1, (LONGSIZE * 6)
+ LONG_L t7, a1, (LONGSIZE * 7)
- st.d t0, a0, 0
- st.d t1, a0, 8
- ld.d t0, a1, 64
- ld.d t1, a1, 72
- st.d t2, a0, 16
- st.d t3, a0, 24
- ld.d t2, a1, 80
- ld.d t3, a1, 88
- st.d t4, a0, 32
- st.d t5, a0, 40
- ld.d t4, a1, 96
- ld.d t5, a1, 104
- st.d t6, a0, 48
- st.d t7, a0, 56
- ld.d t6, a1, 112
- ld.d t7, a1, 120
- addi.d a0, a0, 128
- addi.d a1, a1, 128
+ LONG_S t0, a0, (LONGSIZE * 0)
+ LONG_S t1, a0, (LONGSIZE * 1)
+ LONG_L t0, a1, (LONGSIZE * 8)
+ LONG_L t1, a1, (LONGSIZE * 9)
+ LONG_S t2, a0, (LONGSIZE * 2)
+ LONG_S t3, a0, (LONGSIZE * 3)
+ LONG_L t2, a1, (LONGSIZE * 10)
+ LONG_L t3, a1, (LONGSIZE * 11)
+ LONG_S t4, a0, (LONGSIZE * 4)
+ LONG_S t5, a0, (LONGSIZE * 5)
+ LONG_L t4, a1, (LONGSIZE * 12)
+ LONG_L t5, a1, (LONGSIZE * 13)
+ LONG_S t6, a0, (LONGSIZE * 6)
+ LONG_S t7, a0, (LONGSIZE * 7)
+ LONG_L t6, a1, (LONGSIZE * 14)
+ LONG_L t7, a1, (LONGSIZE * 15)
+ PTR_ADDI a0, a0, (LONGSIZE * 16)
+ PTR_ADDI a1, a1, (LONGSIZE * 16)
- st.d t0, a0, -64
- st.d t1, a0, -56
- st.d t2, a0, -48
- st.d t3, a0, -40
- st.d t4, a0, -32
- st.d t5, a0, -24
- st.d t6, a0, -16
- st.d t7, a0, -8
+ LONG_S t0, a0, -(LONGSIZE * 8)
+ LONG_S t1, a0, -(LONGSIZE * 7)
+ LONG_S t2, a0, -(LONGSIZE * 6)
+ LONG_S t3, a0, -(LONGSIZE * 5)
+ LONG_S t4, a0, -(LONGSIZE * 4)
+ LONG_S t5, a0, -(LONGSIZE * 3)
+ LONG_S t6, a0, -(LONGSIZE * 2)
+ LONG_S t7, a0, -(LONGSIZE * 1)
- bne t8, a0, 1b
- jr ra
+ bne t8, a0, 1b
+ jr ra
SYM_FUNC_END(copy_page)
EXPORT_SYMBOL(copy_page)
diff --git a/arch/loongarch/mm/tlb.c b/arch/loongarch/mm/tlb.c
index 3b427b319db2..6a3c91b9cacd 100644
--- a/arch/loongarch/mm/tlb.c
+++ b/arch/loongarch/mm/tlb.c
@@ -229,11 +229,11 @@ static void setup_ptwalker(void)
if (cpu_has_ptw)
pwctl1 |= CSR_PWCTL1_PTW;
- csr_write64(pwctl0, LOONGARCH_CSR_PWCTL0);
- csr_write64(pwctl1, LOONGARCH_CSR_PWCTL1);
- csr_write64((long)swapper_pg_dir, LOONGARCH_CSR_PGDH);
- csr_write64((long)invalid_pg_dir, LOONGARCH_CSR_PGDL);
- csr_write64((long)smp_processor_id(), LOONGARCH_CSR_TMID);
+ csr_write(pwctl0, LOONGARCH_CSR_PWCTL0);
+ csr_write(pwctl1, LOONGARCH_CSR_PWCTL1);
+ csr_write((long)swapper_pg_dir, LOONGARCH_CSR_PGDH);
+ csr_write((long)invalid_pg_dir, LOONGARCH_CSR_PGDL);
+ csr_write((long)smp_processor_id(), LOONGARCH_CSR_TMID);
}
static void output_pgtable_bits_defines(void)
@@ -251,8 +251,10 @@ static void output_pgtable_bits_defines(void)
pr_define("_PAGE_GLOBAL_SHIFT %d\n", _PAGE_GLOBAL_SHIFT);
pr_define("_PAGE_PRESENT_SHIFT %d\n", _PAGE_PRESENT_SHIFT);
pr_define("_PAGE_WRITE_SHIFT %d\n", _PAGE_WRITE_SHIFT);
+#ifdef CONFIG_64BIT
pr_define("_PAGE_NO_READ_SHIFT %d\n", _PAGE_NO_READ_SHIFT);
pr_define("_PAGE_NO_EXEC_SHIFT %d\n", _PAGE_NO_EXEC_SHIFT);
+#endif
pr_define("PFN_PTE_SHIFT %d\n", PFN_PTE_SHIFT);
pr_debug("\n");
}
diff --git a/arch/loongarch/mm/tlbex.S b/arch/loongarch/mm/tlbex.S
index c08682a89c58..84a881a339a7 100644
--- a/arch/loongarch/mm/tlbex.S
+++ b/arch/loongarch/mm/tlbex.S
@@ -11,10 +11,18 @@
#define INVTLB_ADDR_GFALSE_AND_ASID 5
-#define PTRS_PER_PGD_BITS (PAGE_SHIFT - 3)
-#define PTRS_PER_PUD_BITS (PAGE_SHIFT - 3)
-#define PTRS_PER_PMD_BITS (PAGE_SHIFT - 3)
-#define PTRS_PER_PTE_BITS (PAGE_SHIFT - 3)
+#define PTRS_PER_PGD_BITS (PAGE_SHIFT - PTRLOG)
+#define PTRS_PER_PUD_BITS (PAGE_SHIFT - PTRLOG)
+#define PTRS_PER_PMD_BITS (PAGE_SHIFT - PTRLOG)
+#define PTRS_PER_PTE_BITS (PAGE_SHIFT - PTRLOG)
+
+#ifdef CONFIG_32BIT
+#define PTE_LL ll.w
+#define PTE_SC sc.w
+#else
+#define PTE_LL ll.d
+#define PTE_SC sc.d
+#endif
.macro tlb_do_page_fault, write
SYM_CODE_START(tlb_do_page_fault_\write)
@@ -60,52 +68,61 @@ SYM_CODE_START(handle_tlb_load)
vmalloc_done_load:
/* Get PGD offset in bytes */
- bstrpick.d ra, t0, PTRS_PER_PGD_BITS + PGDIR_SHIFT - 1, PGDIR_SHIFT
- alsl.d t1, ra, t1, 3
+#ifdef CONFIG_32BIT
+ PTR_BSTRPICK ra, t0, 31, PGDIR_SHIFT
+#else
+ PTR_BSTRPICK ra, t0, PTRS_PER_PGD_BITS + PGDIR_SHIFT - 1, PGDIR_SHIFT
+#endif
+ PTR_ALSL t1, ra, t1, _PGD_T_LOG2
+
#if CONFIG_PGTABLE_LEVELS > 3
- ld.d t1, t1, 0
- bstrpick.d ra, t0, PTRS_PER_PUD_BITS + PUD_SHIFT - 1, PUD_SHIFT
- alsl.d t1, ra, t1, 3
+ PTR_L t1, t1, 0
+ PTR_BSTRPICK ra, t0, PTRS_PER_PUD_BITS + PUD_SHIFT - 1, PUD_SHIFT
+ PTR_ALSL t1, ra, t1, _PMD_T_LOG2
+
#endif
#if CONFIG_PGTABLE_LEVELS > 2
- ld.d t1, t1, 0
- bstrpick.d ra, t0, PTRS_PER_PMD_BITS + PMD_SHIFT - 1, PMD_SHIFT
- alsl.d t1, ra, t1, 3
+ PTR_L t1, t1, 0
+ PTR_BSTRPICK ra, t0, PTRS_PER_PMD_BITS + PMD_SHIFT - 1, PMD_SHIFT
+ PTR_ALSL t1, ra, t1, _PMD_T_LOG2
+
#endif
- ld.d ra, t1, 0
+ PTR_L ra, t1, 0
/*
* For huge tlb entries, pmde doesn't contain an address but
* instead contains the tlb pte. Check the PAGE_HUGE bit and
* see if we need to jump to huge tlb processing.
*/
- rotri.d ra, ra, _PAGE_HUGE_SHIFT + 1
+ PTR_ROTRI ra, ra, _PAGE_HUGE_SHIFT + 1
bltz ra, tlb_huge_update_load
- rotri.d ra, ra, 64 - (_PAGE_HUGE_SHIFT + 1)
- bstrpick.d t0, t0, PTRS_PER_PTE_BITS + PAGE_SHIFT - 1, PAGE_SHIFT
- alsl.d t1, t0, ra, _PTE_T_LOG2
+ PTR_ROTRI ra, ra, BITS_PER_LONG - (_PAGE_HUGE_SHIFT + 1)
+ PTR_BSTRPICK t0, t0, PTRS_PER_PTE_BITS + PAGE_SHIFT - 1, PAGE_SHIFT
+ PTR_ALSL t1, t0, ra, _PTE_T_LOG2
#ifdef CONFIG_SMP
smp_pgtable_change_load:
- ll.d t0, t1, 0
+ PTE_LL t0, t1, 0
#else
- ld.d t0, t1, 0
+ PTR_L t0, t1, 0
#endif
andi ra, t0, _PAGE_PRESENT
beqz ra, nopage_tlb_load
ori t0, t0, _PAGE_VALID
+
#ifdef CONFIG_SMP
- sc.d t0, t1, 0
+ PTE_SC t0, t1, 0
beqz t0, smp_pgtable_change_load
#else
- st.d t0, t1, 0
+ PTR_S t0, t1, 0
#endif
+
tlbsrch
- bstrins.d t1, zero, 3, 3
- ld.d t0, t1, 0
- ld.d t1, t1, 8
+ PTR_BSTRINS t1, zero, _PTE_T_LOG2, _PTE_T_LOG2
+ PTR_L t0, t1, 0
+ PTR_L t1, t1, _PTE_T_SIZE
csrwr t0, LOONGARCH_CSR_TLBELO0
csrwr t1, LOONGARCH_CSR_TLBELO1
tlbwr
@@ -115,30 +132,28 @@ smp_pgtable_change_load:
csrrd ra, EXCEPTION_KS2
ertn
-#ifdef CONFIG_64BIT
vmalloc_load:
la_abs t1, swapper_pg_dir
b vmalloc_done_load
-#endif
/* This is the entry point of a huge page. */
tlb_huge_update_load:
#ifdef CONFIG_SMP
- ll.d ra, t1, 0
+ PTE_LL ra, t1, 0
#else
- rotri.d ra, ra, 64 - (_PAGE_HUGE_SHIFT + 1)
+ PTR_ROTRI ra, ra, BITS_PER_LONG - (_PAGE_HUGE_SHIFT + 1)
#endif
andi t0, ra, _PAGE_PRESENT
beqz t0, nopage_tlb_load
#ifdef CONFIG_SMP
ori t0, ra, _PAGE_VALID
- sc.d t0, t1, 0
+ PTE_SC t0, t1, 0
beqz t0, tlb_huge_update_load
ori t0, ra, _PAGE_VALID
#else
ori t0, ra, _PAGE_VALID
- st.d t0, t1, 0
+ PTR_S t0, t1, 0
#endif
csrrd ra, LOONGARCH_CSR_ASID
csrrd t1, LOONGARCH_CSR_BADV
@@ -158,27 +173,27 @@ tlb_huge_update_load:
xori t0, t0, _PAGE_HUGE
lu12i.w t1, _PAGE_HGLOBAL >> 12
and t1, t0, t1
- srli.d t1, t1, (_PAGE_HGLOBAL_SHIFT - _PAGE_GLOBAL_SHIFT)
+ PTR_SRLI t1, t1, (_PAGE_HGLOBAL_SHIFT - _PAGE_GLOBAL_SHIFT)
or t0, t0, t1
move ra, t0
csrwr ra, LOONGARCH_CSR_TLBELO0
/* Convert to entrylo1 */
- addi.d t1, zero, 1
- slli.d t1, t1, (HPAGE_SHIFT - 1)
- add.d t0, t0, t1
+ PTR_ADDI t1, zero, 1
+ PTR_SLLI t1, t1, (HPAGE_SHIFT - 1)
+ PTR_ADD t0, t0, t1
csrwr t0, LOONGARCH_CSR_TLBELO1
/* Set huge page tlb entry size */
- addu16i.d t0, zero, (CSR_TLBIDX_PS >> 16)
- addu16i.d t1, zero, (PS_HUGE_SIZE << (CSR_TLBIDX_PS_SHIFT - 16))
+ PTR_LI t0, (CSR_TLBIDX_PS >> 16) << 16
+ PTR_LI t1, (PS_HUGE_SIZE << (CSR_TLBIDX_PS_SHIFT))
csrxchg t1, t0, LOONGARCH_CSR_TLBIDX
tlbfill
- addu16i.d t0, zero, (CSR_TLBIDX_PS >> 16)
- addu16i.d t1, zero, (PS_DEFAULT_SIZE << (CSR_TLBIDX_PS_SHIFT - 16))
+ PTR_LI t0, (CSR_TLBIDX_PS >> 16) << 16
+ PTR_LI t1, (PS_DEFAULT_SIZE << (CSR_TLBIDX_PS_SHIFT))
csrxchg t1, t0, LOONGARCH_CSR_TLBIDX
csrrd t0, EXCEPTION_KS0
@@ -216,53 +231,71 @@ SYM_CODE_START(handle_tlb_store)
vmalloc_done_store:
/* Get PGD offset in bytes */
- bstrpick.d ra, t0, PTRS_PER_PGD_BITS + PGDIR_SHIFT - 1, PGDIR_SHIFT
- alsl.d t1, ra, t1, 3
+#ifdef CONFIG_32BIT
+ PTR_BSTRPICK ra, t0, 31, PGDIR_SHIFT
+#else
+ PTR_BSTRPICK ra, t0, PTRS_PER_PGD_BITS + PGDIR_SHIFT - 1, PGDIR_SHIFT
+#endif
+ PTR_ALSL t1, ra, t1, _PGD_T_LOG2
+
#if CONFIG_PGTABLE_LEVELS > 3
- ld.d t1, t1, 0
- bstrpick.d ra, t0, PTRS_PER_PUD_BITS + PUD_SHIFT - 1, PUD_SHIFT
- alsl.d t1, ra, t1, 3
+ PTR_L t1, t1, 0
+ PTR_BSTRPICK ra, t0, PTRS_PER_PUD_BITS + PUD_SHIFT - 1, PUD_SHIFT
+ PTR_ALSL t1, ra, t1, _PMD_T_LOG2
#endif
#if CONFIG_PGTABLE_LEVELS > 2
- ld.d t1, t1, 0
- bstrpick.d ra, t0, PTRS_PER_PMD_BITS + PMD_SHIFT - 1, PMD_SHIFT
- alsl.d t1, ra, t1, 3
+ PTR_L t1, t1, 0
+ PTR_BSTRPICK ra, t0, PTRS_PER_PMD_BITS + PMD_SHIFT - 1, PMD_SHIFT
+ PTR_ALSL t1, ra, t1, _PMD_T_LOG2
#endif
- ld.d ra, t1, 0
+ PTR_L ra, t1, 0
/*
* For huge tlb entries, pmde doesn't contain an address but
* instead contains the tlb pte. Check the PAGE_HUGE bit and
* see if we need to jump to huge tlb processing.
*/
- rotri.d ra, ra, _PAGE_HUGE_SHIFT + 1
+ PTR_ROTRI ra, ra, _PAGE_HUGE_SHIFT + 1
bltz ra, tlb_huge_update_store
- rotri.d ra, ra, 64 - (_PAGE_HUGE_SHIFT + 1)
- bstrpick.d t0, t0, PTRS_PER_PTE_BITS + PAGE_SHIFT - 1, PAGE_SHIFT
- alsl.d t1, t0, ra, _PTE_T_LOG2
+ PTR_ROTRI ra, ra, BITS_PER_LONG - (_PAGE_HUGE_SHIFT + 1)
+ PTR_BSTRPICK t0, t0, PTRS_PER_PTE_BITS + PAGE_SHIFT - 1, PAGE_SHIFT
+ PTR_ALSL t1, t0, ra, _PTE_T_LOG2
#ifdef CONFIG_SMP
smp_pgtable_change_store:
- ll.d t0, t1, 0
+ PTE_LL t0, t1, 0
#else
- ld.d t0, t1, 0
+ PTR_L t0, t1, 0
#endif
+
+#ifdef CONFIG_64BIT
andi ra, t0, _PAGE_PRESENT | _PAGE_WRITE
xori ra, ra, _PAGE_PRESENT | _PAGE_WRITE
+#else
+ PTR_LI ra, _PAGE_PRESENT | _PAGE_WRITE
+ and ra, ra, t0
+ nor ra, ra, zero
+#endif
bnez ra, nopage_tlb_store
+#ifdef CONFIG_64BIT
ori t0, t0, (_PAGE_VALID | _PAGE_DIRTY | _PAGE_MODIFIED)
+#else
+ PTR_LI ra, (_PAGE_VALID | _PAGE_DIRTY | _PAGE_MODIFIED)
+ or t0, ra, t0
+#endif
+
#ifdef CONFIG_SMP
- sc.d t0, t1, 0
+ PTE_SC t0, t1, 0
beqz t0, smp_pgtable_change_store
#else
- st.d t0, t1, 0
+ PTR_S t0, t1, 0
#endif
tlbsrch
- bstrins.d t1, zero, 3, 3
- ld.d t0, t1, 0
- ld.d t1, t1, 8
+ PTR_BSTRINS t1, zero, _PTE_T_LOG2, _PTE_T_LOG2
+ PTR_L t0, t1, 0
+ PTR_L t1, t1, _PTE_T_SIZE
csrwr t0, LOONGARCH_CSR_TLBELO0
csrwr t1, LOONGARCH_CSR_TLBELO1
tlbwr
@@ -272,31 +305,42 @@ smp_pgtable_change_store:
csrrd ra, EXCEPTION_KS2
ertn
-#ifdef CONFIG_64BIT
vmalloc_store:
la_abs t1, swapper_pg_dir
b vmalloc_done_store
-#endif
/* This is the entry point of a huge page. */
tlb_huge_update_store:
#ifdef CONFIG_SMP
- ll.d ra, t1, 0
+ PTE_LL ra, t1, 0
#else
- rotri.d ra, ra, 64 - (_PAGE_HUGE_SHIFT + 1)
+ PTR_ROTRI ra, ra, BITS_PER_LONG - (_PAGE_HUGE_SHIFT + 1)
#endif
+
+#ifdef CONFIG_64BIT
andi t0, ra, _PAGE_PRESENT | _PAGE_WRITE
xori t0, t0, _PAGE_PRESENT | _PAGE_WRITE
+#else
+ PTR_LI t0, _PAGE_PRESENT | _PAGE_WRITE
+ and t0, t0, ra
+ nor t0, t0, zero
+#endif
+
bnez t0, nopage_tlb_store
#ifdef CONFIG_SMP
ori t0, ra, (_PAGE_VALID | _PAGE_DIRTY | _PAGE_MODIFIED)
- sc.d t0, t1, 0
+ PTE_SC t0, t1, 0
beqz t0, tlb_huge_update_store
ori t0, ra, (_PAGE_VALID | _PAGE_DIRTY | _PAGE_MODIFIED)
#else
+#ifdef CONFIG_64BIT
ori t0, ra, (_PAGE_VALID | _PAGE_DIRTY | _PAGE_MODIFIED)
- st.d t0, t1, 0
+#else
+ PTR_LI t0, (_PAGE_VALID | _PAGE_DIRTY | _PAGE_MODIFIED)
+ or t0, ra, t0
+#endif
+ PTR_S t0, t1, 0
#endif
csrrd ra, LOONGARCH_CSR_ASID
csrrd t1, LOONGARCH_CSR_BADV
@@ -316,28 +360,28 @@ tlb_huge_update_store:
xori t0, t0, _PAGE_HUGE
lu12i.w t1, _PAGE_HGLOBAL >> 12
and t1, t0, t1
- srli.d t1, t1, (_PAGE_HGLOBAL_SHIFT - _PAGE_GLOBAL_SHIFT)
+ PTR_SRLI t1, t1, (_PAGE_HGLOBAL_SHIFT - _PAGE_GLOBAL_SHIFT)
or t0, t0, t1
move ra, t0
csrwr ra, LOONGARCH_CSR_TLBELO0
/* Convert to entrylo1 */
- addi.d t1, zero, 1
- slli.d t1, t1, (HPAGE_SHIFT - 1)
- add.d t0, t0, t1
+ PTR_ADDI t1, zero, 1
+ PTR_SLLI t1, t1, (HPAGE_SHIFT - 1)
+ PTR_ADD t0, t0, t1
csrwr t0, LOONGARCH_CSR_TLBELO1
/* Set huge page tlb entry size */
- addu16i.d t0, zero, (CSR_TLBIDX_PS >> 16)
- addu16i.d t1, zero, (PS_HUGE_SIZE << (CSR_TLBIDX_PS_SHIFT - 16))
+ PTR_LI t0, (CSR_TLBIDX_PS >> 16) << 16
+ PTR_LI t1, (PS_HUGE_SIZE << (CSR_TLBIDX_PS_SHIFT))
csrxchg t1, t0, LOONGARCH_CSR_TLBIDX
tlbfill
/* Reset default page size */
- addu16i.d t0, zero, (CSR_TLBIDX_PS >> 16)
- addu16i.d t1, zero, (PS_DEFAULT_SIZE << (CSR_TLBIDX_PS_SHIFT - 16))
+ PTR_LI t0, (CSR_TLBIDX_PS >> 16) << 16
+ PTR_LI t1, (PS_DEFAULT_SIZE << (CSR_TLBIDX_PS_SHIFT))
csrxchg t1, t0, LOONGARCH_CSR_TLBIDX
csrrd t0, EXCEPTION_KS0
@@ -375,52 +419,69 @@ SYM_CODE_START(handle_tlb_modify)
vmalloc_done_modify:
/* Get PGD offset in bytes */
- bstrpick.d ra, t0, PTRS_PER_PGD_BITS + PGDIR_SHIFT - 1, PGDIR_SHIFT
- alsl.d t1, ra, t1, 3
+#ifdef CONFIG_32BIT
+ PTR_BSTRPICK ra, t0, 31, PGDIR_SHIFT
+#else
+ PTR_BSTRPICK ra, t0, PTRS_PER_PGD_BITS + PGDIR_SHIFT - 1, PGDIR_SHIFT
+#endif
+ PTR_ALSL t1, ra, t1, _PGD_T_LOG2
+
#if CONFIG_PGTABLE_LEVELS > 3
- ld.d t1, t1, 0
- bstrpick.d ra, t0, PTRS_PER_PUD_BITS + PUD_SHIFT - 1, PUD_SHIFT
- alsl.d t1, ra, t1, 3
+ PTR_L t1, t1, 0
+ PTR_BSTRPICK ra, t0, PTRS_PER_PUD_BITS + PUD_SHIFT - 1, PUD_SHIFT
+ PTR_ALSL t1, ra, t1, _PMD_T_LOG2
#endif
#if CONFIG_PGTABLE_LEVELS > 2
- ld.d t1, t1, 0
- bstrpick.d ra, t0, PTRS_PER_PMD_BITS + PMD_SHIFT - 1, PMD_SHIFT
- alsl.d t1, ra, t1, 3
+ PTR_L t1, t1, 0
+ PTR_BSTRPICK ra, t0, PTRS_PER_PMD_BITS + PMD_SHIFT - 1, PMD_SHIFT
+ PTR_ALSL t1, ra, t1, _PMD_T_LOG2
#endif
- ld.d ra, t1, 0
+ PTR_L ra, t1, 0
/*
* For huge tlb entries, pmde doesn't contain an address but
* instead contains the tlb pte. Check the PAGE_HUGE bit and
* see if we need to jump to huge tlb processing.
*/
- rotri.d ra, ra, _PAGE_HUGE_SHIFT + 1
+ PTR_ROTRI ra, ra, _PAGE_HUGE_SHIFT + 1
bltz ra, tlb_huge_update_modify
- rotri.d ra, ra, 64 - (_PAGE_HUGE_SHIFT + 1)
- bstrpick.d t0, t0, PTRS_PER_PTE_BITS + PAGE_SHIFT - 1, PAGE_SHIFT
- alsl.d t1, t0, ra, _PTE_T_LOG2
+ PTR_ROTRI ra, ra, BITS_PER_LONG - (_PAGE_HUGE_SHIFT + 1)
+ PTR_BSTRPICK t0, t0, PTRS_PER_PTE_BITS + PAGE_SHIFT - 1, PAGE_SHIFT
+ PTR_ALSL t1, t0, ra, _PTE_T_LOG2
#ifdef CONFIG_SMP
smp_pgtable_change_modify:
- ll.d t0, t1, 0
+ PTE_LL t0, t1, 0
#else
- ld.d t0, t1, 0
+ PTR_L t0, t1, 0
#endif
+#ifdef CONFIG_64BIT
andi ra, t0, _PAGE_WRITE
+#else
+ PTR_LI ra, _PAGE_WRITE
+ and ra, t0, ra
+#endif
+
beqz ra, nopage_tlb_modify
+#ifdef CONFIG_64BIT
ori t0, t0, (_PAGE_VALID | _PAGE_DIRTY | _PAGE_MODIFIED)
+#else
+ PTR_LI ra, (_PAGE_VALID | _PAGE_DIRTY | _PAGE_MODIFIED)
+ or t0, ra, t0
+#endif
+
#ifdef CONFIG_SMP
- sc.d t0, t1, 0
+ PTE_SC t0, t1, 0
beqz t0, smp_pgtable_change_modify
#else
- st.d t0, t1, 0
+ PTR_S t0, t1, 0
#endif
tlbsrch
- bstrins.d t1, zero, 3, 3
- ld.d t0, t1, 0
- ld.d t1, t1, 8
+ PTR_BSTRINS t1, zero, _PTE_T_LOG2, _PTE_T_LOG2
+ PTR_L t0, t1, 0
+ PTR_L t1, t1, _PTE_T_SIZE
csrwr t0, LOONGARCH_CSR_TLBELO0
csrwr t1, LOONGARCH_CSR_TLBELO1
tlbwr
@@ -430,30 +491,40 @@ smp_pgtable_change_modify:
csrrd ra, EXCEPTION_KS2
ertn
-#ifdef CONFIG_64BIT
vmalloc_modify:
la_abs t1, swapper_pg_dir
b vmalloc_done_modify
-#endif
/* This is the entry point of a huge page. */
tlb_huge_update_modify:
#ifdef CONFIG_SMP
- ll.d ra, t1, 0
+ PTE_LL ra, t1, 0
#else
- rotri.d ra, ra, 64 - (_PAGE_HUGE_SHIFT + 1)
+ PTR_ROTRI ra, ra, BITS_PER_LONG - (_PAGE_HUGE_SHIFT + 1)
#endif
+
+#ifdef CONFIG_64BIT
andi t0, ra, _PAGE_WRITE
+#else
+ PTR_LI t0, _PAGE_WRITE
+ and t0, ra, t0
+#endif
+
beqz t0, nopage_tlb_modify
#ifdef CONFIG_SMP
ori t0, ra, (_PAGE_VALID | _PAGE_DIRTY | _PAGE_MODIFIED)
- sc.d t0, t1, 0
+ PTE_SC t0, t1, 0
beqz t0, tlb_huge_update_modify
ori t0, ra, (_PAGE_VALID | _PAGE_DIRTY | _PAGE_MODIFIED)
#else
+#ifdef CONFIG_64BIT
ori t0, ra, (_PAGE_VALID | _PAGE_DIRTY | _PAGE_MODIFIED)
- st.d t0, t1, 0
+#else
+ PTR_LI t0, (_PAGE_VALID | _PAGE_DIRTY | _PAGE_MODIFIED)
+ or t0, ra, t0
+#endif
+ PTR_S t0, t1, 0
#endif
csrrd ra, LOONGARCH_CSR_ASID
csrrd t1, LOONGARCH_CSR_BADV
@@ -473,28 +544,28 @@ tlb_huge_update_modify:
xori t0, t0, _PAGE_HUGE
lu12i.w t1, _PAGE_HGLOBAL >> 12
and t1, t0, t1
- srli.d t1, t1, (_PAGE_HGLOBAL_SHIFT - _PAGE_GLOBAL_SHIFT)
+ PTR_SRLI t1, t1, (_PAGE_HGLOBAL_SHIFT - _PAGE_GLOBAL_SHIFT)
or t0, t0, t1
move ra, t0
csrwr ra, LOONGARCH_CSR_TLBELO0
/* Convert to entrylo1 */
- addi.d t1, zero, 1
- slli.d t1, t1, (HPAGE_SHIFT - 1)
- add.d t0, t0, t1
+ PTR_ADDI t1, zero, 1
+ PTR_SLLI t1, t1, (HPAGE_SHIFT - 1)
+ PTR_ADD t0, t0, t1
csrwr t0, LOONGARCH_CSR_TLBELO1
/* Set huge page tlb entry size */
- addu16i.d t0, zero, (CSR_TLBIDX_PS >> 16)
- addu16i.d t1, zero, (PS_HUGE_SIZE << (CSR_TLBIDX_PS_SHIFT - 16))
+ PTR_LI t0, (CSR_TLBIDX_PS >> 16) << 16
+ PTR_LI t1, (PS_HUGE_SIZE << (CSR_TLBIDX_PS_SHIFT))
csrxchg t1, t0, LOONGARCH_CSR_TLBIDX
tlbfill
/* Reset default page size */
- addu16i.d t0, zero, (CSR_TLBIDX_PS >> 16)
- addu16i.d t1, zero, (PS_DEFAULT_SIZE << (CSR_TLBIDX_PS_SHIFT - 16))
+ PTR_LI t0, (CSR_TLBIDX_PS >> 16) << 16
+ PTR_LI t1, (PS_DEFAULT_SIZE << (CSR_TLBIDX_PS_SHIFT))
csrxchg t1, t0, LOONGARCH_CSR_TLBIDX
csrrd t0, EXCEPTION_KS0
@@ -517,6 +588,44 @@ SYM_CODE_START(handle_tlb_modify_ptw)
jr t0
SYM_CODE_END(handle_tlb_modify_ptw)
+#ifdef CONFIG_32BIT
+SYM_CODE_START(handle_tlb_refill)
+ UNWIND_HINT_UNDEFINED
+ csrwr t0, EXCEPTION_KS0
+ csrwr t1, EXCEPTION_KS1
+ csrwr ra, EXCEPTION_KS2
+ li.w ra, 0x1fffffff
+
+ csrrd t0, LOONGARCH_CSR_PGD
+ csrrd t1, LOONGARCH_CSR_TLBRBADV
+ srli.w t1, t1, PGDIR_SHIFT
+ slli.w t1, t1, 0x2
+ add.w t0, t0, t1
+ and t0, t0, ra
+
+ ld.w t0, t0, 0
+ csrrd t1, LOONGARCH_CSR_TLBRBADV
+ slli.w t1, t1, (32 - PGDIR_SHIFT)
+ srli.w t1, t1, (32 - PGDIR_SHIFT + PAGE_SHIFT + 1)
+ slli.w t1, t1, (0x2 + 1)
+ add.w t0, t0, t1
+ and t0, t0, ra
+
+ ld.w t1, t0, 0x0
+ csrwr t1, LOONGARCH_CSR_TLBRELO0
+
+ ld.w t1, t0, 0x4
+ csrwr t1, LOONGARCH_CSR_TLBRELO1
+
+ tlbfill
+ csrrd t0, EXCEPTION_KS0
+ csrrd t1, EXCEPTION_KS1
+ csrrd ra, EXCEPTION_KS2
+ ertn
+SYM_CODE_END(handle_tlb_refill)
+#endif
+
+#ifdef CONFIG_64BIT
SYM_CODE_START(handle_tlb_refill)
UNWIND_HINT_UNDEFINED
csrwr t0, LOONGARCH_CSR_TLBRSAVE
@@ -534,3 +643,4 @@ SYM_CODE_START(handle_tlb_refill)
csrrd t0, LOONGARCH_CSR_TLBRSAVE
ertn
SYM_CODE_END(handle_tlb_refill)
+#endif
diff --git a/arch/loongarch/pci/pci.c b/arch/loongarch/pci/pci.c
index d9fc5d520b37..d923295ab8c6 100644
--- a/arch/loongarch/pci/pci.c
+++ b/arch/loongarch/pci/pci.c
@@ -14,6 +14,7 @@
#define PCI_DEVICE_ID_LOONGSON_HOST 0x7a00
#define PCI_DEVICE_ID_LOONGSON_DC1 0x7a06
#define PCI_DEVICE_ID_LOONGSON_DC2 0x7a36
+#define PCI_DEVICE_ID_LOONGSON_DC3 0x7a46
int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn,
int reg, int len, u32 *val)
@@ -97,3 +98,4 @@ static void pci_fixup_vgadev(struct pci_dev *pdev)
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_DC1, pci_fixup_vgadev);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_DC2, pci_fixup_vgadev);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_DC3, pci_fixup_vgadev);
diff --git a/arch/loongarch/power/hibernate.c b/arch/loongarch/power/hibernate.c
index e7b7346592cb..817270410ef9 100644
--- a/arch/loongarch/power/hibernate.c
+++ b/arch/loongarch/power/hibernate.c
@@ -10,7 +10,7 @@ static u32 saved_crmd;
static u32 saved_prmd;
static u32 saved_euen;
static u32 saved_ecfg;
-static u64 saved_pcpu_base;
+static unsigned long saved_pcpu_base;
struct pt_regs saved_regs;
void save_processor_state(void)
@@ -20,7 +20,7 @@ void save_processor_state(void)
saved_prmd = csr_read32(LOONGARCH_CSR_PRMD);
saved_euen = csr_read32(LOONGARCH_CSR_EUEN);
saved_ecfg = csr_read32(LOONGARCH_CSR_ECFG);
- saved_pcpu_base = csr_read64(PERCPU_BASE_KS);
+ saved_pcpu_base = csr_read(PERCPU_BASE_KS);
if (is_fpu_owner())
save_fp(current);
@@ -33,7 +33,7 @@ void restore_processor_state(void)
csr_write32(saved_prmd, LOONGARCH_CSR_PRMD);
csr_write32(saved_euen, LOONGARCH_CSR_EUEN);
csr_write32(saved_ecfg, LOONGARCH_CSR_ECFG);
- csr_write64(saved_pcpu_base, PERCPU_BASE_KS);
+ csr_write(saved_pcpu_base, PERCPU_BASE_KS);
if (is_fpu_owner())
restore_fp(current);
diff --git a/arch/loongarch/power/platform.c b/arch/loongarch/power/platform.c
index 5bbdb9fd76e5..faa4fe4e7461 100644
--- a/arch/loongarch/power/platform.c
+++ b/arch/loongarch/power/platform.c
@@ -72,10 +72,10 @@ static int __init loongson3_acpi_suspend_init(void)
status = acpi_evaluate_integer(NULL, "\\SADR", NULL, &suspend_addr);
if (ACPI_FAILURE(status) || !suspend_addr) {
pr_info("ACPI S3 supported with hardware register default\n");
- loongson_sysconf.suspend_addr = (u64)default_suspend_addr;
+ loongson_sysconf.suspend_addr = (unsigned long)default_suspend_addr;
} else {
pr_info("ACPI S3 supported with Loongson ACPI SADR extension\n");
- loongson_sysconf.suspend_addr = (u64)phys_to_virt(PHYSADDR(suspend_addr));
+ loongson_sysconf.suspend_addr = (unsigned long)phys_to_virt(PHYSADDR(suspend_addr));
}
#endif
return 0;
diff --git a/arch/loongarch/power/suspend.c b/arch/loongarch/power/suspend.c
index c9e594925c47..7e3d79f8bbd4 100644
--- a/arch/loongarch/power/suspend.c
+++ b/arch/loongarch/power/suspend.c
@@ -20,24 +20,24 @@ u64 loongarch_suspend_addr;
struct saved_registers {
u32 ecfg;
u32 euen;
- u64 pgd;
- u64 kpgd;
u32 pwctl0;
u32 pwctl1;
- u64 pcpu_base;
+ unsigned long pgd;
+ unsigned long kpgd;
+ unsigned long pcpu_base;
};
static struct saved_registers saved_regs;
void loongarch_common_suspend(void)
{
save_counter();
- saved_regs.pgd = csr_read64(LOONGARCH_CSR_PGDL);
- saved_regs.kpgd = csr_read64(LOONGARCH_CSR_PGDH);
+ saved_regs.pgd = csr_read(LOONGARCH_CSR_PGDL);
+ saved_regs.kpgd = csr_read(LOONGARCH_CSR_PGDH);
saved_regs.pwctl0 = csr_read32(LOONGARCH_CSR_PWCTL0);
saved_regs.pwctl1 = csr_read32(LOONGARCH_CSR_PWCTL1);
saved_regs.ecfg = csr_read32(LOONGARCH_CSR_ECFG);
saved_regs.euen = csr_read32(LOONGARCH_CSR_EUEN);
- saved_regs.pcpu_base = csr_read64(PERCPU_BASE_KS);
+ saved_regs.pcpu_base = csr_read(PERCPU_BASE_KS);
loongarch_suspend_addr = loongson_sysconf.suspend_addr;
}
@@ -46,17 +46,17 @@ void loongarch_common_resume(void)
{
sync_counter();
local_flush_tlb_all();
- csr_write64(eentry, LOONGARCH_CSR_EENTRY);
- csr_write64(eentry, LOONGARCH_CSR_MERRENTRY);
- csr_write64(tlbrentry, LOONGARCH_CSR_TLBRENTRY);
+ csr_write(eentry, LOONGARCH_CSR_EENTRY);
+ csr_write(eentry, LOONGARCH_CSR_MERRENTRY);
+ csr_write(tlbrentry, LOONGARCH_CSR_TLBRENTRY);
- csr_write64(saved_regs.pgd, LOONGARCH_CSR_PGDL);
- csr_write64(saved_regs.kpgd, LOONGARCH_CSR_PGDH);
+ csr_write(saved_regs.pgd, LOONGARCH_CSR_PGDL);
+ csr_write(saved_regs.kpgd, LOONGARCH_CSR_PGDH);
csr_write32(saved_regs.pwctl0, LOONGARCH_CSR_PWCTL0);
csr_write32(saved_regs.pwctl1, LOONGARCH_CSR_PWCTL1);
csr_write32(saved_regs.ecfg, LOONGARCH_CSR_ECFG);
csr_write32(saved_regs.euen, LOONGARCH_CSR_EUEN);
- csr_write64(saved_regs.pcpu_base, PERCPU_BASE_KS);
+ csr_write(saved_regs.pcpu_base, PERCPU_BASE_KS);
}
int loongarch_acpi_suspend(void)
diff --git a/arch/loongarch/power/suspend_asm.S b/arch/loongarch/power/suspend_asm.S
index df0865df26fa..c8119ad5fb2c 100644
--- a/arch/loongarch/power/suspend_asm.S
+++ b/arch/loongarch/power/suspend_asm.S
@@ -14,41 +14,41 @@
/* preparatory stuff */
.macro SETUP_SLEEP
- addi.d sp, sp, -PT_SIZE
- st.d $r1, sp, PT_R1
- st.d $r2, sp, PT_R2
- st.d $r3, sp, PT_R3
- st.d $r4, sp, PT_R4
- st.d $r21, sp, PT_R21
- st.d $r22, sp, PT_R22
- st.d $r23, sp, PT_R23
- st.d $r24, sp, PT_R24
- st.d $r25, sp, PT_R25
- st.d $r26, sp, PT_R26
- st.d $r27, sp, PT_R27
- st.d $r28, sp, PT_R28
- st.d $r29, sp, PT_R29
- st.d $r30, sp, PT_R30
- st.d $r31, sp, PT_R31
+ PTR_ADDI sp, sp, -PT_SIZE
+ REG_S $r1, sp, PT_R1
+ REG_S $r2, sp, PT_R2
+ REG_S $r3, sp, PT_R3
+ REG_S $r4, sp, PT_R4
+ REG_S $r21, sp, PT_R21
+ REG_S $r22, sp, PT_R22
+ REG_S $r23, sp, PT_R23
+ REG_S $r24, sp, PT_R24
+ REG_S $r25, sp, PT_R25
+ REG_S $r26, sp, PT_R26
+ REG_S $r27, sp, PT_R27
+ REG_S $r28, sp, PT_R28
+ REG_S $r29, sp, PT_R29
+ REG_S $r30, sp, PT_R30
+ REG_S $r31, sp, PT_R31
.endm
.macro SETUP_WAKEUP
- ld.d $r1, sp, PT_R1
- ld.d $r2, sp, PT_R2
- ld.d $r3, sp, PT_R3
- ld.d $r4, sp, PT_R4
- ld.d $r21, sp, PT_R21
- ld.d $r22, sp, PT_R22
- ld.d $r23, sp, PT_R23
- ld.d $r24, sp, PT_R24
- ld.d $r25, sp, PT_R25
- ld.d $r26, sp, PT_R26
- ld.d $r27, sp, PT_R27
- ld.d $r28, sp, PT_R28
- ld.d $r29, sp, PT_R29
- ld.d $r30, sp, PT_R30
- ld.d $r31, sp, PT_R31
- addi.d sp, sp, PT_SIZE
+ REG_L $r1, sp, PT_R1
+ REG_L $r2, sp, PT_R2
+ REG_L $r3, sp, PT_R3
+ REG_L $r4, sp, PT_R4
+ REG_L $r21, sp, PT_R21
+ REG_L $r22, sp, PT_R22
+ REG_L $r23, sp, PT_R23
+ REG_L $r24, sp, PT_R24
+ REG_L $r25, sp, PT_R25
+ REG_L $r26, sp, PT_R26
+ REG_L $r27, sp, PT_R27
+ REG_L $r28, sp, PT_R28
+ REG_L $r29, sp, PT_R29
+ REG_L $r30, sp, PT_R30
+ REG_L $r31, sp, PT_R31
+ PTR_ADDI sp, sp, PT_SIZE
.endm
.text
@@ -59,15 +59,15 @@ SYM_FUNC_START(loongarch_suspend_enter)
SETUP_SLEEP
la.pcrel t0, acpi_saved_sp
- st.d sp, t0, 0
+ REG_S sp, t0, 0
bl __flush_cache_all
/* Pass RA and SP to BIOS */
- addi.d a1, sp, 0
+ PTR_ADDI a1, sp, 0
la.pcrel a0, loongarch_wakeup_start
la.pcrel t0, loongarch_suspend_addr
- ld.d t0, t0, 0
+ REG_L t0, t0, 0
jirl ra, t0, 0 /* Call BIOS's STR sleep routine */
/*
@@ -83,7 +83,7 @@ SYM_INNER_LABEL(loongarch_wakeup_start, SYM_L_GLOBAL)
csrwr t0, LOONGARCH_CSR_CRMD
la.pcrel t0, acpi_saved_sp
- ld.d sp, t0, 0
+ REG_L sp, t0, 0
SETUP_WAKEUP
jr ra
diff --git a/arch/loongarch/vdso/Makefile b/arch/loongarch/vdso/Makefile
index c0cc3ca5da9f..520f1513f07d 100644
--- a/arch/loongarch/vdso/Makefile
+++ b/arch/loongarch/vdso/Makefile
@@ -4,8 +4,9 @@
# Include the generic Makefile to check the built vdso.
include $(srctree)/lib/vdso/Makefile.include
-obj-vdso-y := elf.o vgetcpu.o vgettimeofday.o vgetrandom.o \
+obj-vdso-y := elf.o vgetcpu.o vgetrandom.o \
vgetrandom-chacha.o sigreturn.o
+obj-vdso-$(CONFIG_GENERIC_GETTIMEOFDAY) += vgettimeofday.o
# Common compiler flags between ABIs.
ccflags-vdso := \
@@ -16,6 +17,10 @@ ccflags-vdso := \
$(CLANG_FLAGS) \
-D__VDSO__
+ifdef CONFIG_32BIT
+ccflags-vdso += -DBUILD_VDSO32
+endif
+
cflags-vdso := $(ccflags-vdso) \
-isystem $(shell $(CC) -print-file-name=include) \
$(filter -W%,$(filter-out -Wa$(comma)%,$(KBUILD_CFLAGS))) \
diff --git a/arch/loongarch/vdso/vdso.lds.S b/arch/loongarch/vdso/vdso.lds.S
index 8ff986499947..ac537e02beb1 100644
--- a/arch/loongarch/vdso/vdso.lds.S
+++ b/arch/loongarch/vdso/vdso.lds.S
@@ -7,8 +7,6 @@
#include <generated/asm-offsets.h>
#include <vdso/datapage.h>
-OUTPUT_FORMAT("elf64-loongarch", "elf64-loongarch", "elf64-loongarch")
-
OUTPUT_ARCH(loongarch)
SECTIONS
@@ -63,9 +61,11 @@ VERSION
LINUX_5.10 {
global:
__vdso_getcpu;
+#ifdef CONFIG_GENERIC_GETTIMEOFDAY
__vdso_clock_getres;
__vdso_clock_gettime;
__vdso_gettimeofday;
+#endif
__vdso_getrandom;
__vdso_rt_sigreturn;
local: *;
diff --git a/arch/loongarch/vdso/vgetcpu.c b/arch/loongarch/vdso/vgetcpu.c
index 5301cd9d0f83..73af49242ecd 100644
--- a/arch/loongarch/vdso/vgetcpu.c
+++ b/arch/loongarch/vdso/vgetcpu.c
@@ -10,11 +10,19 @@ static __always_inline int read_cpu_id(void)
{
int cpu_id;
+#ifdef CONFIG_64BIT
__asm__ __volatile__(
" rdtime.d $zero, %0\n"
: "=r" (cpu_id)
:
: "memory");
+#else
+ __asm__ __volatile__(
+ " rdtimel.w $zero, %0\n"
+ : "=r" (cpu_id)
+ :
+ : "memory");
+#endif
return cpu_id;
}
diff --git a/arch/mips/configs/gcw0_defconfig b/arch/mips/configs/gcw0_defconfig
index fda9971bdd8d..adb9fd62ddb0 100644
--- a/arch/mips/configs/gcw0_defconfig
+++ b/arch/mips/configs/gcw0_defconfig
@@ -79,7 +79,6 @@ CONFIG_LOGO=y
# CONFIG_LOGO_LINUX_VGA16 is not set
CONFIG_SOUND=y
CONFIG_SND=y
-# CONFIG_SND_SUPPORT_OLD_API is not set
# CONFIG_SND_PROC_FS is not set
# CONFIG_SND_DRIVERS is not set
# CONFIG_SND_SPI is not set
diff --git a/arch/mips/configs/loongson1_defconfig b/arch/mips/configs/loongson1_defconfig
index 02d29110f702..1d9781ff9698 100644
--- a/arch/mips/configs/loongson1_defconfig
+++ b/arch/mips/configs/loongson1_defconfig
@@ -119,7 +119,6 @@ CONFIG_WATCHDOG_SYSFS=y
CONFIG_LOONGSON1_WDT=y
CONFIG_SOUND=y
CONFIG_SND=y
-# CONFIG_SND_SUPPORT_OLD_API is not set
# CONFIG_SND_DRIVERS is not set
# CONFIG_SND_MIPS is not set
# CONFIG_SND_USB is not set
diff --git a/arch/mips/configs/qi_lb60_defconfig b/arch/mips/configs/qi_lb60_defconfig
index 5f5b0254d75e..a1bb0792f6eb 100644
--- a/arch/mips/configs/qi_lb60_defconfig
+++ b/arch/mips/configs/qi_lb60_defconfig
@@ -81,7 +81,6 @@ CONFIG_LOGO=y
# CONFIG_LOGO_LINUX_CLUT224 is not set
CONFIG_SOUND=y
CONFIG_SND=y
-# CONFIG_SND_SUPPORT_OLD_API is not set
# CONFIG_SND_VERBOSE_PROCFS is not set
# CONFIG_SND_DRIVERS is not set
# CONFIG_SND_SPI is not set
diff --git a/arch/mips/configs/rbtx49xx_defconfig b/arch/mips/configs/rbtx49xx_defconfig
index 03a7bbe28a53..49c709d663be 100644
--- a/arch/mips/configs/rbtx49xx_defconfig
+++ b/arch/mips/configs/rbtx49xx_defconfig
@@ -53,7 +53,6 @@ CONFIG_TXX9_WDT=m
# CONFIG_VGA_ARB is not set
CONFIG_SOUND=m
CONFIG_SND=m
-# CONFIG_SND_SUPPORT_OLD_API is not set
# CONFIG_SND_VERBOSE_PROCFS is not set
# CONFIG_SND_DRIVERS is not set
# CONFIG_SND_PCI is not set
diff --git a/arch/mips/configs/rs90_defconfig b/arch/mips/configs/rs90_defconfig
index a53dd66e9b86..8382d535e6dc 100644
--- a/arch/mips/configs/rs90_defconfig
+++ b/arch/mips/configs/rs90_defconfig
@@ -105,7 +105,6 @@ CONFIG_LOGO=y
CONFIG_SOUND=y
CONFIG_SND=y
# CONFIG_SND_PCM_TIMER is not set
-# CONFIG_SND_SUPPORT_OLD_API is not set
# CONFIG_SND_PROC_FS is not set
# CONFIG_SND_DRIVERS is not set
# CONFIG_SND_MIPS is not set
diff --git a/arch/powerpc/configs/85xx-hw.config b/arch/powerpc/configs/85xx-hw.config
index 8aff83217397..2b19c20a9a2c 100644
--- a/arch/powerpc/configs/85xx-hw.config
+++ b/arch/powerpc/configs/85xx-hw.config
@@ -117,7 +117,6 @@ CONFIG_SND_INTEL8X0=y
CONFIG_SND_POWERPC_SOC=y
# CONFIG_SND_PPC is not set
CONFIG_SND_SOC=y
-# CONFIG_SND_SUPPORT_OLD_API is not set
# CONFIG_SND_USB is not set
CONFIG_SND=y
CONFIG_SOUND=y
diff --git a/arch/powerpc/configs/86xx-hw.config b/arch/powerpc/configs/86xx-hw.config
index e7bd265fae5a..07f30ab881e5 100644
--- a/arch/powerpc/configs/86xx-hw.config
+++ b/arch/powerpc/configs/86xx-hw.config
@@ -80,7 +80,6 @@ CONFIG_SERIO_LIBPS2=y
CONFIG_SND_INTEL8X0=y
CONFIG_SND_MIXER_OSS=y
CONFIG_SND_PCM_OSS=y
-# CONFIG_SND_SUPPORT_OLD_API is not set
CONFIG_SND=y
CONFIG_SOUND=y
CONFIG_ULI526X=y
diff --git a/arch/powerpc/configs/mpc5200_defconfig b/arch/powerpc/configs/mpc5200_defconfig
index c0fe5e76604a..617650cea56a 100644
--- a/arch/powerpc/configs/mpc5200_defconfig
+++ b/arch/powerpc/configs/mpc5200_defconfig
@@ -75,7 +75,6 @@ CONFIG_FB_SM501=m
CONFIG_LOGO=y
CONFIG_SOUND=y
CONFIG_SND=y
-# CONFIG_SND_SUPPORT_OLD_API is not set
# CONFIG_SND_DRIVERS is not set
# CONFIG_SND_PCI is not set
# CONFIG_SND_PPC is not set
diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig
index b082c1fae13c..787d707f64a4 100644
--- a/arch/powerpc/configs/ppc6xx_defconfig
+++ b/arch/powerpc/configs/ppc6xx_defconfig
@@ -726,7 +726,6 @@ CONFIG_SND_OSSEMUL=y
CONFIG_SND_MIXER_OSS=m
CONFIG_SND_PCM_OSS=m
CONFIG_SND_DYNAMIC_MINORS=y
-# CONFIG_SND_SUPPORT_OLD_API is not set
CONFIG_SND_VERBOSE_PRINTK=y
CONFIG_SND_DEBUG=y
CONFIG_SND_DEBUG_VERBOSE=y
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 938e5df75b2d..0e5fad5f06ca 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -238,6 +238,7 @@ config S390
select HAVE_PERF_EVENTS
select HAVE_PERF_REGS
select HAVE_PERF_USER_STACK_DUMP
+ select HAVE_POSIX_CPU_TIMERS_TASK_WORK
select HAVE_PREEMPT_DYNAMIC_KEY
select HAVE_REGS_AND_STACK_ACCESS_API
select HAVE_RELIABLE_STACKTRACE
@@ -254,6 +255,7 @@ config S390
select HOTPLUG_SMT
select IOMMU_HELPER if PCI
select IOMMU_SUPPORT if PCI
+ select IRQ_MSI_LIB if PCI
select KASAN_VMALLOC if KASAN
select LOCK_MM_AND_FIND_VMA
select MMU_GATHER_MERGE_VMAS
diff --git a/arch/s390/boot/vmem.c b/arch/s390/boot/vmem.c
index fbe64ffdfb96..7d6cc4c85af0 100644
--- a/arch/s390/boot/vmem.c
+++ b/arch/s390/boot/vmem.c
@@ -244,22 +244,10 @@ static void *boot_crst_alloc(unsigned long val)
static pte_t *boot_pte_alloc(void)
{
- static void *pte_leftover;
pte_t *pte;
- /*
- * handling pte_leftovers this way helps to avoid memory fragmentation
- * during POPULATE_KASAN_MAP_SHADOW when EDAT is off
- */
- if (!pte_leftover) {
- pte_leftover = (void *)physmem_alloc_or_die(RR_VMEM, PAGE_SIZE, PAGE_SIZE);
- pte = pte_leftover + _PAGE_TABLE_SIZE;
- __arch_set_page_dat(pte, 1);
- } else {
- pte = pte_leftover;
- pte_leftover = NULL;
- }
-
+ pte = (void *)physmem_alloc_or_die(RR_VMEM, PAGE_SIZE, PAGE_SIZE);
+ __arch_set_page_dat(pte, 1);
memset64((u64 *)pte, _PAGE_INVALID, PTRS_PER_PTE);
return pte;
}
diff --git a/arch/s390/include/asm/bug.h b/arch/s390/include/asm/bug.h
index acb4b13d98c5..ee9221bb5d18 100644
--- a/arch/s390/include/asm/bug.h
+++ b/arch/s390/include/asm/bug.h
@@ -4,11 +4,14 @@
#include <linux/stringify.h>
+#ifdef CONFIG_BUG
+
#ifndef CONFIG_DEBUG_BUGVERBOSE
#define _BUGVERBOSE_LOCATION(file, line)
#else
#define __BUGVERBOSE_LOCATION(file, line) \
.pushsection .rodata.str, "aMS", @progbits, 1; \
+ .align 2; \
10002: .ascii file "\0"; \
.popsection; \
\
@@ -52,6 +55,8 @@ do { \
#define HAVE_ARCH_BUG
+#endif /* CONFIG_BUG */
+
#include <asm-generic/bug.h>
#endif /* _ASM_S390_BUG_H */
diff --git a/arch/s390/include/asm/page.h b/arch/s390/include/asm/page.h
index 9240a363c893..c1d63b613bf9 100644
--- a/arch/s390/include/asm/page.h
+++ b/arch/s390/include/asm/page.h
@@ -166,6 +166,8 @@ static inline int page_reset_referenced(unsigned long addr)
return CC_TRANSFORM(cc);
}
+int split_pud_page(pud_t *pudp, unsigned long addr);
+
/* Bits int the storage key */
#define _PAGE_CHANGED 0x02 /* HW changed bit */
#define _PAGE_REFERENCED 0x04 /* HW referenced bit */
diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h
index a32f465ecf73..c0ff19dab580 100644
--- a/arch/s390/include/asm/pci.h
+++ b/arch/s390/include/asm/pci.h
@@ -5,6 +5,7 @@
#include <linux/pci.h>
#include <linux/mutex.h>
#include <linux/iommu.h>
+#include <linux/irqdomain.h>
#include <linux/pci_hotplug.h>
#include <asm/pci_clp.h>
#include <asm/pci_debug.h>
@@ -109,6 +110,7 @@ struct zpci_bus {
struct list_head resources;
struct list_head bus_next;
struct resource bus_resource;
+ struct irq_domain *msi_parent_domain;
int topo; /* TID if topo_is_tid, PCHID otherwise */
int domain_nr;
u8 multifunction : 1;
@@ -310,6 +312,9 @@ int zpci_dma_exit_device(struct zpci_dev *zdev);
/* IRQ */
int __init zpci_irq_init(void);
void __init zpci_irq_exit(void);
+int zpci_set_irq(struct zpci_dev *zdev);
+int zpci_create_parent_msi_domain(struct zpci_bus *zbus);
+void zpci_remove_parent_msi_domain(struct zpci_bus *zbus);
/* FMB */
int zpci_fmb_enable_device(struct zpci_dev *);
diff --git a/arch/s390/mm/gmap_helpers.c b/arch/s390/mm/gmap_helpers.c
index 549f14ad08af..d41b19925a5a 100644
--- a/arch/s390/mm/gmap_helpers.c
+++ b/arch/s390/mm/gmap_helpers.c
@@ -47,6 +47,7 @@ static void ptep_zap_softleaf_entry(struct mm_struct *mm, softleaf_t entry)
void gmap_helper_zap_one_page(struct mm_struct *mm, unsigned long vmaddr)
{
struct vm_area_struct *vma;
+ unsigned long pgstev;
spinlock_t *ptl;
pgste_t pgste;
pte_t *ptep;
@@ -65,9 +66,13 @@ void gmap_helper_zap_one_page(struct mm_struct *mm, unsigned long vmaddr)
if (pte_swap(*ptep)) {
preempt_disable();
pgste = pgste_get_lock(ptep);
+ pgstev = pgste_val(pgste);
- ptep_zap_softleaf_entry(mm, softleaf_from_pte(*ptep));
- pte_clear(mm, vmaddr, ptep);
+ if ((pgstev & _PGSTE_GPS_USAGE_MASK) == _PGSTE_GPS_USAGE_UNUSED ||
+ (pgstev & _PGSTE_GPS_ZERO)) {
+ ptep_zap_softleaf_entry(mm, softleaf_from_pte(*ptep));
+ pte_clear(mm, vmaddr, ptep);
+ }
pgste_set_unlock(ptep, pgste);
preempt_enable();
diff --git a/arch/s390/mm/pageattr.c b/arch/s390/mm/pageattr.c
index 3042647c9dbf..d3ce04a4b248 100644
--- a/arch/s390/mm/pageattr.c
+++ b/arch/s390/mm/pageattr.c
@@ -204,7 +204,7 @@ static int walk_pmd_level(pud_t *pudp, unsigned long addr, unsigned long end,
return rc;
}
-static int split_pud_page(pud_t *pudp, unsigned long addr)
+int split_pud_page(pud_t *pudp, unsigned long addr)
{
unsigned long pmd_addr, prot;
pmd_t *pm_dir, *pmdp;
diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c
index d96587b84e81..eeadff45e0e1 100644
--- a/arch/s390/mm/vmem.c
+++ b/arch/s390/mm/vmem.c
@@ -330,10 +330,14 @@ static int modify_pud_table(p4d_t *p4d, unsigned long addr, unsigned long end,
if (pud_leaf(*pud)) {
if (IS_ALIGNED(addr, PUD_SIZE) &&
IS_ALIGNED(next, PUD_SIZE)) {
+ if (!direct)
+ vmem_free_pages(pud_deref(*pud), get_order(PUD_SIZE), altmap);
pud_clear(pud);
pages++;
+ continue;
+ } else {
+ split_pud_page(pud, addr & PUD_MASK);
}
- continue;
}
} else if (pud_none(*pud)) {
if (IS_ALIGNED(addr, PUD_SIZE) &&
@@ -433,9 +437,15 @@ static int modify_pagetable(unsigned long start, unsigned long end, bool add,
if (WARN_ON_ONCE(!PAGE_ALIGNED(start | end)))
return -EINVAL;
- /* Don't mess with any tables not fully in 1:1 mapping & vmemmap area */
+ /* Don't mess with any tables not fully in 1:1 mapping, vmemmap & kasan area */
+#ifdef CONFIG_KASAN
+ if (WARN_ON_ONCE(!(start >= KASAN_SHADOW_START && end <= KASAN_SHADOW_END) &&
+ end > __abs_lowcore))
+ return -EINVAL;
+#else
if (WARN_ON_ONCE(end > __abs_lowcore))
return -EINVAL;
+#endif
for (addr = start; addr < end; addr = next) {
next = pgd_addr_end(addr, end);
pgd = pgd_offset_k(addr);
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c
index 93d2c9c780fc..5a6ace9d875a 100644
--- a/arch/s390/pci/pci.c
+++ b/arch/s390/pci/pci.c
@@ -708,6 +708,12 @@ int zpci_reenable_device(struct zpci_dev *zdev)
if (rc)
return rc;
+ if (zdev->msi_nr_irqs > 0) {
+ rc = zpci_set_irq(zdev);
+ if (rc)
+ return rc;
+ }
+
rc = zpci_iommu_register_ioat(zdev, &status);
if (rc)
zpci_disable_device(zdev);
diff --git a/arch/s390/pci/pci_bus.c b/arch/s390/pci/pci_bus.c
index 72adc8f6e94f..66c4bd888b29 100644
--- a/arch/s390/pci/pci_bus.c
+++ b/arch/s390/pci/pci_bus.c
@@ -14,6 +14,7 @@
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/seq_file.h>
+#include <linux/irqdomain.h>
#include <linux/jump_label.h>
#include <linux/pci.h>
#include <linux/printk.h>
@@ -198,19 +199,27 @@ static int zpci_bus_create_pci_bus(struct zpci_bus *zbus, struct zpci_dev *fr, s
zbus->multifunction = zpci_bus_is_multifunction_root(fr);
zbus->max_bus_speed = fr->max_bus_speed;
+ if (zpci_create_parent_msi_domain(zbus))
+ goto out_free_domain;
+
/*
* Note that the zbus->resources are taken over and zbus->resources
* is empty after a successful call
*/
bus = pci_create_root_bus(NULL, ZPCI_BUS_NR, ops, zbus, &zbus->resources);
- if (!bus) {
- zpci_free_domain(zbus->domain_nr);
- return -EFAULT;
- }
+ if (!bus)
+ goto out_remove_msi_domain;
zbus->bus = bus;
+ dev_set_msi_domain(&zbus->bus->dev, zbus->msi_parent_domain);
return 0;
+
+out_remove_msi_domain:
+ zpci_remove_parent_msi_domain(zbus);
+out_free_domain:
+ zpci_free_domain(zbus->domain_nr);
+ return -ENOMEM;
}
static void zpci_bus_release(struct kref *kref)
@@ -231,6 +240,7 @@ static void zpci_bus_release(struct kref *kref)
mutex_lock(&zbus_list_lock);
list_del(&zbus->bus_next);
mutex_unlock(&zbus_list_lock);
+ zpci_remove_parent_msi_domain(zbus);
kfree(zbus);
}
diff --git a/arch/s390/pci/pci_irq.c b/arch/s390/pci/pci_irq.c
index 2a06df8c2498..e9dd45f3c09d 100644
--- a/arch/s390/pci/pci_irq.c
+++ b/arch/s390/pci/pci_irq.c
@@ -6,6 +6,7 @@
#include <linux/kernel_stat.h>
#include <linux/pci.h>
#include <linux/msi.h>
+#include <linux/irqchip/irq-msi-lib.h>
#include <linux/smp.h>
#include <asm/isc.h>
@@ -97,7 +98,7 @@ static int zpci_clear_directed_irq(struct zpci_dev *zdev)
}
/* Register adapter interruptions */
-static int zpci_set_irq(struct zpci_dev *zdev)
+int zpci_set_irq(struct zpci_dev *zdev)
{
int rc;
@@ -125,27 +126,53 @@ static int zpci_clear_irq(struct zpci_dev *zdev)
static int zpci_set_irq_affinity(struct irq_data *data, const struct cpumask *dest,
bool force)
{
- struct msi_desc *entry = irq_data_get_msi_desc(data);
- struct msi_msg msg = entry->msg;
- int cpu_addr = smp_cpu_get_cpu_address(cpumask_first(dest));
+ irq_data_update_affinity(data, dest);
+ return IRQ_SET_MASK_OK;
+}
- msg.address_lo &= 0xff0000ff;
- msg.address_lo |= (cpu_addr << 8);
- pci_write_msi_msg(data->irq, &msg);
+/*
+ * Encode the hwirq number for the parent domain. The encoding must be unique
+ * for each IRQ of each device in the parent domain, so it uses the devfn to
+ * identify the device and the msi_index to identify the IRQ within that device.
+ */
+static inline u32 zpci_encode_hwirq(u8 devfn, u16 msi_index)
+{
+ return (devfn << 16) | msi_index;
+}
- return IRQ_SET_MASK_OK;
+static inline u16 zpci_decode_hwirq_msi_index(irq_hw_number_t hwirq)
+{
+ return hwirq & 0xffff;
+}
+
+static void zpci_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
+{
+ struct msi_desc *desc = irq_data_get_msi_desc(data);
+ struct zpci_dev *zdev = to_zpci_dev(desc->dev);
+
+ if (irq_delivery == DIRECTED) {
+ int cpu = cpumask_first(irq_data_get_affinity_mask(data));
+
+ msg->address_lo = zdev->msi_addr & 0xff0000ff;
+ msg->address_lo |= (smp_cpu_get_cpu_address(cpu) << 8);
+ } else {
+ msg->address_lo = zdev->msi_addr & 0xffffffff;
+ }
+ msg->address_hi = zdev->msi_addr >> 32;
+ msg->data = zpci_decode_hwirq_msi_index(data->hwirq);
}
static struct irq_chip zpci_irq_chip = {
.name = "PCI-MSI",
- .irq_unmask = pci_msi_unmask_irq,
- .irq_mask = pci_msi_mask_irq,
+ .irq_compose_msi_msg = zpci_compose_msi_msg,
};
static void zpci_handle_cpu_local_irq(bool rescan)
{
struct airq_iv *dibv = zpci_ibv[smp_processor_id()];
union zpci_sic_iib iib = {{0}};
+ struct irq_domain *msi_domain;
+ irq_hw_number_t hwirq;
unsigned long bit;
int irqs_on = 0;
@@ -163,7 +190,9 @@ static void zpci_handle_cpu_local_irq(bool rescan)
continue;
}
inc_irq_stat(IRQIO_MSI);
- generic_handle_irq(airq_iv_get_data(dibv, bit));
+ hwirq = airq_iv_get_data(dibv, bit);
+ msi_domain = (struct irq_domain *)airq_iv_get_ptr(dibv, bit);
+ generic_handle_domain_irq(msi_domain, hwirq);
}
}
@@ -228,6 +257,8 @@ static void zpci_floating_irq_handler(struct airq_struct *airq,
struct tpi_info *tpi_info)
{
union zpci_sic_iib iib = {{0}};
+ struct irq_domain *msi_domain;
+ irq_hw_number_t hwirq;
unsigned long si, ai;
struct airq_iv *aibv;
int irqs_on = 0;
@@ -255,7 +286,9 @@ static void zpci_floating_irq_handler(struct airq_struct *airq,
break;
inc_irq_stat(IRQIO_MSI);
airq_iv_lock(aibv, ai);
- generic_handle_irq(airq_iv_get_data(aibv, ai));
+ hwirq = airq_iv_get_data(aibv, ai);
+ msi_domain = (struct irq_domain *)airq_iv_get_ptr(aibv, ai);
+ generic_handle_domain_irq(msi_domain, hwirq);
airq_iv_unlock(aibv, ai);
}
}
@@ -277,7 +310,9 @@ static int __alloc_airq(struct zpci_dev *zdev, int msi_vecs,
zdev->aisb = *bit;
/* Create adapter interrupt vector */
- zdev->aibv = airq_iv_create(msi_vecs, AIRQ_IV_DATA | AIRQ_IV_BITLOCK, NULL);
+ zdev->aibv = airq_iv_create(msi_vecs,
+ AIRQ_IV_PTR | AIRQ_IV_DATA | AIRQ_IV_BITLOCK,
+ NULL);
if (!zdev->aibv)
return -ENOMEM;
@@ -289,146 +324,220 @@ static int __alloc_airq(struct zpci_dev *zdev, int msi_vecs,
return 0;
}
-int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
+bool arch_restore_msi_irqs(struct pci_dev *pdev)
{
- unsigned int hwirq, msi_vecs, irqs_per_msi, i, cpu;
struct zpci_dev *zdev = to_zpci(pdev);
- struct msi_desc *msi;
- struct msi_msg msg;
- unsigned long bit;
- int cpu_addr;
- int rc, irq;
+ zpci_set_irq(zdev);
+ return true;
+}
+
+static struct airq_struct zpci_airq = {
+ .handler = zpci_floating_irq_handler,
+ .isc = PCI_ISC,
+};
+
+static void zpci_msi_teardown_directed(struct zpci_dev *zdev)
+{
+ airq_iv_free(zpci_ibv[0], zdev->msi_first_bit, zdev->max_msi);
+ zdev->msi_first_bit = -1U;
+ zdev->msi_nr_irqs = 0;
+}
+
+static void zpci_msi_teardown_floating(struct zpci_dev *zdev)
+{
+ airq_iv_release(zdev->aibv);
+ zdev->aibv = NULL;
+ airq_iv_free_bit(zpci_sbv, zdev->aisb);
zdev->aisb = -1UL;
zdev->msi_first_bit = -1U;
+ zdev->msi_nr_irqs = 0;
+}
+
+static void zpci_msi_teardown(struct irq_domain *domain, msi_alloc_info_t *arg)
+{
+ struct zpci_dev *zdev = to_zpci_dev(domain->dev);
+
+ zpci_clear_irq(zdev);
+ if (irq_delivery == DIRECTED)
+ zpci_msi_teardown_directed(zdev);
+ else
+ zpci_msi_teardown_floating(zdev);
+}
+
+static int zpci_msi_prepare(struct irq_domain *domain,
+ struct device *dev, int nvec,
+ msi_alloc_info_t *info)
+{
+ struct zpci_dev *zdev = to_zpci_dev(dev);
+ struct pci_dev *pdev = to_pci_dev(dev);
+ unsigned long bit;
+ int msi_vecs, rc;
msi_vecs = min_t(unsigned int, nvec, zdev->max_msi);
if (msi_vecs < nvec) {
- pr_info("%s requested %d irqs, allocate system limit of %d",
+ pr_info("%s requested %d IRQs, allocate system limit of %d\n",
pci_name(pdev), nvec, zdev->max_msi);
}
rc = __alloc_airq(zdev, msi_vecs, &bit);
- if (rc < 0)
+ if (rc) {
+ pr_err("Allocating adapter IRQs for %s failed\n", pci_name(pdev));
return rc;
+ }
- /*
- * Request MSI interrupts:
- * When using MSI, nvec_used interrupt sources and their irq
- * descriptors are controlled through one msi descriptor.
- * Thus the outer loop over msi descriptors shall run only once,
- * while two inner loops iterate over the interrupt vectors.
- * When using MSI-X, each interrupt vector/irq descriptor
- * is bound to exactly one msi descriptor (nvec_used is one).
- * So the inner loops are executed once, while the outer iterates
- * over the MSI-X descriptors.
- */
- hwirq = bit;
- msi_for_each_desc(msi, &pdev->dev, MSI_DESC_NOTASSOCIATED) {
- if (hwirq - bit >= msi_vecs)
- break;
- irqs_per_msi = min_t(unsigned int, msi_vecs, msi->nvec_used);
- irq = __irq_alloc_descs(-1, 0, irqs_per_msi, 0, THIS_MODULE,
- (irq_delivery == DIRECTED) ?
- msi->affinity : NULL);
- if (irq < 0)
- return -ENOMEM;
+ zdev->msi_first_bit = bit;
+ zdev->msi_nr_irqs = msi_vecs;
+ rc = zpci_set_irq(zdev);
+ if (rc) {
+ pr_err("Registering adapter IRQs for %s failed\n",
+ pci_name(pdev));
+
+ if (irq_delivery == DIRECTED)
+ zpci_msi_teardown_directed(zdev);
+ else
+ zpci_msi_teardown_floating(zdev);
+ return rc;
+ }
+ return 0;
+}
- for (i = 0; i < irqs_per_msi; i++) {
- rc = irq_set_msi_desc_off(irq, i, msi);
- if (rc)
- return rc;
- irq_set_chip_and_handler(irq + i, &zpci_irq_chip,
- handle_percpu_irq);
- }
+static int zpci_msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs, void *args)
+{
+ struct msi_desc *desc = ((msi_alloc_info_t *)args)->desc;
+ struct zpci_dev *zdev = to_zpci_dev(desc->dev);
+ struct zpci_bus *zbus = zdev->zbus;
+ unsigned int cpu, hwirq;
+ unsigned long bit;
+ int i;
- msg.data = hwirq - bit;
- if (irq_delivery == DIRECTED) {
- if (msi->affinity)
- cpu = cpumask_first(&msi->affinity->mask);
- else
- cpu = 0;
- cpu_addr = smp_cpu_get_cpu_address(cpu);
+ bit = zdev->msi_first_bit + desc->msi_index;
+ hwirq = zpci_encode_hwirq(zdev->devfn, desc->msi_index);
- msg.address_lo = zdev->msi_addr & 0xff0000ff;
- msg.address_lo |= (cpu_addr << 8);
+ if (desc->msi_index + nr_irqs > zdev->max_msi)
+ return -EINVAL;
+ for (i = 0; i < nr_irqs; i++) {
+ irq_domain_set_info(domain, virq + i, hwirq + i,
+ &zpci_irq_chip, zdev,
+ handle_percpu_irq, NULL, NULL);
+
+ if (irq_delivery == DIRECTED) {
for_each_possible_cpu(cpu) {
- for (i = 0; i < irqs_per_msi; i++)
- airq_iv_set_data(zpci_ibv[cpu],
- hwirq + i, irq + i);
+ airq_iv_set_ptr(zpci_ibv[cpu], bit + i,
+ (unsigned long)zbus->msi_parent_domain);
+ airq_iv_set_data(zpci_ibv[cpu], bit + i, hwirq + i);
}
} else {
- msg.address_lo = zdev->msi_addr & 0xffffffff;
- for (i = 0; i < irqs_per_msi; i++)
- airq_iv_set_data(zdev->aibv, hwirq + i, irq + i);
+ airq_iv_set_ptr(zdev->aibv, bit + i,
+ (unsigned long)zbus->msi_parent_domain);
+ airq_iv_set_data(zdev->aibv, bit + i, hwirq + i);
}
- msg.address_hi = zdev->msi_addr >> 32;
- pci_write_msi_msg(irq, &msg);
- hwirq += irqs_per_msi;
}
- zdev->msi_first_bit = bit;
- zdev->msi_nr_irqs = hwirq - bit;
-
- rc = zpci_set_irq(zdev);
- if (rc)
- return rc;
-
- return (zdev->msi_nr_irqs == nvec) ? 0 : zdev->msi_nr_irqs;
+ return 0;
}
-void arch_teardown_msi_irqs(struct pci_dev *pdev)
+static void zpci_msi_clear_airq(struct irq_data *d, int i)
{
- struct zpci_dev *zdev = to_zpci(pdev);
- struct msi_desc *msi;
- unsigned int i;
- int rc;
+ struct msi_desc *desc = irq_data_get_msi_desc(d);
+ struct zpci_dev *zdev = to_zpci_dev(desc->dev);
+ unsigned long bit;
+ unsigned int cpu;
+ u16 msi_index;
- /* Disable interrupts */
- rc = zpci_clear_irq(zdev);
- if (rc)
- return;
+ msi_index = zpci_decode_hwirq_msi_index(d->hwirq);
+ bit = zdev->msi_first_bit + msi_index;
- /* Release MSI interrupts */
- msi_for_each_desc(msi, &pdev->dev, MSI_DESC_ASSOCIATED) {
- for (i = 0; i < msi->nvec_used; i++) {
- irq_set_msi_desc(msi->irq + i, NULL);
- irq_free_desc(msi->irq + i);
+ if (irq_delivery == DIRECTED) {
+ for_each_possible_cpu(cpu) {
+ airq_iv_set_ptr(zpci_ibv[cpu], bit + i, 0);
+ airq_iv_set_data(zpci_ibv[cpu], bit + i, 0);
}
- msi->msg.address_lo = 0;
- msi->msg.address_hi = 0;
- msi->msg.data = 0;
- msi->irq = 0;
+ } else {
+ airq_iv_set_ptr(zdev->aibv, bit + i, 0);
+ airq_iv_set_data(zdev->aibv, bit + i, 0);
}
+}
- if (zdev->aisb != -1UL) {
- zpci_ibv[zdev->aisb] = NULL;
- airq_iv_free_bit(zpci_sbv, zdev->aisb);
- zdev->aisb = -1UL;
- }
- if (zdev->aibv) {
- airq_iv_release(zdev->aibv);
- zdev->aibv = NULL;
- }
+static void zpci_msi_domain_free(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs)
+{
+ struct irq_data *d;
+ int i;
- if ((irq_delivery == DIRECTED) && zdev->msi_first_bit != -1U)
- airq_iv_free(zpci_ibv[0], zdev->msi_first_bit, zdev->msi_nr_irqs);
+ for (i = 0; i < nr_irqs; i++) {
+ d = irq_domain_get_irq_data(domain, virq + i);
+ zpci_msi_clear_airq(d, i);
+ irq_domain_reset_irq_data(d);
+ }
}
-bool arch_restore_msi_irqs(struct pci_dev *pdev)
+static const struct irq_domain_ops zpci_msi_domain_ops = {
+ .alloc = zpci_msi_domain_alloc,
+ .free = zpci_msi_domain_free,
+};
+
+static bool zpci_init_dev_msi_info(struct device *dev, struct irq_domain *domain,
+ struct irq_domain *real_parent,
+ struct msi_domain_info *info)
{
- struct zpci_dev *zdev = to_zpci(pdev);
+ if (!msi_lib_init_dev_msi_info(dev, domain, real_parent, info))
+ return false;
+
+ info->ops->msi_prepare = zpci_msi_prepare;
+ info->ops->msi_teardown = zpci_msi_teardown;
- zpci_set_irq(zdev);
return true;
}
-static struct airq_struct zpci_airq = {
- .handler = zpci_floating_irq_handler,
- .isc = PCI_ISC,
+static struct msi_parent_ops zpci_msi_parent_ops = {
+ .supported_flags = MSI_GENERIC_FLAGS_MASK |
+ MSI_FLAG_PCI_MSIX |
+ MSI_FLAG_MULTI_PCI_MSI,
+ .required_flags = MSI_FLAG_USE_DEF_DOM_OPS |
+ MSI_FLAG_USE_DEF_CHIP_OPS,
+ .init_dev_msi_info = zpci_init_dev_msi_info,
};
+int zpci_create_parent_msi_domain(struct zpci_bus *zbus)
+{
+ char fwnode_name[18];
+
+ snprintf(fwnode_name, sizeof(fwnode_name), "ZPCI_MSI_DOM_%04x", zbus->domain_nr);
+ struct irq_domain_info info = {
+ .fwnode = irq_domain_alloc_named_fwnode(fwnode_name),
+ .ops = &zpci_msi_domain_ops,
+ };
+
+ if (!info.fwnode) {
+ pr_err("Failed to allocate fwnode for MSI IRQ domain\n");
+ return -ENOMEM;
+ }
+
+ if (irq_delivery == FLOATING)
+ zpci_msi_parent_ops.required_flags |= MSI_FLAG_NO_AFFINITY;
+
+ zbus->msi_parent_domain = msi_create_parent_irq_domain(&info, &zpci_msi_parent_ops);
+ if (!zbus->msi_parent_domain) {
+ irq_domain_free_fwnode(info.fwnode);
+ pr_err("Failed to create MSI IRQ domain\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void zpci_remove_parent_msi_domain(struct zpci_bus *zbus)
+{
+ struct fwnode_handle *fn;
+
+ fn = zbus->msi_parent_domain->fwnode;
+ irq_domain_remove(zbus->msi_parent_domain);
+ irq_domain_free_fwnode(fn);
+}
+
static void __init cpu_enable_directed_irq(void *unused)
{
union zpci_sic_iib iib = {{0}};
@@ -465,6 +574,7 @@ static int __init zpci_directed_irq_init(void)
* is only done on the first vector.
*/
zpci_ibv[cpu] = airq_iv_create(cache_line_size() * BITS_PER_BYTE,
+ AIRQ_IV_PTR |
AIRQ_IV_DATA |
AIRQ_IV_CACHELINE |
(!cpu ? AIRQ_IV_ALLOC : 0), NULL);
diff --git a/arch/sh/configs/edosk7760_defconfig b/arch/sh/configs/edosk7760_defconfig
index abeae220606a..905fac107284 100644
--- a/arch/sh/configs/edosk7760_defconfig
+++ b/arch/sh/configs/edosk7760_defconfig
@@ -79,7 +79,6 @@ CONFIG_FB_TILEBLITTING=y
CONFIG_FB_SH_MOBILE_LCDC=m
CONFIG_SOUND=y
CONFIG_SND=y
-# CONFIG_SND_SUPPORT_OLD_API is not set
# CONFIG_SND_VERBOSE_PROCFS is not set
CONFIG_SND_VERBOSE_PRINTK=y
CONFIG_SND_SOC=y
diff --git a/arch/sh/configs/se7724_defconfig b/arch/sh/configs/se7724_defconfig
index 9e3a54936f76..8ca46d704c8b 100644
--- a/arch/sh/configs/se7724_defconfig
+++ b/arch/sh/configs/se7724_defconfig
@@ -83,7 +83,6 @@ CONFIG_LOGO=y
# CONFIG_LOGO_SUPERH_VGA16 is not set
CONFIG_SOUND=y
CONFIG_SND=m
-# CONFIG_SND_SUPPORT_OLD_API is not set
# CONFIG_SND_DRIVERS is not set
# CONFIG_SND_SPI is not set
# CONFIG_SND_SUPERH is not set
diff --git a/arch/sh/configs/sh7785lcr_32bit_defconfig b/arch/sh/configs/sh7785lcr_32bit_defconfig
index eb63aa61b046..5468cc53cddb 100644
--- a/arch/sh/configs/sh7785lcr_32bit_defconfig
+++ b/arch/sh/configs/sh7785lcr_32bit_defconfig
@@ -93,7 +93,6 @@ CONFIG_SND_PCM_OSS=y
CONFIG_SND_SEQUENCER_OSS=y
CONFIG_SND_HRTIMER=y
CONFIG_SND_DYNAMIC_MINORS=y
-# CONFIG_SND_SUPPORT_OLD_API is not set
# CONFIG_SND_VERBOSE_PROCFS is not set
CONFIG_SND_VERBOSE_PRINTK=y
CONFIG_SND_DEBUG=y
diff --git a/block/bio.c b/block/bio.c
index fa5ff36b443f..e726c0e280a8 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -321,9 +321,13 @@ static struct bio *__bio_chain_endio(struct bio *bio)
return parent;
}
+/*
+ * This function should only be used as a flag and must never be called.
+ * If execution reaches here, it indicates a serious programming error.
+ */
static void bio_chain_endio(struct bio *bio)
{
- bio_endio(__bio_chain_endio(bio));
+ BUG();
}
/**
diff --git a/block/blk-mq-dma.c b/block/blk-mq-dma.c
index b6dbc9767596..fb018fffffdc 100644
--- a/block/blk-mq-dma.c
+++ b/block/blk-mq-dma.c
@@ -199,6 +199,7 @@ static bool blk_dma_map_iter_start(struct request *req, struct device *dma_dev,
if (blk_can_dma_map_iova(req, dma_dev) &&
dma_iova_try_alloc(dma_dev, state, vec.paddr, total_len))
return blk_rq_dma_map_iova(req, dma_dev, state, iter, &vec);
+ memset(state, 0, sizeof(*state));
return blk_dma_map_direct(req, dma_dev, iter, &vec);
}
diff --git a/block/blk-mq.c b/block/blk-mq.c
index bd8b11c472a2..1978eef95dca 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -336,12 +336,12 @@ void blk_mq_quiesce_tagset(struct blk_mq_tag_set *set)
{
struct request_queue *q;
- mutex_lock(&set->tag_list_lock);
- list_for_each_entry(q, &set->tag_list, tag_set_list) {
+ rcu_read_lock();
+ list_for_each_entry_rcu(q, &set->tag_list, tag_set_list) {
if (!blk_queue_skip_tagset_quiesce(q))
blk_mq_quiesce_queue_nowait(q);
}
- mutex_unlock(&set->tag_list_lock);
+ rcu_read_unlock();
blk_mq_wait_quiesce_done(set);
}
@@ -351,12 +351,12 @@ void blk_mq_unquiesce_tagset(struct blk_mq_tag_set *set)
{
struct request_queue *q;
- mutex_lock(&set->tag_list_lock);
- list_for_each_entry(q, &set->tag_list, tag_set_list) {
+ rcu_read_lock();
+ list_for_each_entry_rcu(q, &set->tag_list, tag_set_list) {
if (!blk_queue_skip_tagset_quiesce(q))
blk_mq_unquiesce_queue(q);
}
- mutex_unlock(&set->tag_list_lock);
+ rcu_read_unlock();
}
EXPORT_SYMBOL_GPL(blk_mq_unquiesce_tagset);
@@ -4311,7 +4311,7 @@ static void blk_mq_del_queue_tag_set(struct request_queue *q)
struct blk_mq_tag_set *set = q->tag_set;
mutex_lock(&set->tag_list_lock);
- list_del(&q->tag_set_list);
+ list_del_rcu(&q->tag_set_list);
if (list_is_singular(&set->tag_list)) {
/* just transitioned to unshared */
set->flags &= ~BLK_MQ_F_TAG_QUEUE_SHARED;
@@ -4319,7 +4319,6 @@ static void blk_mq_del_queue_tag_set(struct request_queue *q)
blk_mq_update_tag_set_shared(set, false);
}
mutex_unlock(&set->tag_list_lock);
- INIT_LIST_HEAD(&q->tag_set_list);
}
static void blk_mq_add_queue_tag_set(struct blk_mq_tag_set *set,
@@ -4338,7 +4337,7 @@ static void blk_mq_add_queue_tag_set(struct blk_mq_tag_set *set,
}
if (set->flags & BLK_MQ_F_TAG_QUEUE_SHARED)
queue_set_hctx_shared(q, true);
- list_add_tail(&q->tag_set_list, &set->tag_list);
+ list_add_tail_rcu(&q->tag_set_list, &set->tag_list);
mutex_unlock(&set->tag_list_lock);
}
@@ -5193,27 +5192,19 @@ EXPORT_SYMBOL_GPL(blk_mq_update_nr_hw_queues);
static int blk_hctx_poll(struct request_queue *q, struct blk_mq_hw_ctx *hctx,
struct io_comp_batch *iob, unsigned int flags)
{
- long state = get_current_state();
int ret;
do {
ret = q->mq_ops->poll(hctx, iob);
- if (ret > 0) {
- __set_current_state(TASK_RUNNING);
+ if (ret > 0)
return ret;
- }
-
- if (signal_pending_state(state, current))
- __set_current_state(TASK_RUNNING);
- if (task_is_running(current))
+ if (task_sigpending(current))
return 1;
-
if (ret < 0 || (flags & BLK_POLL_ONESHOT))
break;
cpu_relax();
} while (!need_resched());
- __set_current_state(TASK_RUNNING);
return 0;
}
diff --git a/block/blk-zoned.c b/block/blk-zoned.c
index 394d8d74bba9..1c54678fae6b 100644
--- a/block/blk-zoned.c
+++ b/block/blk-zoned.c
@@ -2100,7 +2100,7 @@ static int blk_revalidate_seq_zone(struct blk_zone *zone, unsigned int idx,
* we have a zone write plug for such zone if the device has a zone
* write plug hash table.
*/
- if (!queue_emulates_zone_append(disk->queue) || !disk->zone_wplugs_hash)
+ if (!disk->zone_wplugs_hash)
return 0;
wp_offset = disk_zone_wplug_sync_wp_offset(disk, zone);
diff --git a/drivers/acpi/platform_profile.c b/drivers/acpi/platform_profile.c
index b43f4459a4f6..ea04a8c69215 100644
--- a/drivers/acpi/platform_profile.c
+++ b/drivers/acpi/platform_profile.c
@@ -37,6 +37,7 @@ static const char * const profile_names[] = {
[PLATFORM_PROFILE_BALANCED] = "balanced",
[PLATFORM_PROFILE_BALANCED_PERFORMANCE] = "balanced-performance",
[PLATFORM_PROFILE_PERFORMANCE] = "performance",
+ [PLATFORM_PROFILE_MAX_POWER] = "max-power",
[PLATFORM_PROFILE_CUSTOM] = "custom",
};
static_assert(ARRAY_SIZE(profile_names) == PLATFORM_PROFILE_LAST);
@@ -506,7 +507,8 @@ int platform_profile_cycle(void)
if (err)
return err;
- if (profile == PLATFORM_PROFILE_CUSTOM ||
+ if (profile == PLATFORM_PROFILE_MAX_POWER ||
+ profile == PLATFORM_PROFILE_CUSTOM ||
profile == PLATFORM_PROFILE_LAST)
return -EINVAL;
@@ -515,7 +517,8 @@ int platform_profile_cycle(void)
if (err)
return err;
- /* never iterate into a custom if all drivers supported it */
+ /* never iterate into a custom or max power if all drivers supported it */
+ clear_bit(PLATFORM_PROFILE_MAX_POWER, data.aggregate);
clear_bit(PLATFORM_PROFILE_CUSTOM, data.aggregate);
next = find_next_bit_wrap(data.aggregate,
diff --git a/drivers/base/power/runtime-test.c b/drivers/base/power/runtime-test.c
index 477feca804c7..1535ad2b0264 100644
--- a/drivers/base/power/runtime-test.c
+++ b/drivers/base/power/runtime-test.c
@@ -38,10 +38,6 @@ static void pm_runtime_already_suspended_test(struct kunit *test)
KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev));
pm_runtime_get_noresume(dev);
- KUNIT_EXPECT_EQ(test, 0, pm_runtime_barrier(dev)); /* no wakeup needed */
- pm_runtime_put(dev);
-
- pm_runtime_get_noresume(dev);
KUNIT_EXPECT_EQ(test, 1, pm_runtime_put_sync(dev));
KUNIT_EXPECT_EQ(test, 1, pm_runtime_suspend(dev));
@@ -174,7 +170,7 @@ static void pm_runtime_error_test(struct kunit *test)
KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev));
KUNIT_EXPECT_EQ(test, 0, pm_runtime_get(dev));
- KUNIT_EXPECT_EQ(test, 1, pm_runtime_barrier(dev)); /* resume was pending */
+ pm_runtime_barrier(dev);
pm_runtime_put(dev);
pm_runtime_suspend(dev); /* flush the put(), to suspend */
KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev));
@@ -225,7 +221,7 @@ static void pm_runtime_probe_active_test(struct kunit *test)
KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev));
/* Nothing to flush. We stay active. */
- KUNIT_EXPECT_EQ(test, 0, pm_runtime_barrier(dev));
+ pm_runtime_barrier(dev);
KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev));
/* Ask for idle? Now we suspend. */
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 62707738caa4..84676cc24221 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -1467,30 +1467,20 @@ static void __pm_runtime_barrier(struct device *dev)
* Next, make sure that all pending requests for the device have been flushed
* from pm_wq and wait for all runtime PM operations involving the device in
* progress to complete.
- *
- * Return value:
- * 1, if there was a resume request pending and the device had to be woken up,
- * 0, otherwise
*/
-int pm_runtime_barrier(struct device *dev)
+void pm_runtime_barrier(struct device *dev)
{
- int retval = 0;
-
pm_runtime_get_noresume(dev);
spin_lock_irq(&dev->power.lock);
if (dev->power.request_pending
- && dev->power.request == RPM_REQ_RESUME) {
+ && dev->power.request == RPM_REQ_RESUME)
rpm_resume(dev, 0);
- retval = 1;
- }
__pm_runtime_barrier(dev);
spin_unlock_irq(&dev->power.lock);
pm_runtime_put_noidle(dev);
-
- return retval;
}
EXPORT_SYMBOL_GPL(pm_runtime_barrier);
diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
index 2c715df63f23..df9831783a13 100644
--- a/drivers/block/ublk_drv.c
+++ b/drivers/block/ublk_drv.c
@@ -926,6 +926,7 @@ static size_t ublk_copy_user_pages(const struct request *req,
size_t done = 0;
rq_for_each_segment(bv, req, iter) {
+ unsigned len;
void *bv_buf;
size_t copied;
@@ -934,18 +935,17 @@ static size_t ublk_copy_user_pages(const struct request *req,
continue;
}
- bv.bv_offset += offset;
- bv.bv_len -= offset;
- bv_buf = bvec_kmap_local(&bv);
+ len = bv.bv_len - offset;
+ bv_buf = kmap_local_page(bv.bv_page) + bv.bv_offset + offset;
if (dir == ITER_DEST)
- copied = copy_to_iter(bv_buf, bv.bv_len, uiter);
+ copied = copy_to_iter(bv_buf, len, uiter);
else
- copied = copy_from_iter(bv_buf, bv.bv_len, uiter);
+ copied = copy_from_iter(bv_buf, len, uiter);
kunmap_local(bv_buf);
done += copied;
- if (copied < bv.bv_len)
+ if (copied < len)
break;
offset = 0;
@@ -3673,6 +3673,19 @@ exit:
return ret;
}
+static bool ublk_ctrl_uring_cmd_may_sleep(u32 cmd_op)
+{
+ switch (_IOC_NR(cmd_op)) {
+ case UBLK_CMD_GET_QUEUE_AFFINITY:
+ case UBLK_CMD_GET_DEV_INFO:
+ case UBLK_CMD_GET_DEV_INFO2:
+ case _IOC_NR(UBLK_U_CMD_GET_FEATURES):
+ return false;
+ default:
+ return true;
+ }
+}
+
static int ublk_ctrl_uring_cmd(struct io_uring_cmd *cmd,
unsigned int issue_flags)
{
@@ -3681,7 +3694,8 @@ static int ublk_ctrl_uring_cmd(struct io_uring_cmd *cmd,
u32 cmd_op = cmd->cmd_op;
int ret = -EINVAL;
- if (issue_flags & IO_URING_F_NONBLOCK)
+ if (ublk_ctrl_uring_cmd_may_sleep(cmd_op) &&
+ issue_flags & IO_URING_F_NONBLOCK)
return -EAGAIN;
ublk_ctrl_cmd_dump(cmd);
diff --git a/drivers/firmware/efi/libstub/loongarch.c b/drivers/firmware/efi/libstub/loongarch.c
index 3782d0a187d1..9825f5218137 100644
--- a/drivers/firmware/efi/libstub/loongarch.c
+++ b/drivers/firmware/efi/libstub/loongarch.c
@@ -72,10 +72,10 @@ efi_status_t efi_boot_kernel(void *handle, efi_loaded_image_t *image,
desc_ver, priv.runtime_map);
/* Config Direct Mapping */
- csr_write64(CSR_DMW0_INIT, LOONGARCH_CSR_DMWIN0);
- csr_write64(CSR_DMW1_INIT, LOONGARCH_CSR_DMWIN1);
- csr_write64(CSR_DMW2_INIT, LOONGARCH_CSR_DMWIN2);
- csr_write64(CSR_DMW3_INIT, LOONGARCH_CSR_DMWIN3);
+ csr_write(CSR_DMW0_INIT, LOONGARCH_CSR_DMWIN0);
+ csr_write(CSR_DMW1_INIT, LOONGARCH_CSR_DMWIN1);
+ csr_write(CSR_DMW2_INIT, LOONGARCH_CSR_DMWIN2);
+ csr_write(CSR_DMW3_INIT, LOONGARCH_CSR_DMWIN3);
real_kernel_entry = (void *)kernel_entry_address(kernel_addr, image);
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index c74da29253e8..bd185482a7fd 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -737,7 +737,6 @@ config GPIO_TB10X
depends on ARC_PLAT_TB10X || COMPILE_TEST
select GPIO_GENERIC
select GENERIC_IRQ_CHIP
- select OF_GPIO
config GPIO_TEGRA
tristate "NVIDIA Tegra GPIO support"
@@ -1568,6 +1567,7 @@ config GPIO_QIXIS_FPGA
tristate "NXP QIXIS FPGA GPIO support"
depends on MFD_SIMPLE_MFD_I2C || COMPILE_TEST
select GPIO_REGMAP
+ select REGMAP_MMIO
help
This enables support for the GPIOs found in the QIXIS FPGA which is
integrated on some NXP Layerscape boards such as LX2160ARDB and
diff --git a/drivers/gpio/gpio-mmio.c b/drivers/gpio/gpio-mmio.c
index b3a26a06260b..5daf962b0323 100644
--- a/drivers/gpio/gpio-mmio.c
+++ b/drivers/gpio/gpio-mmio.c
@@ -231,7 +231,7 @@ static int gpio_mmio_set(struct gpio_chip *gc, unsigned int gpio, int val)
struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
unsigned long mask = gpio_mmio_line2mask(gc, gpio);
- guard(raw_spinlock)(&chip->lock);
+ guard(raw_spinlock_irqsave)(&chip->lock);
if (val)
chip->sdata |= mask;
@@ -262,7 +262,7 @@ static int gpio_mmio_set_set(struct gpio_chip *gc, unsigned int gpio, int val)
struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
unsigned long mask = gpio_mmio_line2mask(gc, gpio);
- guard(raw_spinlock)(&chip->lock);
+ guard(raw_spinlock_irqsave)(&chip->lock);
if (val)
chip->sdata |= mask;
@@ -302,7 +302,7 @@ static void gpio_mmio_set_multiple_single_reg(struct gpio_chip *gc,
struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
unsigned long set_mask, clear_mask;
- guard(raw_spinlock)(&chip->lock);
+ guard(raw_spinlock_irqsave)(&chip->lock);
gpio_mmio_multiple_get_masks(gc, mask, bits, &set_mask, &clear_mask);
@@ -391,7 +391,7 @@ static int gpio_mmio_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
- scoped_guard(raw_spinlock, &chip->lock) {
+ scoped_guard(raw_spinlock_irqsave, &chip->lock) {
chip->sdir &= ~gpio_mmio_line2mask(gc, gpio);
if (chip->reg_dir_in)
@@ -431,7 +431,7 @@ static void gpio_mmio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
- guard(raw_spinlock)(&chip->lock);
+ guard(raw_spinlock_irqsave)(&chip->lock);
chip->sdir |= gpio_mmio_line2mask(gc, gpio);
diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c
index e5ba38e65c10..9581bd5ca947 100644
--- a/drivers/gpio/gpio-regmap.c
+++ b/drivers/gpio/gpio-regmap.c
@@ -338,7 +338,7 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
config->regmap_irq_line, config->regmap_irq_flags,
0, config->regmap_irq_chip, &gpio->irq_chip_data);
if (ret)
- goto err_free_bitmap;
+ goto err_remove_gpiochip;
irq_domain = regmap_irq_get_domain(gpio->irq_chip_data);
} else
diff --git a/drivers/gpio/gpiolib-acpi-quirks.c b/drivers/gpio/gpiolib-acpi-quirks.c
index 7b95d1b03361..a0116f004975 100644
--- a/drivers/gpio/gpiolib-acpi-quirks.c
+++ b/drivers/gpio/gpiolib-acpi-quirks.c
@@ -370,6 +370,28 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] __initconst = {
.ignore_wake = "ASCP1A00:00@8",
},
},
+ {
+ /*
+ * Spurious wakeups, likely from touchpad controller
+ * Dell Precision 7780
+ * Found in BIOS 1.24.1
+ *
+ * Found in touchpad firmware, installed by Dell Touchpad Firmware Update Utility version 1160.4196.9, A01
+ * ( Dell-Touchpad-Firmware-Update-Utility_VYGNN_WIN64_1160.4196.9_A00.EXE ),
+ * released on 11 Jul 2024
+ *
+ * https://lore.kernel.org/linux-i2c/197ae95ffd8.dc819e60457077.7692120488609091556@zohomail.com/
+ */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_FAMILY, "Precision"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Precision 7780"),
+ DMI_MATCH(DMI_BOARD_NAME, "0C6JVW"),
+ },
+ .driver_data = &(struct acpi_gpiolib_dmi_quirk) {
+ .ignore_wake = "VEN_0488:00@355",
+ },
+ },
{} /* Terminating entry */
};
diff --git a/drivers/gpio/gpiolib-shared.c b/drivers/gpio/gpiolib-shared.c
index 8bdd107b1ad1..ba4b718d40a0 100644
--- a/drivers/gpio/gpiolib-shared.c
+++ b/drivers/gpio/gpiolib-shared.c
@@ -36,6 +36,8 @@ struct gpio_shared_ref {
enum gpiod_flags flags;
char *con_id;
int dev_id;
+ /* Protects the auxiliary device struct and the lookup table. */
+ struct mutex lock;
struct auxiliary_device adev;
struct gpiod_lookup_table *lookup;
};
@@ -49,6 +51,7 @@ struct gpio_shared_entry {
unsigned int offset;
/* Index in the property value array. */
size_t index;
+ /* Synchronizes the modification of shared_desc. */
struct mutex lock;
struct gpio_shared_desc *shared_desc;
struct kref ref;
@@ -56,7 +59,6 @@ struct gpio_shared_entry {
};
static LIST_HEAD(gpio_shared_list);
-static DEFINE_MUTEX(gpio_shared_lock);
static DEFINE_IDA(gpio_shared_ida);
#if IS_ENABLED(CONFIG_OF)
@@ -77,6 +79,10 @@ gpio_shared_find_entry(struct fwnode_handle *controller_node,
/* Handle all special nodes that we should ignore. */
static bool gpio_shared_of_node_ignore(struct device_node *node)
{
+ /* Ignore disabled devices. */
+ if (!of_device_is_available(node))
+ return true;
+
/*
* __symbols__ is a special, internal node and should not be considered
* when scanning for shared GPIOs.
@@ -183,6 +189,7 @@ static int gpio_shared_of_traverse(struct device_node *curr)
ref->fwnode = fwnode_handle_get(of_fwnode_handle(curr));
ref->flags = args.args[1];
+ mutex_init(&ref->lock);
if (strends(prop->name, "gpios"))
suffix = "-gpios";
@@ -254,7 +261,7 @@ static int gpio_shared_make_adev(struct gpio_device *gdev,
struct auxiliary_device *adev = &ref->adev;
int ret;
- lockdep_assert_held(&gpio_shared_lock);
+ guard(mutex)(&ref->lock);
memset(adev, 0, sizeof(*adev));
@@ -369,14 +376,14 @@ int gpio_shared_add_proxy_lookup(struct device *consumer, unsigned long lflags)
if (!lookup)
return -ENOMEM;
- guard(mutex)(&gpio_shared_lock);
-
list_for_each_entry(entry, &gpio_shared_list, list) {
list_for_each_entry(ref, &entry->refs, list) {
if (!device_match_fwnode(consumer, ref->fwnode) &&
!gpio_shared_dev_is_reset_gpio(consumer, entry, ref))
continue;
+ guard(mutex)(&ref->lock);
+
/* We've already done that on a previous request. */
if (ref->lookup)
return 0;
@@ -395,7 +402,8 @@ int gpio_shared_add_proxy_lookup(struct device *consumer, unsigned long lflags)
lookup->table[0] = GPIO_LOOKUP(no_free_ptr(key), 0,
ref->con_id, lflags);
- gpiod_add_lookup_table(no_free_ptr(lookup));
+ ref->lookup = no_free_ptr(lookup);
+ gpiod_add_lookup_table(ref->lookup);
return 0;
}
@@ -408,10 +416,8 @@ int gpio_shared_add_proxy_lookup(struct device *consumer, unsigned long lflags)
static void gpio_shared_remove_adev(struct auxiliary_device *adev)
{
- lockdep_assert_held(&gpio_shared_lock);
-
- auxiliary_device_uninit(adev);
auxiliary_device_delete(adev);
+ auxiliary_device_uninit(adev);
}
int gpio_device_setup_shared(struct gpio_device *gdev)
@@ -421,8 +427,6 @@ int gpio_device_setup_shared(struct gpio_device *gdev)
unsigned long *flags;
int ret;
- guard(mutex)(&gpio_shared_lock);
-
list_for_each_entry(entry, &gpio_shared_list, list) {
list_for_each_entry(ref, &entry->refs, list) {
if (gdev->dev.parent == &ref->adev.dev) {
@@ -479,19 +483,32 @@ void gpio_device_teardown_shared(struct gpio_device *gdev)
struct gpio_shared_entry *entry;
struct gpio_shared_ref *ref;
- guard(mutex)(&gpio_shared_lock);
-
list_for_each_entry(entry, &gpio_shared_list, list) {
if (!device_match_fwnode(&gdev->dev, entry->fwnode))
continue;
+ /*
+ * For some reason if we call synchronize_srcu() in GPIO core,
+ * descent here and take this mutex and then recursively call
+ * synchronize_srcu() again from gpiochip_remove() (which is
+ * totally fine) called after gpio_shared_remove_adev(),
+ * lockdep prints a false positive deadlock splat. Disable
+ * lockdep here.
+ */
+ lockdep_off();
list_for_each_entry(ref, &entry->refs, list) {
- gpiod_remove_lookup_table(ref->lookup);
- kfree(ref->lookup->table[0].key);
- kfree(ref->lookup);
- ref->lookup = NULL;
+ guard(mutex)(&ref->lock);
+
+ if (ref->lookup) {
+ gpiod_remove_lookup_table(ref->lookup);
+ kfree(ref->lookup->table[0].key);
+ kfree(ref->lookup);
+ ref->lookup = NULL;
+ }
+
gpio_shared_remove_adev(&ref->adev);
}
+ lockdep_on();
}
}
@@ -515,8 +532,6 @@ static void gpiod_shared_put(void *data)
{
struct gpio_shared_entry *entry = data;
- lockdep_assert_not_held(&gpio_shared_lock);
-
kref_put(&entry->ref, gpio_shared_release);
}
@@ -554,8 +569,6 @@ struct gpio_shared_desc *devm_gpiod_shared_get(struct device *dev)
struct gpio_shared_entry *entry;
int ret;
- lockdep_assert_not_held(&gpio_shared_lock);
-
entry = dev_get_platdata(dev);
if (WARN_ON(!entry))
/* Programmer bug */
@@ -590,6 +603,7 @@ EXPORT_SYMBOL_GPL(devm_gpiod_shared_get);
static void gpio_shared_drop_ref(struct gpio_shared_ref *ref)
{
list_del(&ref->list);
+ mutex_destroy(&ref->lock);
kfree(ref->con_id);
ida_free(&gpio_shared_ida, ref->dev_id);
fwnode_handle_put(ref->fwnode);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
index a67285118c37..c362d4dfb5bb 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
@@ -1069,7 +1069,9 @@ amdgpu_vm_tlb_flush(struct amdgpu_vm_update_params *params,
}
/* Prepare a TLB flush fence to be attached to PTs */
- if (!params->unlocked) {
+ if (!params->unlocked &&
+ /* SI doesn't support pasid or KIQ/MES */
+ params->adev->family > AMDGPU_FAMILY_SI) {
amdgpu_vm_tlb_fence_create(params->adev, vm, fence);
/* Makes sure no PD/PT is freed before the flush */
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
index b107ee80e472..1f6a22983c0d 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
@@ -265,6 +265,8 @@ static int vcn_v4_0_5_sw_fini(struct amdgpu_ip_block *ip_block)
if (amdgpu_sriov_vf(adev))
amdgpu_virt_free_mm_table(adev);
+ amdgpu_vcn_sysfs_reset_mask_fini(adev);
+
for (i = 0; i < adev->vcn.num_vcn_inst; i++) {
r = amdgpu_vcn_suspend(adev, i);
if (r)
diff --git a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h
index 0320163b6e74..f98c735b2905 100644
--- a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h
+++ b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h
@@ -3644,14 +3644,18 @@ static const uint32_t cwsr_trap_gfx9_4_3_hex[] = {
};
static const uint32_t cwsr_trap_gfx12_hex[] = {
- 0xbfa00001, 0xbfa002a2,
- 0xb0804009, 0xb8f8f804,
+ 0xbfa00001, 0xbfa002b2,
+ 0xb0804009, 0xb8eef81a,
+ 0xbf880000, 0xb980081a,
+ 0x00000000, 0xb8f8f804,
+ 0x9177ff77, 0x0c000000,
+ 0x846e9a6e, 0x8c776e77,
0x9178ff78, 0x00008c00,
0xb8fbf811, 0x8b6eff78,
0x00004000, 0xbfa10008,
0x8b6eff7b, 0x00000080,
0xbfa20018, 0x8b6ea07b,
- 0xbfa20042, 0xbf830010,
+ 0xbfa2004a, 0xbf830010,
0xb8fbf811, 0xbfa0fffb,
0x8b6eff7b, 0x00000bd0,
0xbfa20010, 0xb8eef812,
@@ -3662,28 +3666,32 @@ static const uint32_t cwsr_trap_gfx12_hex[] = {
0xf0000000, 0xbfa20005,
0x8b6fff6f, 0x00000200,
0xbfa20002, 0x8b6ea07b,
- 0xbfa2002c, 0xbefa4d82,
+ 0xbfa20034, 0xbefa4d82,
0xbf8a0000, 0x84fa887a,
0xbf0d8f7b, 0xbfa10002,
0x8c7bff7b, 0xffff0000,
- 0xf4601bbd, 0xf8000010,
- 0xbf8a0000, 0x846e976e,
- 0x9177ff77, 0x00800000,
- 0x8c776e77, 0xf4603bbd,
- 0xf8000000, 0xbf8a0000,
- 0xf4603ebd, 0xf8000008,
- 0xbf8a0000, 0x8bee6e6e,
- 0xbfa10001, 0xbe80486e,
- 0x8b6eff6d, 0xf0000000,
- 0xbfa20009, 0xb8eef811,
- 0x8b6eff6e, 0x00000080,
- 0xbfa20007, 0x8c78ff78,
- 0x00004000, 0x80ec886c,
- 0x82ed806d, 0xbfa00002,
- 0x806c846c, 0x826d806d,
- 0x8b6dff6d, 0x0000ffff,
- 0x8bfe7e7e, 0x8bea6a6a,
- 0x85788978, 0xb9783244,
+ 0x8b6eff77, 0x0c000000,
+ 0x916dff6d, 0x0c000000,
+ 0x8c6d6e6d, 0xf4601bbd,
+ 0xf8000010, 0xbf8a0000,
+ 0x846e976e, 0x9177ff77,
+ 0x00800000, 0x8c776e77,
+ 0xf4603bbd, 0xf8000000,
+ 0xbf8a0000, 0xf4603ebd,
+ 0xf8000008, 0xbf8a0000,
+ 0x8bee6e6e, 0xbfa10001,
+ 0xbe80486e, 0x8b6eff6d,
+ 0xf0000000, 0xbfa20009,
+ 0xb8eef811, 0x8b6eff6e,
+ 0x00000080, 0xbfa20007,
+ 0x8c78ff78, 0x00004000,
+ 0x80ec886c, 0x82ed806d,
+ 0xbfa00002, 0x806c846c,
+ 0x826d806d, 0x8b6dff6d,
+ 0x0000ffff, 0x8bfe7e7e,
+ 0x8bea6a6a, 0x85788978,
+ 0x936eff77, 0x0002001a,
+ 0xb96ef81a, 0xb9783244,
0xbe804a6c, 0xb8faf802,
0xbf0d987a, 0xbfa10001,
0xbfb00000, 0x8b6dff6d,
@@ -3981,7 +3989,7 @@ static const uint32_t cwsr_trap_gfx12_hex[] = {
0x008ce800, 0x00000000,
0x807d817d, 0x8070ff70,
0x00000080, 0xbf0a7b7d,
- 0xbfa2fff7, 0xbfa0016e,
+ 0xbfa2fff7, 0xbfa00171,
0xbef4007e, 0x8b75ff7f,
0x0000ffff, 0x8c75ff75,
0x00040000, 0xbef60080,
@@ -4163,12 +4171,14 @@ static const uint32_t cwsr_trap_gfx12_hex[] = {
0xf8000074, 0xbf8a0000,
0x8b6dff6d, 0x0000ffff,
0x8bfe7e7e, 0x8bea6a6a,
- 0xb97af804, 0xbe804ec2,
- 0xbf94fffe, 0xbe804a6c,
+ 0x936eff77, 0x0002001a,
+ 0xb96ef81a, 0xb97af804,
0xbe804ec2, 0xbf94fffe,
- 0xbfb10000, 0xbf9f0000,
+ 0xbe804a6c, 0xbe804ec2,
+ 0xbf94fffe, 0xbfb10000,
0xbf9f0000, 0xbf9f0000,
0xbf9f0000, 0xbf9f0000,
+ 0xbf9f0000, 0x00000000,
};
static const uint32_t cwsr_trap_gfx9_5_0_hex[] = {
diff --git a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx12.asm b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx12.asm
index 5a1a1b1f897f..07999b4649de 100644
--- a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx12.asm
+++ b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx12.asm
@@ -78,9 +78,16 @@ var SQ_WAVE_EXCP_FLAG_PRIV_RESTORE_PART_2_SHIFT = SQ_WAVE_EXCP_FLAG_PRIV_ILLEGAL
var SQ_WAVE_EXCP_FLAG_PRIV_RESTORE_PART_2_SIZE = SQ_WAVE_EXCP_FLAG_PRIV_HOST_TRAP_SHIFT - SQ_WAVE_EXCP_FLAG_PRIV_ILLEGAL_INST_SHIFT
var SQ_WAVE_EXCP_FLAG_PRIV_RESTORE_PART_3_SHIFT = SQ_WAVE_EXCP_FLAG_PRIV_WAVE_START_SHIFT
var SQ_WAVE_EXCP_FLAG_PRIV_RESTORE_PART_3_SIZE = 32 - SQ_WAVE_EXCP_FLAG_PRIV_RESTORE_PART_3_SHIFT
+
+var SQ_WAVE_SCHED_MODE_DEP_MODE_SHIFT = 0
+var SQ_WAVE_SCHED_MODE_DEP_MODE_SIZE = 2
+
var BARRIER_STATE_SIGNAL_OFFSET = 16
var BARRIER_STATE_VALID_OFFSET = 0
+var TTMP11_SCHED_MODE_SHIFT = 26
+var TTMP11_SCHED_MODE_SIZE = 2
+var TTMP11_SCHED_MODE_MASK = 0xC000000
var TTMP11_DEBUG_TRAP_ENABLED_SHIFT = 23
var TTMP11_DEBUG_TRAP_ENABLED_MASK = 0x800000
@@ -160,8 +167,19 @@ L_JUMP_TO_RESTORE:
s_branch L_RESTORE
L_SKIP_RESTORE:
+ // Assume most relaxed scheduling mode is set. Save and revert to normal mode.
+ s_getreg_b32 ttmp2, hwreg(HW_REG_WAVE_SCHED_MODE)
+ s_wait_alu 0
+ s_setreg_imm32_b32 hwreg(HW_REG_WAVE_SCHED_MODE, \
+ SQ_WAVE_SCHED_MODE_DEP_MODE_SHIFT, SQ_WAVE_SCHED_MODE_DEP_MODE_SIZE), 0
+
s_getreg_b32 s_save_state_priv, hwreg(HW_REG_WAVE_STATE_PRIV) //save STATUS since we will change SCC
+ // Save SCHED_MODE[1:0] into ttmp11[27:26].
+ s_andn2_b32 ttmp11, ttmp11, TTMP11_SCHED_MODE_MASK
+ s_lshl_b32 ttmp2, ttmp2, TTMP11_SCHED_MODE_SHIFT
+ s_or_b32 ttmp11, ttmp11, ttmp2
+
// Clear SPI_PRIO: do not save with elevated priority.
// Clear ECC_ERR: prevents SQC store and triggers FATAL_HALT if setreg'd.
s_andn2_b32 s_save_state_priv, s_save_state_priv, SQ_WAVE_STATE_PRIV_ALWAYS_CLEAR_MASK
@@ -238,6 +256,13 @@ L_FETCH_2ND_TRAP:
s_cbranch_scc0 L_NO_SIGN_EXTEND_TMA
s_or_b32 ttmp15, ttmp15, 0xFFFF0000
L_NO_SIGN_EXTEND_TMA:
+#if ASIC_FAMILY == CHIP_GFX12
+ // Move SCHED_MODE[1:0] from ttmp11 to unused bits in ttmp1[27:26] (return PC_HI).
+ // The second-level trap will restore from ttmp1 for backwards compatibility.
+ s_and_b32 ttmp2, ttmp11, TTMP11_SCHED_MODE_MASK
+ s_andn2_b32 ttmp1, ttmp1, TTMP11_SCHED_MODE_MASK
+ s_or_b32 ttmp1, ttmp1, ttmp2
+#endif
s_load_dword ttmp2, [ttmp14, ttmp15], 0x10 scope:SCOPE_SYS // debug trap enabled flag
s_wait_idle
@@ -287,6 +312,10 @@ L_EXIT_TRAP:
// STATE_PRIV.BARRIER_COMPLETE may have changed since we read it.
// Only restore fields which the trap handler changes.
s_lshr_b32 s_save_state_priv, s_save_state_priv, SQ_WAVE_STATE_PRIV_SCC_SHIFT
+
+ // Assume relaxed scheduling mode after this point.
+ restore_sched_mode(ttmp2)
+
s_setreg_b32 hwreg(HW_REG_WAVE_STATE_PRIV, SQ_WAVE_STATE_PRIV_SCC_SHIFT, \
SQ_WAVE_STATE_PRIV_POISON_ERR_SHIFT - SQ_WAVE_STATE_PRIV_SCC_SHIFT + 1), s_save_state_priv
@@ -1043,6 +1072,9 @@ L_SKIP_BARRIER_RESTORE:
s_and_b64 exec, exec, exec // Restore STATUS.EXECZ, not writable by s_setreg_b32
s_and_b64 vcc, vcc, vcc // Restore STATUS.VCCZ, not writable by s_setreg_b32
+ // Assume relaxed scheduling mode after this point.
+ restore_sched_mode(s_restore_tmp)
+
s_setreg_b32 hwreg(HW_REG_WAVE_STATE_PRIV), s_restore_state_priv // SCC is included, which is changed by previous salu
// Make barrier and LDS state visible to all waves in the group.
@@ -1134,3 +1166,8 @@ function valu_sgpr_hazard
end
#endif
end
+
+function restore_sched_mode(s_tmp)
+ s_bfe_u32 s_tmp, ttmp11, (TTMP11_SCHED_MODE_SHIFT | (TTMP11_SCHED_MODE_SIZE << 0x10))
+ s_setreg_b32 hwreg(HW_REG_WAVE_SCHED_MODE), s_tmp
+end
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_queue.c b/drivers/gpu/drm/amd/amdkfd/kfd_queue.c
index f1e7583650c4..80c4fa2b0975 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_queue.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_queue.c
@@ -409,6 +409,7 @@ static u32 kfd_get_vgpr_size_per_cu(u32 gfxv)
vgpr_size = 0x80000;
else if (gfxv == 110000 || /* GFX_VERSION_PLUM_BONITO */
gfxv == 110001 || /* GFX_VERSION_WHEAT_NAS */
+ gfxv == 110501 || /* GFX_VERSION_GFX1151 */
gfxv == 120000 || /* GFX_VERSION_GFX1200 */
gfxv == 120001) /* GFX_VERSION_GFX1201 */
vgpr_size = 0x60000;
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
index 97c2270f278f..79ea138897fc 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
@@ -1144,30 +1144,48 @@ static int
svm_range_split_tail(struct svm_range *prange, uint64_t new_last,
struct list_head *insert_list, struct list_head *remap_list)
{
+ unsigned long last_align_down = ALIGN_DOWN(prange->last, 512);
+ unsigned long start_align = ALIGN(prange->start, 512);
+ bool huge_page_mapping = last_align_down > start_align;
struct svm_range *tail = NULL;
- int r = svm_range_split(prange, prange->start, new_last, &tail);
+ int r;
- if (!r) {
- list_add(&tail->list, insert_list);
- if (!IS_ALIGNED(new_last + 1, 1UL << prange->granularity))
- list_add(&tail->update_list, remap_list);
- }
- return r;
+ r = svm_range_split(prange, prange->start, new_last, &tail);
+
+ if (r)
+ return r;
+
+ list_add(&tail->list, insert_list);
+
+ if (huge_page_mapping && tail->start > start_align &&
+ tail->start < last_align_down && (!IS_ALIGNED(tail->start, 512)))
+ list_add(&tail->update_list, remap_list);
+
+ return 0;
}
static int
svm_range_split_head(struct svm_range *prange, uint64_t new_start,
struct list_head *insert_list, struct list_head *remap_list)
{
+ unsigned long last_align_down = ALIGN_DOWN(prange->last, 512);
+ unsigned long start_align = ALIGN(prange->start, 512);
+ bool huge_page_mapping = last_align_down > start_align;
struct svm_range *head = NULL;
- int r = svm_range_split(prange, new_start, prange->last, &head);
+ int r;
- if (!r) {
- list_add(&head->list, insert_list);
- if (!IS_ALIGNED(new_start, 1UL << prange->granularity))
- list_add(&head->update_list, remap_list);
- }
- return r;
+ r = svm_range_split(prange, new_start, prange->last, &head);
+
+ if (r)
+ return r;
+
+ list_add(&head->list, insert_list);
+
+ if (huge_page_mapping && head->last + 1 > start_align &&
+ head->last + 1 < last_align_down && (!IS_ALIGNED(head->last, 512)))
+ list_add(&head->update_list, remap_list);
+
+ return 0;
}
static void
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
index 811636af14ea..3eb32d58a120 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
@@ -491,6 +491,10 @@ static ssize_t node_show(struct kobject *kobj, struct attribute *attr,
dev->node_props.num_sdma_queues_per_engine);
sysfs_show_32bit_prop(buffer, offs, "num_cp_queues",
dev->node_props.num_cp_queues);
+ sysfs_show_32bit_prop(buffer, offs, "cwsr_size",
+ dev->node_props.cwsr_size);
+ sysfs_show_32bit_prop(buffer, offs, "ctl_stack_size",
+ dev->node_props.ctl_stack_size);
if (dev->gpu) {
log_max_watch_addr =
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index ef97cede9926..bd0403005f37 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -1063,6 +1063,9 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc,
void amdgpu_dm_update_connector_after_detect(
struct amdgpu_dm_connector *aconnector);
+void populate_hdmi_info_from_connector(struct drm_hdmi_info *info,
+ struct dc_edid_caps *edid_caps);
+
extern const struct drm_encoder_helper_funcs amdgpu_dm_encoder_helper_funcs;
int amdgpu_dm_process_dmub_aux_transfer_sync(struct dc_context *ctx, unsigned int link_index,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
index ac98c746c3de..e5e993d3ef74 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
@@ -139,6 +139,9 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
edid_caps->edid_hdmi = connector->display_info.is_hdmi;
+ if (edid_caps->edid_hdmi)
+ populate_hdmi_info_from_connector(&connector->display_info.hdmi, edid_caps);
+
apply_edid_quirks(dev, edid_buf, edid_caps);
sad_count = drm_edid_to_sad((struct edid *) edid->raw_edid, &sads);
@@ -990,6 +993,11 @@ dm_helpers_read_acpi_edid(struct amdgpu_dm_connector *aconnector)
return drm_edid_read_custom(connector, dm_helpers_probe_acpi_edid, connector);
}
+void populate_hdmi_info_from_connector(struct drm_hdmi_info *hdmi, struct dc_edid_caps *edid_caps)
+{
+ edid_caps->scdc_present = hdmi->scdc.supported;
+}
+
enum dc_edid_status dm_helpers_read_local_edid(
struct dc_context *ctx,
struct dc_link *link,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
index dbd1da4d85d3..5e92eaa67aa3 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
@@ -884,28 +884,26 @@ struct dsc_mst_fairness_params {
};
#if defined(CONFIG_DRM_AMD_DC_FP)
-static uint64_t kbps_to_pbn(int kbps, bool is_peak_pbn)
+static uint16_t get_fec_overhead_multiplier(struct dc_link *dc_link)
{
- uint64_t effective_kbps = (uint64_t)kbps;
+ u8 link_coding_cap;
+ uint16_t fec_overhead_multiplier_x1000 = PBN_FEC_OVERHEAD_MULTIPLIER_8B_10B;
- if (is_peak_pbn) { // add 0.6% (1006/1000) overhead into effective kbps
- effective_kbps *= 1006;
- effective_kbps = div_u64(effective_kbps, 1000);
- }
+ link_coding_cap = dc_link_dp_mst_decide_link_encoding_format(dc_link);
+ if (link_coding_cap == DP_128b_132b_ENCODING)
+ fec_overhead_multiplier_x1000 = PBN_FEC_OVERHEAD_MULTIPLIER_128B_132B;
- return (uint64_t) DIV64_U64_ROUND_UP(effective_kbps * 64, (54 * 8 * 1000));
+ return fec_overhead_multiplier_x1000;
}
-static uint32_t pbn_to_kbps(unsigned int pbn, bool with_margin)
+static int kbps_to_peak_pbn(int kbps, uint16_t fec_overhead_multiplier_x1000)
{
- uint64_t pbn_effective = (uint64_t)pbn;
-
- if (with_margin) // deduct 0.6% (994/1000) overhead from effective pbn
- pbn_effective *= (1000000 / PEAK_FACTOR_X1000);
- else
- pbn_effective *= 1000;
+ u64 peak_kbps = kbps;
- return DIV_U64_ROUND_UP(pbn_effective * 8 * 54, 64);
+ peak_kbps *= 1006;
+ peak_kbps *= fec_overhead_multiplier_x1000;
+ peak_kbps = div_u64(peak_kbps, 1000 * 1000);
+ return (int) DIV64_U64_ROUND_UP(peak_kbps * 64, (54 * 8 * 1000));
}
static void set_dsc_configs_from_fairness_vars(struct dsc_mst_fairness_params *params,
@@ -976,7 +974,7 @@ static int bpp_x16_from_pbn(struct dsc_mst_fairness_params param, int pbn)
dc_dsc_get_default_config_option(param.sink->ctx->dc, &dsc_options);
dsc_options.max_target_bpp_limit_override_x16 = drm_connector->display_info.max_dsc_bpp * 16;
- kbps = pbn_to_kbps(pbn, false);
+ kbps = div_u64((u64)pbn * 994 * 8 * 54, 64);
dc_dsc_compute_config(
param.sink->ctx->dc->res_pool->dscs[0],
&param.sink->dsc_caps.dsc_dec_caps,
@@ -1005,11 +1003,12 @@ static int increase_dsc_bpp(struct drm_atomic_state *state,
int link_timeslots_used;
int fair_pbn_alloc;
int ret = 0;
+ uint16_t fec_overhead_multiplier_x1000 = get_fec_overhead_multiplier(dc_link);
for (i = 0; i < count; i++) {
if (vars[i + k].dsc_enabled) {
initial_slack[i] =
- kbps_to_pbn(params[i].bw_range.max_kbps, false) - vars[i + k].pbn;
+ kbps_to_peak_pbn(params[i].bw_range.max_kbps, fec_overhead_multiplier_x1000) - vars[i + k].pbn;
bpp_increased[i] = false;
remaining_to_increase += 1;
} else {
@@ -1105,6 +1104,7 @@ static int try_disable_dsc(struct drm_atomic_state *state,
int next_index;
int remaining_to_try = 0;
int ret;
+ uint16_t fec_overhead_multiplier_x1000 = get_fec_overhead_multiplier(dc_link);
int var_pbn;
for (i = 0; i < count; i++) {
@@ -1137,7 +1137,7 @@ static int try_disable_dsc(struct drm_atomic_state *state,
DRM_DEBUG_DRIVER("MST_DSC index #%d, try no compression\n", next_index);
var_pbn = vars[next_index].pbn;
- vars[next_index].pbn = kbps_to_pbn(params[next_index].bw_range.stream_kbps, true);
+ vars[next_index].pbn = kbps_to_peak_pbn(params[next_index].bw_range.stream_kbps, fec_overhead_multiplier_x1000);
ret = drm_dp_atomic_find_time_slots(state,
params[next_index].port->mgr,
params[next_index].port,
@@ -1197,6 +1197,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
int count = 0;
int i, k, ret;
bool debugfs_overwrite = false;
+ uint16_t fec_overhead_multiplier_x1000 = get_fec_overhead_multiplier(dc_link);
struct drm_connector_state *new_conn_state;
memset(params, 0, sizeof(params));
@@ -1277,7 +1278,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
DRM_DEBUG_DRIVER("MST_DSC Try no compression\n");
for (i = 0; i < count; i++) {
vars[i + k].aconnector = params[i].aconnector;
- vars[i + k].pbn = kbps_to_pbn(params[i].bw_range.stream_kbps, false);
+ vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps, fec_overhead_multiplier_x1000);
vars[i + k].dsc_enabled = false;
vars[i + k].bpp_x16 = 0;
ret = drm_dp_atomic_find_time_slots(state, params[i].port->mgr, params[i].port,
@@ -1299,7 +1300,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
DRM_DEBUG_DRIVER("MST_DSC Try max compression\n");
for (i = 0; i < count; i++) {
if (params[i].compression_possible && params[i].clock_force_enable != DSC_CLK_FORCE_DISABLE) {
- vars[i + k].pbn = kbps_to_pbn(params[i].bw_range.min_kbps, false);
+ vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.min_kbps, fec_overhead_multiplier_x1000);
vars[i + k].dsc_enabled = true;
vars[i + k].bpp_x16 = params[i].bw_range.min_target_bpp_x16;
ret = drm_dp_atomic_find_time_slots(state, params[i].port->mgr,
@@ -1307,7 +1308,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
if (ret < 0)
return ret;
} else {
- vars[i + k].pbn = kbps_to_pbn(params[i].bw_range.stream_kbps, false);
+ vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps, fec_overhead_multiplier_x1000);
vars[i + k].dsc_enabled = false;
vars[i + k].bpp_x16 = 0;
ret = drm_dp_atomic_find_time_slots(state, params[i].port->mgr,
@@ -1762,6 +1763,18 @@ clean_exit:
return ret;
}
+static uint32_t kbps_from_pbn(unsigned int pbn)
+{
+ uint64_t kbps = (uint64_t)pbn;
+
+ kbps *= (1000000 / PEAK_FACTOR_X1000);
+ kbps *= 8;
+ kbps *= 54;
+ kbps /= 64;
+
+ return (uint32_t)kbps;
+}
+
static bool is_dsc_common_config_possible(struct dc_stream_state *stream,
struct dc_dsc_bw_range *bw_range)
{
@@ -1860,7 +1873,7 @@ enum dc_status dm_dp_mst_is_port_support_mode(
dc_link_get_highest_encoding_format(stream->link));
cur_link_settings = stream->link->verified_link_cap;
root_link_bw_in_kbps = dc_link_bandwidth_kbps(aconnector->dc_link, &cur_link_settings);
- virtual_channel_bw_in_kbps = pbn_to_kbps(aconnector->mst_output_port->full_pbn, true);
+ virtual_channel_bw_in_kbps = kbps_from_pbn(aconnector->mst_output_port->full_pbn);
/* pick the end to end bw bottleneck */
end_to_end_bw_in_kbps = min(root_link_bw_in_kbps, virtual_channel_bw_in_kbps);
@@ -1913,7 +1926,7 @@ enum dc_status dm_dp_mst_is_port_support_mode(
immediate_upstream_port = aconnector->mst_output_port->parent->port_parent;
if (immediate_upstream_port) {
- virtual_channel_bw_in_kbps = pbn_to_kbps(immediate_upstream_port->full_pbn, true);
+ virtual_channel_bw_in_kbps = kbps_from_pbn(immediate_upstream_port->full_pbn);
virtual_channel_bw_in_kbps = min(root_link_bw_in_kbps, virtual_channel_bw_in_kbps);
} else {
/* For topology LCT 1 case - only one mstb*/
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c
index 922f23557f5d..0971dfa25845 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c
@@ -86,7 +86,7 @@ uint8_t dc_plane_get_pipe_mask(struct dc_state *dc_state, const struct dc_plane
struct dc_plane_state *dc_create_plane_state(const struct dc *dc)
{
struct dc_plane_state *plane_state = kvzalloc(sizeof(*plane_state),
- GFP_KERNEL);
+ GFP_ATOMIC);
if (NULL == plane_state)
return NULL;
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/display_mode_core.c b/drivers/gpu/drm/amd/display/dc/dml2_0/display_mode_core.c
index c468f492b876..09303c282495 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/display_mode_core.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/display_mode_core.c
@@ -6711,6 +6711,76 @@ static noinline_for_stack void dml_prefetch_check(struct display_mode_lib_st *mo
} // for j
}
+static noinline_for_stack void set_vm_row_and_swath_parameters(struct display_mode_lib_st *mode_lib)
+{
+ struct CalculateVMRowAndSwath_params_st *CalculateVMRowAndSwath_params = &mode_lib->scratch.CalculateVMRowAndSwath_params;
+ struct dml_core_mode_support_locals_st *s = &mode_lib->scratch.dml_core_mode_support_locals;
+
+ CalculateVMRowAndSwath_params->NumberOfActiveSurfaces = mode_lib->ms.num_active_planes;
+ CalculateVMRowAndSwath_params->myPipe = s->SurfParameters;
+ CalculateVMRowAndSwath_params->SurfaceSizeInMALL = mode_lib->ms.SurfaceSizeInMALL;
+ CalculateVMRowAndSwath_params->PTEBufferSizeInRequestsLuma = mode_lib->ms.ip.dpte_buffer_size_in_pte_reqs_luma;
+ CalculateVMRowAndSwath_params->PTEBufferSizeInRequestsChroma = mode_lib->ms.ip.dpte_buffer_size_in_pte_reqs_chroma;
+ CalculateVMRowAndSwath_params->DCCMetaBufferSizeBytes = mode_lib->ms.ip.dcc_meta_buffer_size_bytes;
+ CalculateVMRowAndSwath_params->UseMALLForStaticScreen = mode_lib->ms.cache_display_cfg.plane.UseMALLForStaticScreen;
+ CalculateVMRowAndSwath_params->UseMALLForPStateChange = mode_lib->ms.cache_display_cfg.plane.UseMALLForPStateChange;
+ CalculateVMRowAndSwath_params->MALLAllocatedForDCN = mode_lib->ms.soc.mall_allocated_for_dcn_mbytes;
+ CalculateVMRowAndSwath_params->SwathWidthY = mode_lib->ms.SwathWidthYThisState;
+ CalculateVMRowAndSwath_params->SwathWidthC = mode_lib->ms.SwathWidthCThisState;
+ CalculateVMRowAndSwath_params->GPUVMEnable = mode_lib->ms.cache_display_cfg.plane.GPUVMEnable;
+ CalculateVMRowAndSwath_params->HostVMEnable = mode_lib->ms.cache_display_cfg.plane.HostVMEnable;
+ CalculateVMRowAndSwath_params->HostVMMaxNonCachedPageTableLevels = mode_lib->ms.cache_display_cfg.plane.HostVMMaxPageTableLevels;
+ CalculateVMRowAndSwath_params->GPUVMMaxPageTableLevels = mode_lib->ms.cache_display_cfg.plane.GPUVMMaxPageTableLevels;
+ CalculateVMRowAndSwath_params->GPUVMMinPageSizeKBytes = mode_lib->ms.cache_display_cfg.plane.GPUVMMinPageSizeKBytes;
+ CalculateVMRowAndSwath_params->HostVMMinPageSize = mode_lib->ms.soc.hostvm_min_page_size_kbytes * 1024;
+ CalculateVMRowAndSwath_params->PTEBufferModeOverrideEn = mode_lib->ms.cache_display_cfg.plane.PTEBufferModeOverrideEn;
+ CalculateVMRowAndSwath_params->PTEBufferModeOverrideVal = mode_lib->ms.cache_display_cfg.plane.PTEBufferMode;
+ CalculateVMRowAndSwath_params->PTEBufferSizeNotExceeded = mode_lib->ms.PTEBufferSizeNotExceededPerState;
+ CalculateVMRowAndSwath_params->DCCMetaBufferSizeNotExceeded = mode_lib->ms.DCCMetaBufferSizeNotExceededPerState;
+ CalculateVMRowAndSwath_params->dpte_row_width_luma_ub = s->dummy_integer_array[0];
+ CalculateVMRowAndSwath_params->dpte_row_width_chroma_ub = s->dummy_integer_array[1];
+ CalculateVMRowAndSwath_params->dpte_row_height_luma = mode_lib->ms.dpte_row_height;
+ CalculateVMRowAndSwath_params->dpte_row_height_chroma = mode_lib->ms.dpte_row_height_chroma;
+ CalculateVMRowAndSwath_params->dpte_row_height_linear_luma = s->dummy_integer_array[2]; // VBA_DELTA
+ CalculateVMRowAndSwath_params->dpte_row_height_linear_chroma = s->dummy_integer_array[3]; // VBA_DELTA
+ CalculateVMRowAndSwath_params->meta_req_width = s->dummy_integer_array[4];
+ CalculateVMRowAndSwath_params->meta_req_width_chroma = s->dummy_integer_array[5];
+ CalculateVMRowAndSwath_params->meta_req_height = s->dummy_integer_array[6];
+ CalculateVMRowAndSwath_params->meta_req_height_chroma = s->dummy_integer_array[7];
+ CalculateVMRowAndSwath_params->meta_row_width = s->dummy_integer_array[8];
+ CalculateVMRowAndSwath_params->meta_row_width_chroma = s->dummy_integer_array[9];
+ CalculateVMRowAndSwath_params->meta_row_height = mode_lib->ms.meta_row_height;
+ CalculateVMRowAndSwath_params->meta_row_height_chroma = mode_lib->ms.meta_row_height_chroma;
+ CalculateVMRowAndSwath_params->vm_group_bytes = s->dummy_integer_array[10];
+ CalculateVMRowAndSwath_params->dpte_group_bytes = mode_lib->ms.dpte_group_bytes;
+ CalculateVMRowAndSwath_params->PixelPTEReqWidthY = s->dummy_integer_array[11];
+ CalculateVMRowAndSwath_params->PixelPTEReqHeightY = s->dummy_integer_array[12];
+ CalculateVMRowAndSwath_params->PTERequestSizeY = s->dummy_integer_array[13];
+ CalculateVMRowAndSwath_params->PixelPTEReqWidthC = s->dummy_integer_array[14];
+ CalculateVMRowAndSwath_params->PixelPTEReqHeightC = s->dummy_integer_array[15];
+ CalculateVMRowAndSwath_params->PTERequestSizeC = s->dummy_integer_array[16];
+ CalculateVMRowAndSwath_params->dpde0_bytes_per_frame_ub_l = s->dummy_integer_array[17];
+ CalculateVMRowAndSwath_params->meta_pte_bytes_per_frame_ub_l = s->dummy_integer_array[18];
+ CalculateVMRowAndSwath_params->dpde0_bytes_per_frame_ub_c = s->dummy_integer_array[19];
+ CalculateVMRowAndSwath_params->meta_pte_bytes_per_frame_ub_c = s->dummy_integer_array[20];
+ CalculateVMRowAndSwath_params->PrefetchSourceLinesY = mode_lib->ms.PrefetchLinesYThisState;
+ CalculateVMRowAndSwath_params->PrefetchSourceLinesC = mode_lib->ms.PrefetchLinesCThisState;
+ CalculateVMRowAndSwath_params->VInitPreFillY = mode_lib->ms.PrefillY;
+ CalculateVMRowAndSwath_params->VInitPreFillC = mode_lib->ms.PrefillC;
+ CalculateVMRowAndSwath_params->MaxNumSwathY = mode_lib->ms.MaxNumSwY;
+ CalculateVMRowAndSwath_params->MaxNumSwathC = mode_lib->ms.MaxNumSwC;
+ CalculateVMRowAndSwath_params->meta_row_bw = mode_lib->ms.meta_row_bandwidth_this_state;
+ CalculateVMRowAndSwath_params->dpte_row_bw = mode_lib->ms.dpte_row_bandwidth_this_state;
+ CalculateVMRowAndSwath_params->PixelPTEBytesPerRow = mode_lib->ms.DPTEBytesPerRowThisState;
+ CalculateVMRowAndSwath_params->PDEAndMetaPTEBytesFrame = mode_lib->ms.PDEAndMetaPTEBytesPerFrameThisState;
+ CalculateVMRowAndSwath_params->MetaRowByte = mode_lib->ms.MetaRowBytesThisState;
+ CalculateVMRowAndSwath_params->use_one_row_for_frame = mode_lib->ms.use_one_row_for_frame_this_state;
+ CalculateVMRowAndSwath_params->use_one_row_for_frame_flip = mode_lib->ms.use_one_row_for_frame_flip_this_state;
+ CalculateVMRowAndSwath_params->UsesMALLForStaticScreen = s->dummy_boolean_array[0];
+ CalculateVMRowAndSwath_params->PTE_BUFFER_MODE = s->dummy_boolean_array[1];
+ CalculateVMRowAndSwath_params->BIGK_FRAGMENT_SIZE = s->dummy_integer_array[21];
+}
+
/// @brief The Mode Support function.
dml_bool_t dml_core_mode_support(struct display_mode_lib_st *mode_lib)
{
@@ -7683,69 +7753,7 @@ dml_bool_t dml_core_mode_support(struct display_mode_lib_st *mode_lib)
s->SurfParameters[k].SwathHeightC = mode_lib->ms.SwathHeightCThisState[k];
}
- CalculateVMRowAndSwath_params->NumberOfActiveSurfaces = mode_lib->ms.num_active_planes;
- CalculateVMRowAndSwath_params->myPipe = s->SurfParameters;
- CalculateVMRowAndSwath_params->SurfaceSizeInMALL = mode_lib->ms.SurfaceSizeInMALL;
- CalculateVMRowAndSwath_params->PTEBufferSizeInRequestsLuma = mode_lib->ms.ip.dpte_buffer_size_in_pte_reqs_luma;
- CalculateVMRowAndSwath_params->PTEBufferSizeInRequestsChroma = mode_lib->ms.ip.dpte_buffer_size_in_pte_reqs_chroma;
- CalculateVMRowAndSwath_params->DCCMetaBufferSizeBytes = mode_lib->ms.ip.dcc_meta_buffer_size_bytes;
- CalculateVMRowAndSwath_params->UseMALLForStaticScreen = mode_lib->ms.cache_display_cfg.plane.UseMALLForStaticScreen;
- CalculateVMRowAndSwath_params->UseMALLForPStateChange = mode_lib->ms.cache_display_cfg.plane.UseMALLForPStateChange;
- CalculateVMRowAndSwath_params->MALLAllocatedForDCN = mode_lib->ms.soc.mall_allocated_for_dcn_mbytes;
- CalculateVMRowAndSwath_params->SwathWidthY = mode_lib->ms.SwathWidthYThisState;
- CalculateVMRowAndSwath_params->SwathWidthC = mode_lib->ms.SwathWidthCThisState;
- CalculateVMRowAndSwath_params->GPUVMEnable = mode_lib->ms.cache_display_cfg.plane.GPUVMEnable;
- CalculateVMRowAndSwath_params->HostVMEnable = mode_lib->ms.cache_display_cfg.plane.HostVMEnable;
- CalculateVMRowAndSwath_params->HostVMMaxNonCachedPageTableLevels = mode_lib->ms.cache_display_cfg.plane.HostVMMaxPageTableLevels;
- CalculateVMRowAndSwath_params->GPUVMMaxPageTableLevels = mode_lib->ms.cache_display_cfg.plane.GPUVMMaxPageTableLevels;
- CalculateVMRowAndSwath_params->GPUVMMinPageSizeKBytes = mode_lib->ms.cache_display_cfg.plane.GPUVMMinPageSizeKBytes;
- CalculateVMRowAndSwath_params->HostVMMinPageSize = mode_lib->ms.soc.hostvm_min_page_size_kbytes * 1024;
- CalculateVMRowAndSwath_params->PTEBufferModeOverrideEn = mode_lib->ms.cache_display_cfg.plane.PTEBufferModeOverrideEn;
- CalculateVMRowAndSwath_params->PTEBufferModeOverrideVal = mode_lib->ms.cache_display_cfg.plane.PTEBufferMode;
- CalculateVMRowAndSwath_params->PTEBufferSizeNotExceeded = mode_lib->ms.PTEBufferSizeNotExceededPerState;
- CalculateVMRowAndSwath_params->DCCMetaBufferSizeNotExceeded = mode_lib->ms.DCCMetaBufferSizeNotExceededPerState;
- CalculateVMRowAndSwath_params->dpte_row_width_luma_ub = s->dummy_integer_array[0];
- CalculateVMRowAndSwath_params->dpte_row_width_chroma_ub = s->dummy_integer_array[1];
- CalculateVMRowAndSwath_params->dpte_row_height_luma = mode_lib->ms.dpte_row_height;
- CalculateVMRowAndSwath_params->dpte_row_height_chroma = mode_lib->ms.dpte_row_height_chroma;
- CalculateVMRowAndSwath_params->dpte_row_height_linear_luma = s->dummy_integer_array[2]; // VBA_DELTA
- CalculateVMRowAndSwath_params->dpte_row_height_linear_chroma = s->dummy_integer_array[3]; // VBA_DELTA
- CalculateVMRowAndSwath_params->meta_req_width = s->dummy_integer_array[4];
- CalculateVMRowAndSwath_params->meta_req_width_chroma = s->dummy_integer_array[5];
- CalculateVMRowAndSwath_params->meta_req_height = s->dummy_integer_array[6];
- CalculateVMRowAndSwath_params->meta_req_height_chroma = s->dummy_integer_array[7];
- CalculateVMRowAndSwath_params->meta_row_width = s->dummy_integer_array[8];
- CalculateVMRowAndSwath_params->meta_row_width_chroma = s->dummy_integer_array[9];
- CalculateVMRowAndSwath_params->meta_row_height = mode_lib->ms.meta_row_height;
- CalculateVMRowAndSwath_params->meta_row_height_chroma = mode_lib->ms.meta_row_height_chroma;
- CalculateVMRowAndSwath_params->vm_group_bytes = s->dummy_integer_array[10];
- CalculateVMRowAndSwath_params->dpte_group_bytes = mode_lib->ms.dpte_group_bytes;
- CalculateVMRowAndSwath_params->PixelPTEReqWidthY = s->dummy_integer_array[11];
- CalculateVMRowAndSwath_params->PixelPTEReqHeightY = s->dummy_integer_array[12];
- CalculateVMRowAndSwath_params->PTERequestSizeY = s->dummy_integer_array[13];
- CalculateVMRowAndSwath_params->PixelPTEReqWidthC = s->dummy_integer_array[14];
- CalculateVMRowAndSwath_params->PixelPTEReqHeightC = s->dummy_integer_array[15];
- CalculateVMRowAndSwath_params->PTERequestSizeC = s->dummy_integer_array[16];
- CalculateVMRowAndSwath_params->dpde0_bytes_per_frame_ub_l = s->dummy_integer_array[17];
- CalculateVMRowAndSwath_params->meta_pte_bytes_per_frame_ub_l = s->dummy_integer_array[18];
- CalculateVMRowAndSwath_params->dpde0_bytes_per_frame_ub_c = s->dummy_integer_array[19];
- CalculateVMRowAndSwath_params->meta_pte_bytes_per_frame_ub_c = s->dummy_integer_array[20];
- CalculateVMRowAndSwath_params->PrefetchSourceLinesY = mode_lib->ms.PrefetchLinesYThisState;
- CalculateVMRowAndSwath_params->PrefetchSourceLinesC = mode_lib->ms.PrefetchLinesCThisState;
- CalculateVMRowAndSwath_params->VInitPreFillY = mode_lib->ms.PrefillY;
- CalculateVMRowAndSwath_params->VInitPreFillC = mode_lib->ms.PrefillC;
- CalculateVMRowAndSwath_params->MaxNumSwathY = mode_lib->ms.MaxNumSwY;
- CalculateVMRowAndSwath_params->MaxNumSwathC = mode_lib->ms.MaxNumSwC;
- CalculateVMRowAndSwath_params->meta_row_bw = mode_lib->ms.meta_row_bandwidth_this_state;
- CalculateVMRowAndSwath_params->dpte_row_bw = mode_lib->ms.dpte_row_bandwidth_this_state;
- CalculateVMRowAndSwath_params->PixelPTEBytesPerRow = mode_lib->ms.DPTEBytesPerRowThisState;
- CalculateVMRowAndSwath_params->PDEAndMetaPTEBytesFrame = mode_lib->ms.PDEAndMetaPTEBytesPerFrameThisState;
- CalculateVMRowAndSwath_params->MetaRowByte = mode_lib->ms.MetaRowBytesThisState;
- CalculateVMRowAndSwath_params->use_one_row_for_frame = mode_lib->ms.use_one_row_for_frame_this_state;
- CalculateVMRowAndSwath_params->use_one_row_for_frame_flip = mode_lib->ms.use_one_row_for_frame_flip_this_state;
- CalculateVMRowAndSwath_params->UsesMALLForStaticScreen = s->dummy_boolean_array[0];
- CalculateVMRowAndSwath_params->PTE_BUFFER_MODE = s->dummy_boolean_array[1];
- CalculateVMRowAndSwath_params->BIGK_FRAGMENT_SIZE = s->dummy_integer_array[21];
+ set_vm_row_and_swath_parameters(mode_lib);
CalculateVMRowAndSwath(&mode_lib->scratch,
CalculateVMRowAndSwath_params);
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
index 8fe399939220..4986f12dc9df 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
@@ -1484,9 +1484,6 @@ void build_audio_output(
state->clk_mgr);
}
- audio_output->pll_info.feed_back_divider =
- pipe_ctx->pll_settings.feedback_divider;
-
audio_output->pll_info.dto_source =
translate_to_dto_source(
pipe_ctx->stream_res.tg->inst + 1);
diff --git a/drivers/gpu/drm/amd/display/include/audio_types.h b/drivers/gpu/drm/amd/display/include/audio_types.h
index e4a26143f14c..6699ad4fa825 100644
--- a/drivers/gpu/drm/amd/display/include/audio_types.h
+++ b/drivers/gpu/drm/amd/display/include/audio_types.h
@@ -47,15 +47,15 @@ struct audio_crtc_info {
uint32_t h_total;
uint32_t h_active;
uint32_t v_active;
- uint32_t pixel_repetition;
uint32_t requested_pixel_clock_100Hz; /* in 100Hz */
uint32_t calculated_pixel_clock_100Hz; /* in 100Hz */
- uint32_t refresh_rate;
+ uint32_t dsc_bits_per_pixel;
+ uint32_t dsc_num_slices;
enum dc_color_depth color_depth;
enum dc_pixel_encoding pixel_encoding;
+ uint16_t refresh_rate;
+ uint8_t pixel_repetition;
bool interlaced;
- uint32_t dsc_bits_per_pixel;
- uint32_t dsc_num_slices;
};
struct azalia_clock_info {
uint32_t pixel_clock_in_10khz;
@@ -78,11 +78,9 @@ enum audio_dto_source {
struct audio_pll_info {
uint32_t audio_dto_source_clock_in_khz;
- uint32_t feed_back_divider;
+ uint32_t ss_percentage;
enum audio_dto_source dto_source;
bool ss_enabled;
- uint32_t ss_percentage;
- uint32_t ss_percentage_divider;
};
struct audio_channel_associate_info {
diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi83.c b/drivers/gpu/drm/bridge/ti-sn65dsi83.c
index 033c44326552..fffb47b62f43 100644
--- a/drivers/gpu/drm/bridge/ti-sn65dsi83.c
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi83.c
@@ -429,7 +429,14 @@ static void sn65dsi83_handle_errors(struct sn65dsi83 *ctx)
*/
ret = regmap_read(ctx->regmap, REG_IRQ_STAT, &irq_stat);
- if (ret || irq_stat) {
+
+ /*
+ * Some hardware (Toradex Verdin AM62) is known to report the
+ * PLL_UNLOCK error interrupt while working without visible
+ * problems. In lack of a reliable way to discriminate such cases
+ * from user-visible PLL_UNLOCK cases, ignore that bit entirely.
+ */
+ if (ret || irq_stat & ~REG_IRQ_STAT_CHA_PLL_UNLOCK) {
/*
* IRQ acknowledged is not always possible (the bridge can be in
* a state where it doesn't answer anymore). To prevent an
@@ -654,7 +661,7 @@ static void sn65dsi83_atomic_enable(struct drm_bridge *bridge,
if (ctx->irq) {
/* Enable irq to detect errors */
regmap_write(ctx->regmap, REG_IRQ_GLOBAL, REG_IRQ_GLOBAL_IRQ_EN);
- regmap_write(ctx->regmap, REG_IRQ_EN, 0xff);
+ regmap_write(ctx->regmap, REG_IRQ_EN, 0xff & ~REG_IRQ_EN_CHA_PLL_UNLOCK_EN);
} else {
/* Use the polling task */
sn65dsi83_monitor_start(ctx);
diff --git a/drivers/gpu/drm/drm_gem_dma_helper.c b/drivers/gpu/drm/drm_gem_dma_helper.c
index 12d8307997a0..eb56ba234796 100644
--- a/drivers/gpu/drm/drm_gem_dma_helper.c
+++ b/drivers/gpu/drm/drm_gem_dma_helper.c
@@ -308,7 +308,7 @@ int drm_gem_dma_dumb_create(struct drm_file *file_priv,
struct drm_gem_dma_object *dma_obj;
int ret;
- ret = drm_mode_size_dumb(drm, args, SZ_8, 0);
+ ret = drm_mode_size_dumb(drm, args, 0, 0);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
index dc94a27710e5..93b9cff89080 100644
--- a/drivers/gpu/drm/drm_gem_shmem_helper.c
+++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
@@ -559,7 +559,7 @@ int drm_gem_shmem_dumb_create(struct drm_file *file, struct drm_device *dev,
{
int ret;
- ret = drm_mode_size_dumb(dev, args, SZ_8, 0);
+ ret = drm_mode_size_dumb(dev, args, 0, 0);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c
index ce76c55913f7..b143589717e6 100644
--- a/drivers/gpu/drm/drm_plane.c
+++ b/drivers/gpu/drm/drm_plane.c
@@ -338,14 +338,14 @@ static int drm_plane_create_hotspot_properties(struct drm_plane *plane)
prop_x = drm_property_create_signed_range(plane->dev, 0, "HOTSPOT_X",
INT_MIN, INT_MAX);
- if (IS_ERR(prop_x))
- return PTR_ERR(prop_x);
+ if (!prop_x)
+ return -ENOMEM;
prop_y = drm_property_create_signed_range(plane->dev, 0, "HOTSPOT_Y",
INT_MIN, INT_MAX);
- if (IS_ERR(prop_y)) {
+ if (!prop_y) {
drm_property_destroy(plane->dev, prop_x);
- return PTR_ERR(prop_y);
+ return -ENOMEM;
}
drm_object_attach_property(&plane->base, prop_x, 0);
diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c
index 9cd03e2adeb2..44f4fcce526e 100644
--- a/drivers/gpu/drm/i915/display/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/display/intel_fbdev.c
@@ -288,13 +288,18 @@ int intel_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper,
drm_framebuffer_put(&fb->base);
fb = NULL;
}
+
+ wakeref = intel_display_rpm_get(display);
+
if (!fb || drm_WARN_ON(display->drm, !intel_fb_bo(&fb->base))) {
drm_dbg_kms(display->drm,
"no BIOS fb, allocating a new one\n");
fb = __intel_fbdev_fb_alloc(display, sizes);
- if (IS_ERR(fb))
- return PTR_ERR(fb);
+ if (IS_ERR(fb)) {
+ ret = PTR_ERR(fb);
+ goto out_unlock;
+ }
} else {
drm_dbg_kms(display->drm, "re-using BIOS fb\n");
prealloc = true;
@@ -302,8 +307,6 @@ int intel_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper,
sizes->fb_height = fb->base.height;
}
- wakeref = intel_display_rpm_get(display);
-
/* Pin the GGTT vma for our access via info->screen_base.
* This also validates that any existing fb inherited from the
* BIOS is suitable for own access.
diff --git a/drivers/gpu/drm/i915/intel_memory_region.h b/drivers/gpu/drm/i915/intel_memory_region.h
index b3b75be9ced5..e9a4e6090fe0 100644
--- a/drivers/gpu/drm/i915/intel_memory_region.h
+++ b/drivers/gpu/drm/i915/intel_memory_region.h
@@ -72,7 +72,7 @@ struct intel_memory_region {
u16 instance;
enum intel_region_id id;
char name[16];
- char uabi_name[16];
+ char uabi_name[20];
bool private; /* not for userspace */
struct {
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
index 951d715dea30..d019177462cf 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -161,6 +161,30 @@ static void mgag200_set_startadd(struct mga_device *mdev,
WREG_ECRT(0x00, crtcext0);
}
+/*
+ * Set the opmode for the hardware swapper for Big-Endian processor
+ * support for the frame buffer aperture and DMAWIN space.
+ */
+static void mgag200_set_datasiz(struct mga_device *mdev, u32 format)
+{
+#if defined(__BIG_ENDIAN)
+ u32 opmode = RREG32(MGAREG_OPMODE);
+
+ opmode &= ~(GENMASK(17, 16) | GENMASK(9, 8) | GENMASK(3, 2));
+
+ /* Big-endian byte-swapping */
+ switch (format) {
+ case DRM_FORMAT_RGB565:
+ opmode |= 0x10100;
+ break;
+ case DRM_FORMAT_XRGB8888:
+ opmode |= 0x20200;
+ break;
+ }
+ WREG32(MGAREG_OPMODE, opmode);
+#endif
+}
+
void mgag200_init_registers(struct mga_device *mdev)
{
u8 crtc11, misc;
@@ -496,6 +520,7 @@ void mgag200_primary_plane_helper_atomic_update(struct drm_plane *plane,
struct drm_atomic_helper_damage_iter iter;
struct drm_rect damage;
+ mgag200_set_datasiz(mdev, fb->format->format);
drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
drm_atomic_for_each_plane_damage(&iter, &damage) {
mgag200_handle_damage(mdev, shadow_plane_state->data, fb, &damage);
diff --git a/drivers/gpu/drm/nouveau/dispnv04/nouveau_i2c_encoder.c b/drivers/gpu/drm/nouveau/dispnv04/nouveau_i2c_encoder.c
index e2bf99c43336..a60209097a20 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/nouveau_i2c_encoder.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/nouveau_i2c_encoder.c
@@ -94,26 +94,6 @@ fail_unregister:
return err;
}
-/**
- * nouveau_i2c_encoder_destroy - Unregister the I2C device backing an encoder
- * @drm_encoder: Encoder to be unregistered.
- *
- * This should be called from the @destroy method of an I2C slave
- * encoder driver once I2C access is no longer needed.
- */
-void nouveau_i2c_encoder_destroy(struct drm_encoder *drm_encoder)
-{
- struct nouveau_i2c_encoder *encoder = to_encoder_i2c(drm_encoder);
- struct i2c_client *client = nouveau_i2c_encoder_get_client(drm_encoder);
- struct module *module = client->dev.driver->owner;
-
- i2c_unregister_device(client);
- encoder->i2c_client = NULL;
-
- module_put(module);
-}
-EXPORT_SYMBOL(nouveau_i2c_encoder_destroy);
-
/*
* Wrapper fxns which can be plugged in to drm_encoder_helper_funcs:
*/
diff --git a/drivers/gpu/drm/nouveau/include/dispnv04/i2c/encoder_i2c.h b/drivers/gpu/drm/nouveau/include/dispnv04/i2c/encoder_i2c.h
index 31334aa90781..869820701a56 100644
--- a/drivers/gpu/drm/nouveau/include/dispnv04/i2c/encoder_i2c.h
+++ b/drivers/gpu/drm/nouveau/include/dispnv04/i2c/encoder_i2c.h
@@ -202,7 +202,24 @@ static inline struct i2c_client *nouveau_i2c_encoder_get_client(struct drm_encod
return to_encoder_i2c(encoder)->i2c_client;
}
-void nouveau_i2c_encoder_destroy(struct drm_encoder *encoder);
+/**
+ * nouveau_i2c_encoder_destroy - Unregister the I2C device backing an encoder
+ * @drm_encoder: Encoder to be unregistered.
+ *
+ * This should be called from the @destroy method of an I2C slave
+ * encoder driver once I2C access is no longer needed.
+ */
+static __always_inline void nouveau_i2c_encoder_destroy(struct drm_encoder *drm_encoder)
+{
+ struct nouveau_i2c_encoder *encoder = to_encoder_i2c(drm_encoder);
+ struct i2c_client *client = nouveau_i2c_encoder_get_client(drm_encoder);
+ struct module *module = client->dev.driver->owner;
+
+ i2c_unregister_device(client);
+ encoder->i2c_client = NULL;
+
+ module_put(module);
+}
/*
* Wrapper fxns which can be plugged in to drm_encoder_helper_funcs:
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h
index 226c7ec56b8e..b8b97e10ae83 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h
@@ -73,6 +73,10 @@ struct nvkm_gsp {
const struct firmware *bl;
const struct firmware *rm;
+
+ struct {
+ struct nvkm_falcon_fw sb;
+ } falcon;
} fws;
struct nvkm_firmware fw;
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
index 869d4335c0f4..4a193b7d6d9e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -183,11 +183,11 @@ nouveau_fence_context_new(struct nouveau_channel *chan, struct nouveau_fence_cha
fctx->context = drm->runl[chan->runlist].context_base + chan->chid;
if (chan == drm->cechan)
- strcpy(fctx->name, "copy engine channel");
+ strscpy(fctx->name, "copy engine channel");
else if (chan == drm->channel)
- strcpy(fctx->name, "generic kernel channel");
+ strscpy(fctx->name, "generic kernel channel");
else
- strcpy(fctx->name, cli->name);
+ strscpy(fctx->name, cli->name);
kref_init(&fctx->fence_ref);
if (!priv->uevent)
diff --git a/drivers/gpu/drm/nouveau/nouveau_hwmon.c b/drivers/gpu/drm/nouveau/nouveau_hwmon.c
index 5c07a9ee8b77..34effe6d86ad 100644
--- a/drivers/gpu/drm/nouveau/nouveau_hwmon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_hwmon.c
@@ -125,7 +125,7 @@ nouveau_hwmon_get_pwm1_max(struct device *d,
if (ret < 0)
return ret;
- return sprintf(buf, "%i\n", ret);
+ return sysfs_emit(buf, "%i\n", ret);
}
static ssize_t
@@ -141,7 +141,7 @@ nouveau_hwmon_get_pwm1_min(struct device *d,
if (ret < 0)
return ret;
- return sprintf(buf, "%i\n", ret);
+ return sysfs_emit(buf, "%i\n", ret);
}
static ssize_t
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c
index 5b721bd9d799..503760246660 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c
@@ -259,18 +259,16 @@ nvkm_gsp_fwsec_v3(struct nvkm_gsp *gsp, const char *name,
}
static int
-nvkm_gsp_fwsec(struct nvkm_gsp *gsp, const char *name, u32 init_cmd)
+nvkm_gsp_fwsec_init(struct nvkm_gsp *gsp, struct nvkm_falcon_fw *fw, const char *name, u32 init_cmd)
{
struct nvkm_subdev *subdev = &gsp->subdev;
struct nvkm_device *device = subdev->device;
struct nvkm_bios *bios = device->bios;
const union nvfw_falcon_ucode_desc *desc;
struct nvbios_pmuE flcn_ucode;
- u8 idx, ver, hdr;
u32 data;
u16 size, vers;
- struct nvkm_falcon_fw fw = {};
- u32 mbox0 = 0;
+ u8 idx, ver, hdr;
int ret;
/* Lookup in VBIOS. */
@@ -291,8 +289,8 @@ nvkm_gsp_fwsec(struct nvkm_gsp *gsp, const char *name, u32 init_cmd)
vers = (desc->v2.Hdr & 0x0000ff00) >> 8;
switch (vers) {
- case 2: ret = nvkm_gsp_fwsec_v2(gsp, name, &desc->v2, size, init_cmd, &fw); break;
- case 3: ret = nvkm_gsp_fwsec_v3(gsp, name, &desc->v3, size, init_cmd, &fw); break;
+ case 2: ret = nvkm_gsp_fwsec_v2(gsp, name, &desc->v2, size, init_cmd, fw); break;
+ case 3: ret = nvkm_gsp_fwsec_v3(gsp, name, &desc->v3, size, init_cmd, fw); break;
default:
nvkm_error(subdev, "%s(v%d): version unknown\n", name, vers);
return -EINVAL;
@@ -303,15 +301,19 @@ nvkm_gsp_fwsec(struct nvkm_gsp *gsp, const char *name, u32 init_cmd)
return ret;
}
- /* Boot. */
- ret = nvkm_falcon_fw_boot(&fw, subdev, true, &mbox0, NULL, 0, 0);
- nvkm_falcon_fw_dtor(&fw);
- if (ret)
- return ret;
-
return 0;
}
+static int
+nvkm_gsp_fwsec_boot(struct nvkm_gsp *gsp, struct nvkm_falcon_fw *fw)
+{
+ struct nvkm_subdev *subdev = &gsp->subdev;
+ u32 mbox0 = 0;
+
+ /* Boot */
+ return nvkm_falcon_fw_boot(fw, subdev, true, &mbox0, NULL, 0, 0);
+}
+
int
nvkm_gsp_fwsec_sb(struct nvkm_gsp *gsp)
{
@@ -320,7 +322,7 @@ nvkm_gsp_fwsec_sb(struct nvkm_gsp *gsp)
int ret;
u32 err;
- ret = nvkm_gsp_fwsec(gsp, "fwsec-sb", NVFW_FALCON_APPIF_DMEMMAPPER_CMD_SB);
+ ret = nvkm_gsp_fwsec_boot(gsp, &gsp->fws.falcon.sb);
if (ret)
return ret;
@@ -335,26 +337,47 @@ nvkm_gsp_fwsec_sb(struct nvkm_gsp *gsp)
}
int
+nvkm_gsp_fwsec_sb_ctor(struct nvkm_gsp *gsp)
+{
+ return nvkm_gsp_fwsec_init(gsp, &gsp->fws.falcon.sb, "fwsec-sb",
+ NVFW_FALCON_APPIF_DMEMMAPPER_CMD_SB);
+}
+
+void
+nvkm_gsp_fwsec_sb_dtor(struct nvkm_gsp *gsp)
+{
+ nvkm_falcon_fw_dtor(&gsp->fws.falcon.sb);
+}
+
+int
nvkm_gsp_fwsec_frts(struct nvkm_gsp *gsp)
{
struct nvkm_subdev *subdev = &gsp->subdev;
struct nvkm_device *device = subdev->device;
+ struct nvkm_falcon_fw fw = {};
int ret;
u32 err, wpr2_lo, wpr2_hi;
- ret = nvkm_gsp_fwsec(gsp, "fwsec-frts", NVFW_FALCON_APPIF_DMEMMAPPER_CMD_FRTS);
+ ret = nvkm_gsp_fwsec_init(gsp, &fw, "fwsec-frts", NVFW_FALCON_APPIF_DMEMMAPPER_CMD_FRTS);
if (ret)
return ret;
+ ret = nvkm_gsp_fwsec_boot(gsp, &fw);
+ if (ret)
+ goto fwsec_dtor;
+
/* Verify. */
err = nvkm_rd32(device, 0x001400 + (0xe * 4)) >> 16;
if (err) {
nvkm_error(subdev, "fwsec-frts: 0x%04x\n", err);
- return -EIO;
+ ret = -EIO;
+ } else {
+ wpr2_lo = nvkm_rd32(device, 0x1fa824);
+ wpr2_hi = nvkm_rd32(device, 0x1fa828);
+ nvkm_debug(subdev, "fwsec-frts: WPR2 @ %08x - %08x\n", wpr2_lo, wpr2_hi);
}
- wpr2_lo = nvkm_rd32(device, 0x1fa824);
- wpr2_hi = nvkm_rd32(device, 0x1fa828);
- nvkm_debug(subdev, "fwsec-frts: WPR2 @ %08x - %08x\n", wpr2_lo, wpr2_hi);
- return 0;
+fwsec_dtor:
+ nvkm_falcon_fw_dtor(&fw);
+ return ret;
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h
index c3494b7ac572..86bdd203bc10 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h
@@ -6,7 +6,10 @@
enum nvkm_acr_lsf_id;
int nvkm_gsp_fwsec_frts(struct nvkm_gsp *);
+
+int nvkm_gsp_fwsec_sb_ctor(struct nvkm_gsp *);
int nvkm_gsp_fwsec_sb(struct nvkm_gsp *);
+void nvkm_gsp_fwsec_sb_dtor(struct nvkm_gsp *);
struct nvkm_gsp_fwif {
int version;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c
index 32e6a065d6d7..2a7e80c6d70f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c
@@ -1817,12 +1817,16 @@ r535_gsp_rm_boot_ctor(struct nvkm_gsp *gsp)
RM_RISCV_UCODE_DESC *desc;
int ret;
+ ret = nvkm_gsp_fwsec_sb_ctor(gsp);
+ if (ret)
+ return ret;
+
hdr = nvfw_bin_hdr(&gsp->subdev, fw->data);
desc = (void *)fw->data + hdr->header_offset;
ret = nvkm_gsp_mem_ctor(gsp, hdr->data_size, &gsp->boot.fw);
if (ret)
- return ret;
+ goto dtor_fwsec;
memcpy(gsp->boot.fw.data, fw->data + hdr->data_offset, hdr->data_size);
@@ -1831,6 +1835,9 @@ r535_gsp_rm_boot_ctor(struct nvkm_gsp *gsp)
gsp->boot.manifest_offset = desc->manifestOffset;
gsp->boot.app_version = desc->appVersion;
return 0;
+dtor_fwsec:
+ nvkm_gsp_fwsec_sb_dtor(gsp);
+ return ret;
}
static const struct nvkm_firmware_func
@@ -2101,6 +2108,7 @@ r535_gsp_dtor(struct nvkm_gsp *gsp)
mutex_destroy(&gsp->cmdq.mutex);
nvkm_gsp_dtor_fws(gsp);
+ nvkm_gsp_fwsec_sb_dtor(gsp);
nvkm_gsp_mem_dtor(&gsp->rmargs);
nvkm_gsp_mem_dtor(&gsp->wpr_meta);
diff --git a/drivers/gpu/drm/panel/panel-novatek-nt35560.c b/drivers/gpu/drm/panel/panel-novatek-nt35560.c
index 561e6643dcbb..6e5173f98a22 100644
--- a/drivers/gpu/drm/panel/panel-novatek-nt35560.c
+++ b/drivers/gpu/drm/panel/panel-novatek-nt35560.c
@@ -213,7 +213,7 @@ static const struct backlight_properties nt35560_bl_props = {
static void nt35560_read_id(struct mipi_dsi_multi_context *dsi_ctx)
{
- struct device dev = dsi_ctx->dsi->dev;
+ struct device *dev = &dsi_ctx->dsi->dev;
u8 vendor, version, panel;
u16 val;
@@ -225,7 +225,7 @@ static void nt35560_read_id(struct mipi_dsi_multi_context *dsi_ctx)
return;
if (vendor == 0x00) {
- dev_err(&dev, "device vendor ID is zero\n");
+ dev_err(dev, "device vendor ID is zero\n");
dsi_ctx->accum_err = -ENODEV;
return;
}
@@ -236,12 +236,12 @@ static void nt35560_read_id(struct mipi_dsi_multi_context *dsi_ctx)
case DISPLAY_SONY_ACX424AKP_ID2:
case DISPLAY_SONY_ACX424AKP_ID3:
case DISPLAY_SONY_ACX424AKP_ID4:
- dev_info(&dev,
+ dev_info(dev,
"MTP vendor: %02x, version: %02x, panel: %02x\n",
vendor, version, panel);
break;
default:
- dev_info(&dev,
+ dev_info(dev,
"unknown vendor: %02x, version: %02x, panel: %02x\n",
vendor, version, panel);
break;
diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c
index b834123a6560..a6b8024e1a3c 100644
--- a/drivers/gpu/drm/panthor/panthor_sched.c
+++ b/drivers/gpu/drm/panthor/panthor_sched.c
@@ -779,6 +779,12 @@ struct panthor_job_profiling_data {
*/
#define MAX_GROUPS_PER_POOL 128
+/*
+ * Mark added on an entry of group pool Xarray to identify if the group has
+ * been fully initialized and can be accessed elsewhere in the driver code.
+ */
+#define GROUP_REGISTERED XA_MARK_1
+
/**
* struct panthor_group_pool - Group pool
*
@@ -3007,7 +3013,7 @@ void panthor_fdinfo_gather_group_samples(struct panthor_file *pfile)
return;
xa_lock(&gpool->xa);
- xa_for_each(&gpool->xa, i, group) {
+ xa_for_each_marked(&gpool->xa, i, group, GROUP_REGISTERED) {
guard(spinlock)(&group->fdinfo.lock);
pfile->stats.cycles += group->fdinfo.data.cycles;
pfile->stats.time += group->fdinfo.data.time;
@@ -3727,6 +3733,8 @@ int panthor_group_create(struct panthor_file *pfile,
group_init_task_info(group);
+ xa_set_mark(&gpool->xa, gid, GROUP_REGISTERED);
+
return gid;
err_erase_gid:
@@ -3744,6 +3752,9 @@ int panthor_group_destroy(struct panthor_file *pfile, u32 group_handle)
struct panthor_scheduler *sched = ptdev->scheduler;
struct panthor_group *group;
+ if (!xa_get_mark(&gpool->xa, group_handle, GROUP_REGISTERED))
+ return -EINVAL;
+
group = xa_erase(&gpool->xa, group_handle);
if (!group)
return -EINVAL;
@@ -3769,12 +3780,12 @@ int panthor_group_destroy(struct panthor_file *pfile, u32 group_handle)
}
static struct panthor_group *group_from_handle(struct panthor_group_pool *pool,
- u32 group_handle)
+ unsigned long group_handle)
{
struct panthor_group *group;
xa_lock(&pool->xa);
- group = group_get(xa_load(&pool->xa, group_handle));
+ group = group_get(xa_find(&pool->xa, &group_handle, group_handle, GROUP_REGISTERED));
xa_unlock(&pool->xa);
return group;
@@ -3861,7 +3872,7 @@ panthor_fdinfo_gather_group_mem_info(struct panthor_file *pfile,
return;
xa_lock(&gpool->xa);
- xa_for_each(&gpool->xa, i, group) {
+ xa_for_each_marked(&gpool->xa, i, group, GROUP_REGISTERED) {
stats->resident += group->fdinfo.kbo_sizes;
if (group->csg_id >= 0)
stats->active += group->fdinfo.kbo_sizes;
diff --git a/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c b/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c
index 9413b76d0bfc..4ef2e3c129ed 100644
--- a/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c
+++ b/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c
@@ -492,9 +492,9 @@ static void rcar_mipi_dsi_set_display_timing(struct rcar_mipi_dsi *dsi,
/* Configuration for Video Parameters, input is always RGB888 */
vprmset0r = TXVMVPRMSET0R_BPP_24;
- if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+ if (!(mode->flags & DRM_MODE_FLAG_PVSYNC))
vprmset0r |= TXVMVPRMSET0R_VSPOL_LOW;
- if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+ if (!(mode->flags & DRM_MODE_FLAG_PHSYNC))
vprmset0r |= TXVMVPRMSET0R_HSPOL_LOW;
vprmset1r = TXVMVPRMSET1R_VACTIVE(mode->vdisplay)
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
index 5718d9d83a49..52c95131af5a 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
@@ -586,7 +586,7 @@ out:
drm_modeset_unlock(&crtc->mutex);
}
-static void tilcdc_crtc_destroy(struct drm_crtc *crtc)
+void tilcdc_crtc_destroy(struct drm_crtc *crtc)
{
struct tilcdc_drm_private *priv = crtc->dev->dev_private;
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
index 7caec4d38ddf..3dcbec312bac 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -172,8 +172,7 @@ static void tilcdc_fini(struct drm_device *dev)
if (priv->crtc)
tilcdc_crtc_shutdown(priv->crtc);
- if (priv->is_registered)
- drm_dev_unregister(dev);
+ drm_dev_unregister(dev);
drm_kms_helper_poll_fini(dev);
drm_atomic_helper_shutdown(dev);
@@ -220,21 +219,21 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev)
priv->wq = alloc_ordered_workqueue("tilcdc", 0);
if (!priv->wq) {
ret = -ENOMEM;
- goto init_failed;
+ goto put_drm;
}
priv->mmio = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->mmio)) {
dev_err(dev, "failed to request / ioremap\n");
ret = PTR_ERR(priv->mmio);
- goto init_failed;
+ goto free_wq;
}
priv->clk = clk_get(dev, "fck");
if (IS_ERR(priv->clk)) {
dev_err(dev, "failed to get functional clock\n");
ret = -ENODEV;
- goto init_failed;
+ goto free_wq;
}
pm_runtime_enable(dev);
@@ -313,7 +312,7 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev)
ret = tilcdc_crtc_create(ddev);
if (ret < 0) {
dev_err(dev, "failed to create crtc\n");
- goto init_failed;
+ goto disable_pm;
}
modeset_init(ddev);
@@ -324,46 +323,46 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev)
if (ret) {
dev_err(dev, "failed to register cpufreq notifier\n");
priv->freq_transition.notifier_call = NULL;
- goto init_failed;
+ goto destroy_crtc;
}
#endif
if (priv->is_componentized) {
ret = component_bind_all(dev, ddev);
if (ret < 0)
- goto init_failed;
+ goto unregister_cpufreq_notif;
ret = tilcdc_add_component_encoder(ddev);
if (ret < 0)
- goto init_failed;
+ goto unbind_component;
} else {
ret = tilcdc_attach_external_device(ddev);
if (ret)
- goto init_failed;
+ goto unregister_cpufreq_notif;
}
if (!priv->external_connector &&
((priv->num_encoders == 0) || (priv->num_connectors == 0))) {
dev_err(dev, "no encoders/connectors found\n");
ret = -EPROBE_DEFER;
- goto init_failed;
+ goto unbind_component;
}
ret = drm_vblank_init(ddev, 1);
if (ret < 0) {
dev_err(dev, "failed to initialize vblank\n");
- goto init_failed;
+ goto unbind_component;
}
ret = platform_get_irq(pdev, 0);
if (ret < 0)
- goto init_failed;
+ goto unbind_component;
priv->irq = ret;
ret = tilcdc_irq_install(ddev, priv->irq);
if (ret < 0) {
dev_err(dev, "failed to install IRQ handler\n");
- goto init_failed;
+ goto unbind_component;
}
drm_mode_config_reset(ddev);
@@ -372,16 +371,34 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev)
ret = drm_dev_register(ddev, 0);
if (ret)
- goto init_failed;
- priv->is_registered = true;
+ goto stop_poll;
drm_client_setup_with_color_mode(ddev, bpp);
return 0;
-init_failed:
- tilcdc_fini(ddev);
+stop_poll:
+ drm_kms_helper_poll_fini(ddev);
+ tilcdc_irq_uninstall(ddev);
+unbind_component:
+ if (priv->is_componentized)
+ component_unbind_all(dev, ddev);
+unregister_cpufreq_notif:
+#ifdef CONFIG_CPU_FREQ
+ cpufreq_unregister_notifier(&priv->freq_transition,
+ CPUFREQ_TRANSITION_NOTIFIER);
+destroy_crtc:
+#endif
+ tilcdc_crtc_destroy(priv->crtc);
+disable_pm:
+ pm_runtime_disable(dev);
+ clk_put(priv->clk);
+free_wq:
+ destroy_workqueue(priv->wq);
+put_drm:
platform_set_drvdata(pdev, NULL);
+ ddev->dev_private = NULL;
+ drm_dev_put(ddev);
return ret;
}
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
index b818448c83f6..58b276f82a66 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
@@ -82,7 +82,6 @@ struct tilcdc_drm_private {
struct drm_encoder *external_encoder;
struct drm_connector *external_connector;
- bool is_registered;
bool is_componentized;
bool irq_enabled;
};
@@ -164,6 +163,7 @@ void tilcdc_crtc_set_panel_info(struct drm_crtc *crtc,
void tilcdc_crtc_set_simulate_vesa_sync(struct drm_crtc *crtc,
bool simulate_vesa_sync);
void tilcdc_crtc_shutdown(struct drm_crtc *crtc);
+void tilcdc_crtc_destroy(struct drm_crtc *crtc);
int tilcdc_crtc_update_fb(struct drm_crtc *crtc,
struct drm_framebuffer *fb,
struct drm_pending_vblank_event *event);
diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c
index b47020fca199..e6abc7b40b18 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_vm.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c
@@ -434,6 +434,11 @@ int ttm_bo_access(struct ttm_buffer_object *bo, unsigned long offset,
if (ret)
return ret;
+ if (!bo->resource) {
+ ret = -ENODATA;
+ goto unlock;
+ }
+
switch (bo->resource->mem_type) {
case TTM_PL_SYSTEM:
fallthrough;
@@ -448,6 +453,7 @@ int ttm_bo_access(struct ttm_buffer_object *bo, unsigned long offset,
ret = -EIO;
}
+unlock:
ttm_bo_unreserve(bo);
return ret;
diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c
index a444d41e53b6..472bca54642b 100644
--- a/drivers/hid/hid-asus.c
+++ b/drivers/hid/hid-asus.c
@@ -27,6 +27,7 @@
#include <linux/hid.h>
#include <linux/module.h>
#include <linux/platform_data/x86/asus-wmi.h>
+#include <linux/platform_data/x86/asus-wmi-leds-ids.h>
#include <linux/input/mt.h>
#include <linux/usb.h> /* For to_usb_interface for T100 touchpad intf check */
#include <linux/power_supply.h>
diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c
index fd563e845d4b..a87ecea7f510 100644
--- a/drivers/i2c/algos/i2c-algo-pcf.c
+++ b/drivers/i2c/algos/i2c-algo-pcf.c
@@ -23,17 +23,8 @@
#include "i2c-algo-pcf.h"
-#define DEB2(x) if (i2c_debug >= 2) x
-#define DEB3(x) if (i2c_debug >= 3) x /* print several statistical values */
-#define DEBPROTO(x) if (i2c_debug >= 9) x;
- /* debug the protocol by showing transferred bits */
#define DEF_TIMEOUT 16
-/*
- * module parameters:
- */
-static int i2c_debug;
-
/* setting states on the bus with the right timing: */
#define set_pcf(adap, ctl, val) adap->setpcf(adap->data, ctl, val)
@@ -47,27 +38,21 @@ static int i2c_debug;
static void i2c_start(struct i2c_algo_pcf_data *adap)
{
- DEBPROTO(printk(KERN_DEBUG "S "));
set_pcf(adap, 1, I2C_PCF_START);
}
static void i2c_repstart(struct i2c_algo_pcf_data *adap)
{
- DEBPROTO(printk(" Sr "));
set_pcf(adap, 1, I2C_PCF_REPSTART);
}
static void i2c_stop(struct i2c_algo_pcf_data *adap)
{
- DEBPROTO(printk("P\n"));
set_pcf(adap, 1, I2C_PCF_STOP);
}
static void handle_lab(struct i2c_algo_pcf_data *adap, const int *status)
{
- DEB2(printk(KERN_INFO
- "i2c-algo-pcf.o: lost arbitration (CSR 0x%02x)\n",
- *status));
/*
* Cleanup from LAB -- reset and enable ESO.
* This resets the PCF8584; since we've lost the bus, no
@@ -88,9 +73,6 @@ static void handle_lab(struct i2c_algo_pcf_data *adap, const int *status)
if (adap->lab_mdelay)
mdelay(adap->lab_mdelay);
- DEB2(printk(KERN_INFO
- "i2c-algo-pcf.o: reset LAB condition (CSR 0x%02x)\n",
- get_pcf(adap, 1)));
}
static int wait_for_bb(struct i2c_algo_pcf_data *adap)
@@ -147,56 +129,48 @@ static int wait_for_pin(struct i2c_algo_pcf_data *adap, int *status)
*
* vdovikin: added detect code for PCF8584
*/
-static int pcf_init_8584 (struct i2c_algo_pcf_data *adap)
+static int pcf_init_8584(struct i2c_algo_pcf_data *adap)
{
unsigned char temp;
- DEB3(printk(KERN_DEBUG "i2c-algo-pcf.o: PCF state 0x%02x\n",
- get_pcf(adap, 1)));
-
/* S1=0x80: S0 selected, serial interface off */
set_pcf(adap, 1, I2C_PCF_PIN);
/*
* check to see S1 now used as R/W ctrl -
* PCF8584 does that when ESO is zero
*/
- if (((temp = get_pcf(adap, 1)) & 0x7f) != (0)) {
- DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S0 (0x%02x).\n", temp));
+ temp = get_pcf(adap, 1);
+ if ((temp & 0x7f) != 0)
return -ENXIO; /* definitely not PCF8584 */
- }
/* load own address in S0, effective address is (own << 1) */
i2c_outb(adap, get_own(adap));
/* check it's really written */
- if ((temp = i2c_inb(adap)) != get_own(adap)) {
- DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't set S0 (0x%02x).\n", temp));
+ temp = i2c_inb(adap);
+ if (temp != get_own(adap))
return -ENXIO;
- }
/* S1=0xA0, next byte in S2 */
set_pcf(adap, 1, I2C_PCF_PIN | I2C_PCF_ES1);
/* check to see S2 now selected */
- if (((temp = get_pcf(adap, 1)) & 0x7f) != I2C_PCF_ES1) {
- DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S2 (0x%02x).\n", temp));
+ temp = get_pcf(adap, 1);
+ if ((temp & 0x7f) != I2C_PCF_ES1)
return -ENXIO;
- }
/* load clock register S2 */
i2c_outb(adap, get_clock(adap));
/* check it's really written, the only 5 lowest bits does matter */
- if (((temp = i2c_inb(adap)) & 0x1f) != get_clock(adap)) {
- DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't set S2 (0x%02x).\n", temp));
+ temp = i2c_inb(adap);
+ if ((temp & 0x1f) != get_clock(adap))
return -ENXIO;
- }
/* Enable serial interface, idle, S0 selected */
set_pcf(adap, 1, I2C_PCF_IDLE);
/* check to see PCF is really idled and we can access status register */
- if ((temp = get_pcf(adap, 1)) != (I2C_PCF_PIN | I2C_PCF_BB)) {
- DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S1` (0x%02x).\n", temp));
+ temp = get_pcf(adap, 1);
+ if (temp != (I2C_PCF_PIN | I2C_PCF_BB))
return -ENXIO;
- }
printk(KERN_DEBUG "i2c-algo-pcf.o: detected and initialized PCF8584.\n");
@@ -209,9 +183,7 @@ static int pcf_sendbytes(struct i2c_adapter *i2c_adap, const char *buf,
struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
int wrcount, status, timeout;
- for (wrcount=0; wrcount<count; ++wrcount) {
- DEB2(dev_dbg(&i2c_adap->dev, "i2c_write: writing %2.2X\n",
- buf[wrcount] & 0xff));
+ for (wrcount = 0; wrcount < count; ++wrcount) {
i2c_outb(adap, buf[wrcount]);
timeout = wait_for_pin(adap, &status);
if (timeout) {
@@ -246,7 +218,8 @@ static int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf,
/* increment number of bytes to read by one -- read dummy byte */
for (i = 0; i <= count; i++) {
- if ((wfp = wait_for_pin(adap, &status))) {
+ wfp = wait_for_pin(adap, &status);
+ if (wfp) {
if (wfp == -EINTR)
return -EINTR; /* arbitration lost */
@@ -280,7 +253,7 @@ static int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf,
}
-static int pcf_doAddress(struct i2c_algo_pcf_data *adap,
+static void pcf_send_address(struct i2c_algo_pcf_data *adap,
struct i2c_msg *msg)
{
unsigned char addr = i2c_8bit_addr_from_msg(msg);
@@ -288,8 +261,6 @@ static int pcf_doAddress(struct i2c_algo_pcf_data *adap,
if (msg->flags & I2C_M_REV_DIR_ADDR)
addr ^= 1;
i2c_outb(adap, addr);
-
- return 0;
}
static int pcf_xfer(struct i2c_adapter *i2c_adap,
@@ -299,7 +270,7 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap,
struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
struct i2c_msg *pmsg;
int i;
- int ret=0, timeout, status;
+ int timeout, status;
if (adap->xfer_begin)
adap->xfer_begin(adap->data);
@@ -307,20 +278,15 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap,
/* Check for bus busy */
timeout = wait_for_bb(adap);
if (timeout) {
- DEB2(printk(KERN_ERR "i2c-algo-pcf.o: "
- "Timeout waiting for BB in pcf_xfer\n");)
i = -EIO;
goto out;
}
- for (i = 0;ret >= 0 && i < num; i++) {
- pmsg = &msgs[i];
-
- DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: Doing %s %d bytes to 0x%02x - %d of %d messages\n",
- str_read_write(pmsg->flags & I2C_M_RD),
- pmsg->len, pmsg->addr, i + 1, num);)
+ for (i = 0; i < num; i++) {
+ int ret;
- ret = pcf_doAddress(adap, pmsg);
+ pmsg = &msgs[i];
+ pcf_send_address(adap, pmsg);
/* Send START */
if (i == 0)
@@ -335,8 +301,6 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap,
goto out;
}
i2c_stop(adap);
- DEB2(printk(KERN_ERR "i2c-algo-pcf.o: Timeout waiting "
- "for PIN(1) in pcf_xfer\n");)
i = -EREMOTEIO;
goto out;
}
@@ -344,35 +308,21 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap,
/* Check LRB (last rcvd bit - slave ack) */
if (status & I2C_PCF_LRB) {
i2c_stop(adap);
- DEB2(printk(KERN_ERR "i2c-algo-pcf.o: No LRB(1) in pcf_xfer\n");)
i = -EREMOTEIO;
goto out;
}
- DEB3(printk(KERN_DEBUG "i2c-algo-pcf.o: Msg %d, addr=0x%x, flags=0x%x, len=%d\n",
- i, msgs[i].addr, msgs[i].flags, msgs[i].len);)
if (pmsg->flags & I2C_M_RD) {
ret = pcf_readbytes(i2c_adap, pmsg->buf, pmsg->len,
(i + 1 == num));
-
- if (ret != pmsg->len) {
- DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: fail: "
- "only read %d bytes.\n",ret));
- } else {
- DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: read %d bytes.\n",ret));
- }
} else {
ret = pcf_sendbytes(i2c_adap, pmsg->buf, pmsg->len,
(i + 1 == num));
-
- if (ret != pmsg->len) {
- DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: fail: "
- "only wrote %d bytes.\n",ret));
- } else {
- DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: wrote %d bytes.\n",ret));
- }
}
+
+ if (ret < 0)
+ goto out;
}
out:
@@ -401,12 +351,11 @@ int i2c_pcf_add_bus(struct i2c_adapter *adap)
struct i2c_algo_pcf_data *pcf_adap = adap->algo_data;
int rval;
- DEB2(dev_dbg(&adap->dev, "hw routines registered.\n"));
-
/* register new adapter to i2c module... */
adap->algo = &pcf_algo;
- if ((rval = pcf_init_8584(pcf_adap)))
+ rval = pcf_init_8584(pcf_adap);
+ if (rval)
return rval;
rval = i2c_add_adapter(adap);
@@ -418,7 +367,3 @@ EXPORT_SYMBOL(i2c_pcf_add_bus);
MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>");
MODULE_DESCRIPTION("I2C-Bus PCF8584 algorithm");
MODULE_LICENSE("GPL");
-
-module_param(i2c_debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(i2c_debug,
- "debug level - 0 off; 1 normal; 2,3 more verbose; 9 pcf-protocol");
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index fd81e49638aa..cea87fcb4a1a 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -166,6 +166,7 @@ config I2C_I801
Arrow Lake (SOC)
Panther Lake (SOC)
Wildcat Lake (SOC)
+ Diamond Rapids (SOC)
This driver can also be built as a module. If so, the module
will be called i2c-i801.
@@ -1474,7 +1475,7 @@ config I2C_ACORN
config I2C_ELEKTOR
tristate "Elektor ISA card"
- depends on ISA && HAS_IOPORT_MAP && BROKEN_ON_SMP
+ depends on ISA && HAS_IOPORT_MAP
select I2C_ALGOPCF
help
This supports the PCF8584 ISA bus I2C adapter. Say Y if you own
diff --git a/drivers/i2c/busses/i2c-amd-mp2-pci.c b/drivers/i2c/busses/i2c-amd-mp2-pci.c
index ef7370d3dbea..60edbabc2986 100644
--- a/drivers/i2c/busses/i2c-amd-mp2-pci.c
+++ b/drivers/i2c/busses/i2c-amd-mp2-pci.c
@@ -458,13 +458,16 @@ struct amd_mp2_dev *amd_mp2_find_device(void)
{
struct device *dev;
struct pci_dev *pci_dev;
+ struct amd_mp2_dev *mp2_dev;
dev = driver_find_next_device(&amd_mp2_pci_driver.driver, NULL);
if (!dev)
return NULL;
pci_dev = to_pci_dev(dev);
- return (struct amd_mp2_dev *)pci_get_drvdata(pci_dev);
+ mp2_dev = (struct amd_mp2_dev *)pci_get_drvdata(pci_dev);
+ put_device(dev);
+ return mp2_dev;
}
EXPORT_SYMBOL_GPL(amd_mp2_find_device);
diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c
index 8554e790f8e3..0d7e2654a534 100644
--- a/drivers/i2c/busses/i2c-bcm2835.c
+++ b/drivers/i2c/busses/i2c-bcm2835.c
@@ -137,12 +137,14 @@ static int clk_bcm2835_i2c_set_rate(struct clk_hw *hw, unsigned long rate,
return 0;
}
-static long clk_bcm2835_i2c_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *parent_rate)
+static int clk_bcm2835_i2c_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
- u32 divider = clk_bcm2835_i2c_calc_divider(rate, *parent_rate);
+ u32 divider = clk_bcm2835_i2c_calc_divider(req->rate, req->best_parent_rate);
- return DIV_ROUND_UP(*parent_rate, divider);
+ req->rate = DIV_ROUND_UP(req->best_parent_rate, divider);
+
+ return 0;
}
static unsigned long clk_bcm2835_i2c_recalc_rate(struct clk_hw *hw,
@@ -156,7 +158,7 @@ static unsigned long clk_bcm2835_i2c_recalc_rate(struct clk_hw *hw,
static const struct clk_ops clk_bcm2835_i2c_ops = {
.set_rate = clk_bcm2835_i2c_set_rate,
- .round_rate = clk_bcm2835_i2c_round_rate,
+ .determine_rate = clk_bcm2835_i2c_determine_rate,
.recalc_rate = clk_bcm2835_i2c_recalc_rate,
};
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index 347843b4f5dd..bb5ce0a382f9 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -78,6 +78,7 @@
#define DW_IC_TX_ABRT_SOURCE 0x80
#define DW_IC_ENABLE_STATUS 0x9c
#define DW_IC_CLR_RESTART_DET 0xa8
+#define DW_IC_SMBUS_INTR_MASK 0xcc
#define DW_IC_COMP_PARAM_1 0xf4
#define DW_IC_COMP_VERSION 0xf8
#define DW_IC_SDA_HOLD_MIN_VERS 0x3131312A /* "111*" == v1.11* */
@@ -330,7 +331,6 @@ struct dw_i2c_dev {
struct i2c_dw_semaphore_callbacks {
int (*probe)(struct dw_i2c_dev *dev);
- void (*remove)(struct dw_i2c_dev *dev);
};
int i2c_dw_init_regmap(struct dw_i2c_dev *dev);
diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c
index 41e9b5ecad20..45bfca05bb30 100644
--- a/drivers/i2c/busses/i2c-designware-master.c
+++ b/drivers/i2c/busses/i2c-designware-master.c
@@ -220,6 +220,13 @@ static int i2c_dw_init_master(struct dw_i2c_dev *dev)
/* Disable the adapter */
__i2c_dw_disable(dev);
+ /*
+ * Mask SMBus interrupts to block storms from broken
+ * firmware that leaves IC_SMBUS=1; the handler never
+ * services them.
+ */
+ regmap_write(dev->map, DW_IC_SMBUS_INTR_MASK, 0);
+
/* Write standard speed timing parameters */
regmap_write(dev->map, DW_IC_SS_SCL_HCNT, dev->ss_hcnt);
regmap_write(dev->map, DW_IC_SS_SCL_LCNT, dev->ss_lcnt);
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index 34d881572351..7be99656a67d 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -197,15 +197,6 @@ static int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev)
return 0;
}
-static void i2c_dw_remove_lock_support(struct dw_i2c_dev *dev)
-{
- if (dev->semaphore_idx < 0)
- return;
-
- if (i2c_dw_semaphore_cb_table[dev->semaphore_idx].remove)
- i2c_dw_semaphore_cb_table[dev->semaphore_idx].remove(dev);
-}
-
static int dw_i2c_plat_probe(struct platform_device *pdev)
{
u32 flags = (uintptr_t)device_get_match_data(&pdev->dev);
@@ -248,7 +239,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
ret = i2c_dw_probe_lock_support(dev);
if (ret) {
- ret = dev_err_probe(device, ret, "failed to probe lock support\n");
+ dev_err_probe(device, ret, "failed to probe lock support\n");
goto exit_reset;
}
@@ -339,8 +330,6 @@ static void dw_i2c_plat_remove(struct platform_device *pdev)
i2c_dw_prepare_clk(dev, false);
- i2c_dw_remove_lock_support(dev);
-
reset_control_assert(dev->rst);
}
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 57fbec1259be..81e6e2d7ad3d 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -84,6 +84,7 @@
* Panther Lake-H (SOC) 0xe322 32 hard yes yes yes
* Panther Lake-P (SOC) 0xe422 32 hard yes yes yes
* Wildcat Lake-U (SOC) 0x4d22 32 hard yes yes yes
+ * Diamond Rapids (SOC) 0x5827 32 hard yes yes yes
*
* Features supported by this driver:
* Software PEC no
@@ -242,6 +243,7 @@
#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_P_SMBUS 0x51a3
#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_M_SMBUS 0x54a3
#define PCI_DEVICE_ID_INTEL_BIRCH_STREAM_SMBUS 0x5796
+#define PCI_DEVICE_ID_INTEL_DIAMOND_RAPIDS_SMBUS 0x5827
#define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS 0x5ad4
#define PCI_DEVICE_ID_INTEL_ARROW_LAKE_H_SMBUS 0x7722
#define PCI_DEVICE_ID_INTEL_RAPTOR_LAKE_S_SMBUS 0x7a23
@@ -1054,6 +1056,7 @@ static const struct pci_device_id i801_ids[] = {
{ PCI_DEVICE_DATA(INTEL, METEOR_LAKE_SOC_S_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) },
{ PCI_DEVICE_DATA(INTEL, METEOR_LAKE_PCH_S_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) },
{ PCI_DEVICE_DATA(INTEL, BIRCH_STREAM_SMBUS, FEATURES_ICH5) },
+ { PCI_DEVICE_DATA(INTEL, DIAMOND_RAPIDS_SMBUS, FEATURES_ICH5) },
{ PCI_DEVICE_DATA(INTEL, ARROW_LAKE_H_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) },
{ PCI_DEVICE_DATA(INTEL, PANTHER_LAKE_H_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) },
{ PCI_DEVICE_DATA(INTEL, PANTHER_LAKE_P_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) },
diff --git a/drivers/i2c/busses/i2c-k1.c b/drivers/i2c/busses/i2c-k1.c
index 6b918770e612..d42c03ef5db5 100644
--- a/drivers/i2c/busses/i2c-k1.c
+++ b/drivers/i2c/busses/i2c-k1.c
@@ -158,11 +158,16 @@ static int spacemit_i2c_handle_err(struct spacemit_i2c_dev *i2c)
{
dev_dbg(i2c->dev, "i2c error status: 0x%08x\n", i2c->status);
- if (i2c->status & (SPACEMIT_SR_BED | SPACEMIT_SR_ALD)) {
+ /* Arbitration Loss Detected */
+ if (i2c->status & SPACEMIT_SR_ALD) {
spacemit_i2c_reset(i2c);
return -EAGAIN;
}
+ /* Bus Error No ACK/NAK */
+ if (i2c->status & SPACEMIT_SR_BED)
+ spacemit_i2c_reset(i2c);
+
return i2c->status & SPACEMIT_SR_ACKNAK ? -ENXIO : -EIO;
}
@@ -224,6 +229,12 @@ static void spacemit_i2c_check_bus_release(struct spacemit_i2c_dev *i2c)
}
}
+static inline void
+spacemit_i2c_clear_int_status(struct spacemit_i2c_dev *i2c, u32 mask)
+{
+ writel(mask & SPACEMIT_I2C_INT_STATUS_MASK, i2c->base + SPACEMIT_ISR);
+}
+
static void spacemit_i2c_init(struct spacemit_i2c_dev *i2c)
{
u32 val;
@@ -267,12 +278,8 @@ static void spacemit_i2c_init(struct spacemit_i2c_dev *i2c)
val = readl(i2c->base + SPACEMIT_IRCR);
val |= SPACEMIT_RCR_SDA_GLITCH_NOFIX;
writel(val, i2c->base + SPACEMIT_IRCR);
-}
-static inline void
-spacemit_i2c_clear_int_status(struct spacemit_i2c_dev *i2c, u32 mask)
-{
- writel(mask & SPACEMIT_I2C_INT_STATUS_MASK, i2c->base + SPACEMIT_ISR);
+ spacemit_i2c_clear_int_status(i2c, SPACEMIT_I2C_INT_STATUS_MASK);
}
static void spacemit_i2c_start(struct spacemit_i2c_dev *i2c)
diff --git a/drivers/i2c/busses/i2c-qcom-cci.c b/drivers/i2c/busses/i2c-qcom-cci.c
index e631d79baf14..884055df1560 100644
--- a/drivers/i2c/busses/i2c-qcom-cci.c
+++ b/drivers/i2c/busses/i2c-qcom-cci.c
@@ -783,8 +783,54 @@ static const struct cci_data cci_v2_data = {
},
};
+static const struct cci_data cci_msm8953_data = {
+ .num_masters = 2,
+ .queue_size = { 64, 16 },
+ .quirks = {
+ .max_write_len = 11,
+ .max_read_len = 12,
+ },
+ .params[I2C_MODE_STANDARD] = {
+ .thigh = 78,
+ .tlow = 114,
+ .tsu_sto = 28,
+ .tsu_sta = 28,
+ .thd_dat = 10,
+ .thd_sta = 77,
+ .tbuf = 118,
+ .scl_stretch_en = 0,
+ .trdhld = 6,
+ .tsp = 1
+ },
+ .params[I2C_MODE_FAST] = {
+ .thigh = 20,
+ .tlow = 28,
+ .tsu_sto = 21,
+ .tsu_sta = 21,
+ .thd_dat = 13,
+ .thd_sta = 18,
+ .tbuf = 32,
+ .scl_stretch_en = 0,
+ .trdhld = 6,
+ .tsp = 3
+ },
+ .params[I2C_MODE_FAST_PLUS] = {
+ .thigh = 16,
+ .tlow = 22,
+ .tsu_sto = 17,
+ .tsu_sta = 18,
+ .thd_dat = 16,
+ .thd_sta = 15,
+ .tbuf = 19,
+ .scl_stretch_en = 1,
+ .trdhld = 3,
+ .tsp = 3
+ },
+};
+
static const struct of_device_id cci_dt_match[] = {
{ .compatible = "qcom,msm8226-cci", .data = &cci_v1_data},
+ { .compatible = "qcom,msm8953-cci", .data = &cci_msm8953_data},
{ .compatible = "qcom,msm8974-cci", .data = &cci_v1_5_data},
{ .compatible = "qcom,msm8996-cci", .data = &cci_v2_data},
diff --git a/drivers/i2c/busses/i2c-stm32.c b/drivers/i2c/busses/i2c-stm32.c
index f84ec056e36d..becf8977979f 100644
--- a/drivers/i2c/busses/i2c-stm32.c
+++ b/drivers/i2c/busses/i2c-stm32.c
@@ -27,8 +27,8 @@ struct stm32_i2c_dma *stm32_i2c_dma_request(struct device *dev,
if (IS_ERR(dma->chan_tx)) {
ret = PTR_ERR(dma->chan_tx);
if (ret != -ENODEV)
- ret = dev_err_probe(dev, ret,
- "can't request DMA tx channel\n");
+ dev_err_probe(dev, ret, "can't request DMA tx channel\n");
+
goto fail_al;
}
@@ -48,8 +48,7 @@ struct stm32_i2c_dma *stm32_i2c_dma_request(struct device *dev,
if (IS_ERR(dma->chan_rx)) {
ret = PTR_ERR(dma->chan_rx);
if (ret != -ENODEV)
- ret = dev_err_probe(dev, ret,
- "can't request DMA rx channel\n");
+ dev_err_probe(dev, ret, "can't request DMA rx channel\n");
goto fail_tx;
}
diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
index f88f7e19203a..7f606c871648 100644
--- a/drivers/i3c/master.c
+++ b/drivers/i3c/master.c
@@ -1742,11 +1742,10 @@ EXPORT_SYMBOL_GPL(i3c_master_do_daa);
struct i3c_dma *i3c_master_dma_map_single(struct device *dev, void *buf,
size_t len, bool force_bounce, enum dma_data_direction dir)
{
- struct i3c_dma *dma_xfer __free(kfree) = NULL;
void *bounce __free(kfree) = NULL;
void *dma_buf = buf;
- dma_xfer = kzalloc(sizeof(*dma_xfer), GFP_KERNEL);
+ struct i3c_dma *dma_xfer __free(kfree) = kzalloc(sizeof(*dma_xfer), GFP_KERNEL);
if (!dma_xfer)
return NULL;
@@ -2819,14 +2818,10 @@ EXPORT_SYMBOL_GPL(i3c_generic_ibi_recycle_slot);
static int i3c_master_check_ops(const struct i3c_master_controller_ops *ops)
{
- if (!ops || !ops->bus_init ||
+ if (!ops || !ops->bus_init || !ops->i3c_xfers ||
!ops->send_ccc_cmd || !ops->do_daa || !ops->i2c_xfers)
return -EINVAL;
- /* Must provide one of priv_xfers (SDR only) or i3c_xfers (all modes) */
- if (!ops->priv_xfers && !ops->i3c_xfers)
- return -EINVAL;
-
if (ops->request_ibi &&
(!ops->enable_ibi || !ops->disable_ibi || !ops->free_ibi ||
!ops->recycle_ibi_slot))
@@ -3031,13 +3026,7 @@ int i3c_dev_do_xfers_locked(struct i3c_dev_desc *dev, struct i3c_xfer *xfers,
if (mode != I3C_SDR && !(master->this->info.hdr_cap & BIT(mode)))
return -EOPNOTSUPP;
- if (master->ops->i3c_xfers)
- return master->ops->i3c_xfers(dev, xfers, nxfers, mode);
-
- if (mode != I3C_SDR)
- return -EINVAL;
-
- return master->ops->priv_xfers(dev, xfers, nxfers);
+ return master->ops->i3c_xfers(dev, xfers, nxfers, mode);
}
int i3c_dev_disable_ibi_locked(struct i3c_dev_desc *dev)
diff --git a/drivers/i3c/master/adi-i3c-master.c b/drivers/i3c/master/adi-i3c-master.c
index 82ac0b3d057a..6380a38e6d29 100644
--- a/drivers/i3c/master/adi-i3c-master.c
+++ b/drivers/i3c/master/adi-i3c-master.c
@@ -332,10 +332,9 @@ static int adi_i3c_master_send_ccc_cmd(struct i3c_master_controller *m,
struct i3c_ccc_cmd *cmd)
{
struct adi_i3c_master *master = to_adi_i3c_master(m);
- struct adi_i3c_xfer *xfer __free(kfree) = NULL;
struct adi_i3c_cmd *ccmd;
- xfer = adi_i3c_master_alloc_xfer(master, 1);
+ struct adi_i3c_xfer *xfer __free(kfree) = adi_i3c_master_alloc_xfer(master, 1);
if (!xfer)
return -ENOMEM;
@@ -365,19 +364,18 @@ static int adi_i3c_master_send_ccc_cmd(struct i3c_master_controller *m,
return 0;
}
-static int adi_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
- struct i3c_priv_xfer *xfers,
- int nxfers)
+static int adi_i3c_master_i3c_xfers(struct i3c_dev_desc *dev,
+ struct i3c_xfer *xfers,
+ int nxfers, enum i3c_xfer_mode mode)
{
struct i3c_master_controller *m = i3c_dev_get_master(dev);
struct adi_i3c_master *master = to_adi_i3c_master(m);
- struct adi_i3c_xfer *xfer __free(kfree) = NULL;
int i, ret;
if (!nxfers)
return 0;
- xfer = adi_i3c_master_alloc_xfer(master, nxfers);
+ struct adi_i3c_xfer *xfer __free(kfree) = adi_i3c_master_alloc_xfer(master, nxfers);
if (!xfer)
return -ENOMEM;
@@ -777,7 +775,6 @@ static int adi_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
{
struct i3c_master_controller *m = i2c_dev_get_master(dev);
struct adi_i3c_master *master = to_adi_i3c_master(m);
- struct adi_i3c_xfer *xfer __free(kfree) = NULL;
int i;
if (!nxfers)
@@ -786,7 +783,8 @@ static int adi_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
if (xfers[i].flags & I2C_M_TEN)
return -EOPNOTSUPP;
}
- xfer = adi_i3c_master_alloc_xfer(master, nxfers);
+
+ struct adi_i3c_xfer *xfer __free(kfree) = adi_i3c_master_alloc_xfer(master, nxfers);
if (!xfer)
return -ENOMEM;
@@ -919,7 +917,7 @@ static const struct i3c_master_controller_ops adi_i3c_master_ops = {
.do_daa = adi_i3c_master_do_daa,
.supports_ccc_cmd = adi_i3c_master_supports_ccc_cmd,
.send_ccc_cmd = adi_i3c_master_send_ccc_cmd,
- .priv_xfers = adi_i3c_master_priv_xfers,
+ .i3c_xfers = adi_i3c_master_i3c_xfers,
.i2c_xfers = adi_i3c_master_i2c_xfers,
.request_ibi = adi_i3c_master_request_ibi,
.enable_ibi = adi_i3c_master_enable_ibi,
diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c
index 276592a8222e..889e2ed5bc83 100644
--- a/drivers/i3c/master/dw-i3c-master.c
+++ b/drivers/i3c/master/dw-i3c-master.c
@@ -902,9 +902,9 @@ rpm_out:
return ret;
}
-static int dw_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
- struct i3c_priv_xfer *i3c_xfers,
- int i3c_nxfers)
+static int dw_i3c_master_i3c_xfers(struct i3c_dev_desc *dev,
+ struct i3c_xfer *i3c_xfers,
+ int i3c_nxfers, enum i3c_xfer_mode mode)
{
struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
struct i3c_master_controller *m = i3c_dev_get_master(dev);
@@ -1498,7 +1498,7 @@ static const struct i3c_master_controller_ops dw_mipi_i3c_ops = {
.do_daa = dw_i3c_master_daa,
.supports_ccc_cmd = dw_i3c_master_supports_ccc_cmd,
.send_ccc_cmd = dw_i3c_master_send_ccc_cmd,
- .priv_xfers = dw_i3c_master_priv_xfers,
+ .i3c_xfers = dw_i3c_master_i3c_xfers,
.attach_i2c_dev = dw_i3c_master_attach_i2c_dev,
.detach_i2c_dev = dw_i3c_master_detach_i2c_dev,
.i2c_xfers = dw_i3c_master_i2c_xfers,
diff --git a/drivers/i3c/master/i3c-master-cdns.c b/drivers/i3c/master/i3c-master-cdns.c
index 97b151564d3d..8eb76b8ca2b0 100644
--- a/drivers/i3c/master/i3c-master-cdns.c
+++ b/drivers/i3c/master/i3c-master-cdns.c
@@ -720,9 +720,9 @@ static int cdns_i3c_master_send_ccc_cmd(struct i3c_master_controller *m,
return ret;
}
-static int cdns_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
- struct i3c_priv_xfer *xfers,
- int nxfers)
+static int cdns_i3c_master_i3c_xfers(struct i3c_dev_desc *dev,
+ struct i3c_xfer *xfers,
+ int nxfers, enum i3c_xfer_mode mode)
{
struct i3c_master_controller *m = i3c_dev_get_master(dev);
struct cdns_i3c_master *master = to_cdns_i3c_master(m);
@@ -1519,7 +1519,7 @@ static const struct i3c_master_controller_ops cdns_i3c_master_ops = {
.detach_i2c_dev = cdns_i3c_master_detach_i2c_dev,
.supports_ccc_cmd = cdns_i3c_master_supports_ccc_cmd,
.send_ccc_cmd = cdns_i3c_master_send_ccc_cmd,
- .priv_xfers = cdns_i3c_master_priv_xfers,
+ .i3c_xfers = cdns_i3c_master_i3c_xfers,
.i2c_xfers = cdns_i3c_master_i2c_xfers,
.enable_ibi = cdns_i3c_master_enable_ibi,
.disable_ibi = cdns_i3c_master_disable_ibi,
diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c
index 47e42cb4dbe7..607d77ab0e54 100644
--- a/drivers/i3c/master/mipi-i3c-hci/core.c
+++ b/drivers/i3c/master/mipi-i3c-hci/core.c
@@ -266,9 +266,9 @@ static int i3c_hci_daa(struct i3c_master_controller *m)
return hci->cmd->perform_daa(hci);
}
-static int i3c_hci_priv_xfers(struct i3c_dev_desc *dev,
- struct i3c_priv_xfer *i3c_xfers,
- int nxfers)
+static int i3c_hci_i3c_xfers(struct i3c_dev_desc *dev,
+ struct i3c_xfer *i3c_xfers, int nxfers,
+ enum i3c_xfer_mode mode)
{
struct i3c_master_controller *m = i3c_dev_get_master(dev);
struct i3c_hci *hci = to_i3c_hci(m);
@@ -515,7 +515,7 @@ static const struct i3c_master_controller_ops i3c_hci_ops = {
.bus_cleanup = i3c_hci_bus_cleanup,
.do_daa = i3c_hci_daa,
.send_ccc_cmd = i3c_hci_send_ccc_cmd,
- .priv_xfers = i3c_hci_priv_xfers,
+ .i3c_xfers = i3c_hci_i3c_xfers,
.i2c_xfers = i3c_hci_i2c_xfers,
.attach_i3c_dev = i3c_hci_attach_i3c_dev,
.reattach_i3c_dev = i3c_hci_reattach_i3c_dev,
diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c
index 275f7b924288..426a418f29b6 100644
--- a/drivers/i3c/master/renesas-i3c.c
+++ b/drivers/i3c/master/renesas-i3c.c
@@ -794,8 +794,8 @@ static int renesas_i3c_send_ccc_cmd(struct i3c_master_controller *m,
return ret;
}
-static int renesas_i3c_priv_xfers(struct i3c_dev_desc *dev, struct i3c_priv_xfer *i3c_xfers,
- int i3c_nxfers)
+static int renesas_i3c_i3c_xfers(struct i3c_dev_desc *dev, struct i3c_xfer *i3c_xfers,
+ int i3c_nxfers, enum i3c_xfer_mode mode)
{
struct i3c_master_controller *m = i3c_dev_get_master(dev);
struct renesas_i3c *i3c = to_renesas_i3c(m);
@@ -1282,7 +1282,7 @@ static const struct i3c_master_controller_ops renesas_i3c_ops = {
.do_daa = renesas_i3c_daa,
.supports_ccc_cmd = renesas_i3c_supports_ccc_cmd,
.send_ccc_cmd = renesas_i3c_send_ccc_cmd,
- .priv_xfers = renesas_i3c_priv_xfers,
+ .i3c_xfers = renesas_i3c_i3c_xfers,
.attach_i2c_dev = renesas_i3c_attach_i2c_dev,
.detach_i2c_dev = renesas_i3c_detach_i2c_dev,
.i2c_xfers = renesas_i3c_i2c_xfers,
diff --git a/drivers/input/misc/qnap-mcu-input.c b/drivers/input/misc/qnap-mcu-input.c
index 76e62f0816c1..3be899bfc114 100644
--- a/drivers/input/misc/qnap-mcu-input.c
+++ b/drivers/input/misc/qnap-mcu-input.c
@@ -103,7 +103,7 @@ static int qnap_mcu_input_probe(struct platform_device *pdev)
input = devm_input_allocate_device(dev);
if (!input)
- return dev_err_probe(dev, -ENOMEM, "no memory for input device\n");
+ return -ENOMEM;
idev->input = input;
idev->dev = dev;
diff --git a/drivers/input/touchscreen/cyttsp5.c b/drivers/input/touchscreen/cyttsp5.c
index 071b7c9bf566..47f4271395a6 100644
--- a/drivers/input/touchscreen/cyttsp5.c
+++ b/drivers/input/touchscreen/cyttsp5.c
@@ -923,8 +923,8 @@ static int cyttsp5_i2c_probe(struct i2c_client *client)
regmap = devm_regmap_init_i2c(client, &config);
if (IS_ERR(regmap)) {
- dev_err(&client->dev, "regmap allocation failed: %ld\n",
- PTR_ERR(regmap));
+ dev_err(&client->dev, "regmap allocation failed: %pe\n",
+ regmap);
return PTR_ERR(regmap);
}
diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c
index 93d659ff90aa..d6edfab16770 100644
--- a/drivers/input/touchscreen/ti_am335x_tsc.c
+++ b/drivers/input/touchscreen/ti_am335x_tsc.c
@@ -389,6 +389,10 @@ static int titsc_parse_dt(struct platform_device *pdev,
dev_warn(&pdev->dev,
"invalid co-ordinate readouts, resetting it to 5\n");
ts_dev->coordinate_readouts = 5;
+ } else if (ts_dev->coordinate_readouts > 6) {
+ dev_warn(&pdev->dev,
+ "co-ordinate readouts too large, limiting to 6\n");
+ ts_dev->coordinate_readouts = 6;
}
err = of_property_read_u32(node, "ti,charge-delay",
diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c
index df42fdf36ae3..a360749fa076 100644
--- a/drivers/input/touchscreen/zforce_ts.c
+++ b/drivers/input/touchscreen/zforce_ts.c
@@ -747,8 +747,7 @@ static int zforce_probe(struct i2c_client *client)
input_dev = devm_input_allocate_device(&client->dev);
if (!input_dev)
- return dev_err_probe(&client->dev, -ENOMEM,
- "could not allocate input device\n");
+ return -ENOMEM;
ts->client = client;
ts->input = input_dev;
diff --git a/drivers/irqchip/irq-loongarch-avec.c b/drivers/irqchip/irq-loongarch-avec.c
index bf52dc8345f5..ba556c008cf3 100644
--- a/drivers/irqchip/irq-loongarch-avec.c
+++ b/drivers/irqchip/irq-loongarch-avec.c
@@ -209,8 +209,9 @@ static void avecintc_compose_msi_msg(struct irq_data *d, struct msi_msg *msg)
struct avecintc_data *adata = irq_data_get_irq_chip_data(d);
msg->address_hi = 0x0;
- msg->address_lo = (loongarch_avec.msi_base_addr | (adata->vec & 0xff) << 4)
- | ((cpu_logical_map(adata->cpu & 0xffff)) << 12);
+ msg->address_lo = (loongarch_avec.msi_base_addr |
+ (adata->vec & AVEC_IRQ_MASK) << AVEC_IRQ_SHIFT) |
+ ((cpu_logical_map(adata->cpu & AVEC_CPU_MASK)) << AVEC_CPU_SHIFT);
msg->data = 0x0;
}
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index 104aa5355090..239c1744a926 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -299,6 +299,7 @@ config DM_CRYPT
select CRYPTO
select CRYPTO_CBC
select CRYPTO_ESSIV
+ select CRYPTO_LIB_MD5 # needed by lmk IV mode
help
This device-mapper target allows you to create a device that
transparently encrypts the data on it. You'll need to activate
@@ -546,6 +547,7 @@ config DM_VERITY
depends on BLK_DEV_DM
select CRYPTO
select CRYPTO_HASH
+ select CRYPTO_LIB_SHA256
select DM_BUFIO
help
This device-mapper target creates a read-only device that
diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c
index af345dc6fde1..82fdea7dea7a 100644
--- a/drivers/md/bcache/request.c
+++ b/drivers/md/bcache/request.c
@@ -1104,7 +1104,7 @@ static void detached_dev_end_io(struct bio *bio)
}
kfree(ddip);
- bio->bi_end_io(bio);
+ bio_endio(bio);
}
static void detached_dev_do_request(struct bcache_device *d, struct bio *bio,
@@ -1121,7 +1121,7 @@ static void detached_dev_do_request(struct bcache_device *d, struct bio *bio,
ddip = kzalloc(sizeof(struct detached_dev_io_private), GFP_NOIO);
if (!ddip) {
bio->bi_status = BLK_STS_RESOURCE;
- bio->bi_end_io(bio);
+ bio_endio(bio);
return;
}
@@ -1136,7 +1136,7 @@ static void detached_dev_do_request(struct bcache_device *d, struct bio *bio,
if ((bio_op(bio) == REQ_OP_DISCARD) &&
!bdev_max_discard_sectors(dc->bdev))
- bio->bi_end_io(bio);
+ detached_dev_end_io(bio);
else
submit_bio_noacct(bio);
}
diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c
index e6d28be11c5c..5235f3e4924b 100644
--- a/drivers/md/dm-bufio.c
+++ b/drivers/md/dm-bufio.c
@@ -1374,7 +1374,7 @@ static void submit_io(struct dm_buffer *b, enum req_op op, unsigned short ioprio
{
unsigned int n_sectors;
sector_t sector;
- unsigned int offset, end;
+ unsigned int offset, end, align;
b->end_io = end_io;
@@ -1388,9 +1388,11 @@ static void submit_io(struct dm_buffer *b, enum req_op op, unsigned short ioprio
b->c->write_callback(b);
offset = b->write_start;
end = b->write_end;
- offset &= -DM_BUFIO_WRITE_ALIGN;
- end += DM_BUFIO_WRITE_ALIGN - 1;
- end &= -DM_BUFIO_WRITE_ALIGN;
+ align = max(DM_BUFIO_WRITE_ALIGN,
+ bdev_physical_block_size(b->c->bdev));
+ offset &= -align;
+ end += align - 1;
+ end &= -align;
if (unlikely(end > b->c->block_size))
end = b->c->block_size;
diff --git a/drivers/md/dm-core.h b/drivers/md/dm-core.h
index a3c9f74fe2dc..1cda8618d74d 100644
--- a/drivers/md/dm-core.h
+++ b/drivers/md/dm-core.h
@@ -139,7 +139,6 @@ struct mapped_device {
struct srcu_struct io_barrier;
#ifdef CONFIG_BLK_DEV_ZONED
- unsigned int nr_zones;
void *zone_revalidate_map;
struct task_struct *revalidate_map_task;
#endif
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 5ef43231fe77..79704fbc523b 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -21,6 +21,7 @@
#include <linux/mempool.h>
#include <linux/slab.h>
#include <linux/crypto.h>
+#include <linux/fips.h>
#include <linux/workqueue.h>
#include <linux/kthread.h>
#include <linux/backing-dev.h>
@@ -120,7 +121,6 @@ struct iv_benbi_private {
#define LMK_SEED_SIZE 64 /* hash + 0 */
struct iv_lmk_private {
- struct crypto_shash *hash_tfm;
u8 *seed;
};
@@ -254,22 +254,15 @@ static unsigned int max_write_size = 0;
module_param(max_write_size, uint, 0644);
MODULE_PARM_DESC(max_write_size, "Maximum size of a write request");
-static unsigned get_max_request_sectors(struct dm_target *ti, struct bio *bio)
+static unsigned get_max_request_sectors(struct dm_target *ti, struct bio *bio, bool no_split)
{
struct crypt_config *cc = ti->private;
unsigned val, sector_align;
bool wrt = op_is_write(bio_op(bio));
- if (wrt) {
- /*
- * For zoned devices, splitting write operations creates the
- * risk of deadlocking queue freeze operations with zone write
- * plugging BIO work when the reminder of a split BIO is
- * issued. So always allow the entire BIO to proceed.
- */
- if (ti->emulate_zone_append)
- return bio_sectors(bio);
-
+ if (no_split) {
+ val = -1;
+ } else if (wrt) {
val = min_not_zero(READ_ONCE(max_write_size),
DM_CRYPT_DEFAULT_MAX_WRITE_SIZE);
} else {
@@ -465,10 +458,6 @@ static void crypt_iv_lmk_dtr(struct crypt_config *cc)
{
struct iv_lmk_private *lmk = &cc->iv_gen_private.lmk;
- if (lmk->hash_tfm && !IS_ERR(lmk->hash_tfm))
- crypto_free_shash(lmk->hash_tfm);
- lmk->hash_tfm = NULL;
-
kfree_sensitive(lmk->seed);
lmk->seed = NULL;
}
@@ -483,11 +472,10 @@ static int crypt_iv_lmk_ctr(struct crypt_config *cc, struct dm_target *ti,
return -EINVAL;
}
- lmk->hash_tfm = crypto_alloc_shash("md5", 0,
- CRYPTO_ALG_ALLOCATES_MEMORY);
- if (IS_ERR(lmk->hash_tfm)) {
- ti->error = "Error initializing LMK hash";
- return PTR_ERR(lmk->hash_tfm);
+ if (fips_enabled) {
+ ti->error = "LMK support is disabled due to FIPS";
+ /* ... because it uses MD5. */
+ return -EINVAL;
}
/* No seed in LMK version 2 */
@@ -498,7 +486,6 @@ static int crypt_iv_lmk_ctr(struct crypt_config *cc, struct dm_target *ti,
lmk->seed = kzalloc(LMK_SEED_SIZE, GFP_KERNEL);
if (!lmk->seed) {
- crypt_iv_lmk_dtr(cc);
ti->error = "Error kmallocing seed storage in LMK";
return -ENOMEM;
}
@@ -514,7 +501,7 @@ static int crypt_iv_lmk_init(struct crypt_config *cc)
/* LMK seed is on the position of LMK_KEYS + 1 key */
if (lmk->seed)
memcpy(lmk->seed, cc->key + (cc->tfms_count * subkey_size),
- crypto_shash_digestsize(lmk->hash_tfm));
+ MD5_DIGEST_SIZE);
return 0;
}
@@ -529,55 +516,31 @@ static int crypt_iv_lmk_wipe(struct crypt_config *cc)
return 0;
}
-static int crypt_iv_lmk_one(struct crypt_config *cc, u8 *iv,
- struct dm_crypt_request *dmreq,
- u8 *data)
+static void crypt_iv_lmk_one(struct crypt_config *cc, u8 *iv,
+ struct dm_crypt_request *dmreq, u8 *data)
{
struct iv_lmk_private *lmk = &cc->iv_gen_private.lmk;
- SHASH_DESC_ON_STACK(desc, lmk->hash_tfm);
- union {
- struct md5_state md5state;
- u8 state[CRYPTO_MD5_STATESIZE];
- } u;
+ struct md5_ctx ctx;
__le32 buf[4];
- int i, r;
- desc->tfm = lmk->hash_tfm;
+ md5_init(&ctx);
- r = crypto_shash_init(desc);
- if (r)
- return r;
-
- if (lmk->seed) {
- r = crypto_shash_update(desc, lmk->seed, LMK_SEED_SIZE);
- if (r)
- return r;
- }
+ if (lmk->seed)
+ md5_update(&ctx, lmk->seed, LMK_SEED_SIZE);
/* Sector is always 512B, block size 16, add data of blocks 1-31 */
- r = crypto_shash_update(desc, data + 16, 16 * 31);
- if (r)
- return r;
+ md5_update(&ctx, data + 16, 16 * 31);
/* Sector is cropped to 56 bits here */
buf[0] = cpu_to_le32(dmreq->iv_sector & 0xFFFFFFFF);
buf[1] = cpu_to_le32((((u64)dmreq->iv_sector >> 32) & 0x00FFFFFF) | 0x80000000);
buf[2] = cpu_to_le32(4024);
buf[3] = 0;
- r = crypto_shash_update(desc, (u8 *)buf, sizeof(buf));
- if (r)
- return r;
+ md5_update(&ctx, (u8 *)buf, sizeof(buf));
/* No MD5 padding here */
- r = crypto_shash_export(desc, &u.md5state);
- if (r)
- return r;
-
- for (i = 0; i < MD5_HASH_WORDS; i++)
- __cpu_to_le32s(&u.md5state.hash[i]);
- memcpy(iv, &u.md5state.hash, cc->iv_size);
-
- return 0;
+ cpu_to_le32_array(ctx.state.h, ARRAY_SIZE(ctx.state.h));
+ memcpy(iv, ctx.state.h, cc->iv_size);
}
static int crypt_iv_lmk_gen(struct crypt_config *cc, u8 *iv,
@@ -585,17 +548,15 @@ static int crypt_iv_lmk_gen(struct crypt_config *cc, u8 *iv,
{
struct scatterlist *sg;
u8 *src;
- int r = 0;
if (bio_data_dir(dmreq->ctx->bio_in) == WRITE) {
sg = crypt_get_sg_data(cc, dmreq->sg_in);
src = kmap_local_page(sg_page(sg));
- r = crypt_iv_lmk_one(cc, iv, dmreq, src + sg->offset);
+ crypt_iv_lmk_one(cc, iv, dmreq, src + sg->offset);
kunmap_local(src);
} else
memset(iv, 0, cc->iv_size);
-
- return r;
+ return 0;
}
static int crypt_iv_lmk_post(struct crypt_config *cc, u8 *iv,
@@ -603,21 +564,19 @@ static int crypt_iv_lmk_post(struct crypt_config *cc, u8 *iv,
{
struct scatterlist *sg;
u8 *dst;
- int r;
if (bio_data_dir(dmreq->ctx->bio_in) == WRITE)
return 0;
sg = crypt_get_sg_data(cc, dmreq->sg_out);
dst = kmap_local_page(sg_page(sg));
- r = crypt_iv_lmk_one(cc, iv, dmreq, dst + sg->offset);
+ crypt_iv_lmk_one(cc, iv, dmreq, dst + sg->offset);
/* Tweak the first block of plaintext sector */
- if (!r)
- crypto_xor(dst + sg->offset, iv, cc->iv_size);
+ crypto_xor(dst + sg->offset, iv, cc->iv_size);
kunmap_local(dst);
- return r;
+ return 0;
}
static void crypt_iv_tcw_dtr(struct crypt_config *cc)
@@ -1781,7 +1740,7 @@ static void crypt_free_buffer_pages(struct crypt_config *cc, struct bio *clone)
bio_for_each_folio_all(fi, clone) {
if (folio_test_large(fi.folio)) {
percpu_counter_sub(&cc->n_allocated_pages,
- 1 << folio_order(fi.folio));
+ folio_nr_pages(fi.folio));
folio_put(fi.folio);
} else {
mempool_free(&fi.folio->page, &cc->page_pool);
@@ -3496,6 +3455,7 @@ static int crypt_map(struct dm_target *ti, struct bio *bio)
struct dm_crypt_io *io;
struct crypt_config *cc = ti->private;
unsigned max_sectors;
+ bool no_split;
/*
* If bio is REQ_PREFLUSH or REQ_OP_DISCARD, just bypass crypt queues.
@@ -3513,10 +3473,20 @@ static int crypt_map(struct dm_target *ti, struct bio *bio)
/*
* Check if bio is too large, split as needed.
+ *
+ * For zoned devices, splitting write operations creates the
+ * risk of deadlocking queue freeze operations with zone write
+ * plugging BIO work when the reminder of a split BIO is
+ * issued. So always allow the entire BIO to proceed.
*/
- max_sectors = get_max_request_sectors(ti, bio);
- if (unlikely(bio_sectors(bio) > max_sectors))
+ no_split = (ti->emulate_zone_append && op_is_write(bio_op(bio))) ||
+ (bio->bi_opf & REQ_ATOMIC);
+ max_sectors = get_max_request_sectors(ti, bio, no_split);
+ if (unlikely(bio_sectors(bio) > max_sectors)) {
+ if (unlikely(no_split))
+ return DM_MAPIO_KILL;
dm_accept_partial_bio(bio, max_sectors);
+ }
/*
* Ensure that bio is a multiple of internal sector encryption size
@@ -3762,15 +3732,20 @@ static void crypt_io_hints(struct dm_target *ti, struct queue_limits *limits)
if (ti->emulate_zone_append)
limits->max_hw_sectors = min(limits->max_hw_sectors,
BIO_MAX_VECS << PAGE_SECTORS_SHIFT);
+
+ limits->atomic_write_hw_unit_max = min(limits->atomic_write_hw_unit_max,
+ BIO_MAX_VECS << PAGE_SHIFT);
+ limits->atomic_write_hw_max = min(limits->atomic_write_hw_max,
+ BIO_MAX_VECS << PAGE_SHIFT);
}
static struct target_type crypt_target = {
.name = "crypt",
- .version = {1, 28, 0},
+ .version = {1, 29, 0},
.module = THIS_MODULE,
.ctr = crypt_ctr,
.dtr = crypt_dtr,
- .features = DM_TARGET_ZONED_HM,
+ .features = DM_TARGET_ZONED_HM | DM_TARGET_ATOMIC_WRITES,
.report_zones = crypt_report_zones,
.map = crypt_map,
.status = crypt_status,
diff --git a/drivers/md/dm-ebs-target.c b/drivers/md/dm-ebs-target.c
index 6abb31ca9662..b354e74a670e 100644
--- a/drivers/md/dm-ebs-target.c
+++ b/drivers/md/dm-ebs-target.c
@@ -103,7 +103,7 @@ static int __ebs_rw_bvec(struct ebs_c *ec, enum req_op op, struct bio_vec *bv,
} else {
flush_dcache_page(bv->bv_page);
memcpy(ba, pa, cur_len);
- dm_bufio_mark_partial_buffer_dirty(b, buf_off, buf_off + cur_len);
+ dm_bufio_mark_buffer_dirty(b);
}
dm_bufio_release(b);
diff --git a/drivers/md/dm-exception-store.h b/drivers/md/dm-exception-store.h
index b67976637538..061b4d310813 100644
--- a/drivers/md/dm-exception-store.h
+++ b/drivers/md/dm-exception-store.h
@@ -29,7 +29,7 @@ typedef sector_t chunk_t;
* chunk within the device.
*/
struct dm_exception {
- struct hlist_bl_node hash_list;
+ struct hlist_node hash_list;
chunk_t old_chunk;
chunk_t new_chunk;
diff --git a/drivers/md/dm-log-writes.c b/drivers/md/dm-log-writes.c
index 7bb7174f8f4f..f0c84e7a5daa 100644
--- a/drivers/md/dm-log-writes.c
+++ b/drivers/md/dm-log-writes.c
@@ -432,6 +432,7 @@ static int log_writes_kthread(void *arg)
struct log_writes_c *lc = arg;
sector_t sector = 0;
+ set_freezable();
while (!kthread_should_stop()) {
bool super = false;
bool logging_enabled;
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index aaf4a0a4b0eb..c18358271618 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -131,7 +131,7 @@ static void queue_if_no_path_timeout_work(struct timer_list *t);
#define MPATHF_QUEUE_IO 0 /* Must we queue all I/O? */
#define MPATHF_QUEUE_IF_NO_PATH 1 /* Queue I/O if last path fails? */
#define MPATHF_SAVED_QUEUE_IF_NO_PATH 2 /* Saved state during suspension */
-#define MPATHF_RETAIN_ATTACHED_HW_HANDLER 3 /* If there's already a hw_handler present, don't change it. */
+/* MPATHF_RETAIN_ATTACHED_HW_HANDLER no longer has any effect */
#define MPATHF_PG_INIT_DISABLED 4 /* pg_init is not currently allowed */
#define MPATHF_PG_INIT_REQUIRED 5 /* pg_init needs calling? */
#define MPATHF_PG_INIT_DELAY_RETRY 6 /* Delay pg_init retry? */
@@ -237,16 +237,10 @@ static struct multipath *alloc_multipath(struct dm_target *ti)
static int alloc_multipath_stage2(struct dm_target *ti, struct multipath *m)
{
- if (m->queue_mode == DM_TYPE_NONE) {
+ if (m->queue_mode == DM_TYPE_NONE)
m->queue_mode = DM_TYPE_REQUEST_BASED;
- } else if (m->queue_mode == DM_TYPE_BIO_BASED) {
+ else if (m->queue_mode == DM_TYPE_BIO_BASED)
INIT_WORK(&m->process_queued_bios, process_queued_bios);
- /*
- * bio-based doesn't support any direct scsi_dh management;
- * it just discovers if a scsi_dh is attached.
- */
- set_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, &m->flags);
- }
dm_table_set_type(ti->table, m->queue_mode);
@@ -887,36 +881,30 @@ static int setup_scsi_dh(struct block_device *bdev, struct multipath *m,
struct request_queue *q = bdev_get_queue(bdev);
int r;
- if (mpath_double_check_test_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, m)) {
-retain:
- if (*attached_handler_name) {
- /*
- * Clear any hw_handler_params associated with a
- * handler that isn't already attached.
- */
- if (m->hw_handler_name && strcmp(*attached_handler_name, m->hw_handler_name)) {
- kfree(m->hw_handler_params);
- m->hw_handler_params = NULL;
- }
-
- /*
- * Reset hw_handler_name to match the attached handler
- *
- * NB. This modifies the table line to show the actual
- * handler instead of the original table passed in.
- */
- kfree(m->hw_handler_name);
- m->hw_handler_name = *attached_handler_name;
- *attached_handler_name = NULL;
+ if (*attached_handler_name) {
+ /*
+ * Clear any hw_handler_params associated with a
+ * handler that isn't already attached.
+ */
+ if (m->hw_handler_name && strcmp(*attached_handler_name,
+ m->hw_handler_name)) {
+ kfree(m->hw_handler_params);
+ m->hw_handler_params = NULL;
}
+
+ /*
+ * Reset hw_handler_name to match the attached handler
+ *
+ * NB. This modifies the table line to show the actual
+ * handler instead of the original table passed in.
+ */
+ kfree(m->hw_handler_name);
+ m->hw_handler_name = *attached_handler_name;
+ *attached_handler_name = NULL;
}
if (m->hw_handler_name) {
r = scsi_dh_attach(q, m->hw_handler_name);
- if (r == -EBUSY) {
- DMINFO("retaining handler on device %pg", bdev);
- goto retain;
- }
if (r < 0) {
*error = "error attaching hardware handler";
return r;
@@ -1138,7 +1126,7 @@ static int parse_features(struct dm_arg_set *as, struct multipath *m)
}
if (!strcasecmp(arg_name, "retain_attached_hw_handler")) {
- set_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, &m->flags);
+ /* no longer has any effect */
continue;
}
@@ -1823,7 +1811,6 @@ static void multipath_status(struct dm_target *ti, status_type_t type,
DMEMIT("%u ", test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags) +
(m->pg_init_retries > 0) * 2 +
(m->pg_init_delay_msecs != DM_PG_INIT_DELAY_DEFAULT) * 2 +
- test_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, &m->flags) +
(m->queue_mode != DM_TYPE_REQUEST_BASED) * 2);
if (test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags))
@@ -1832,8 +1819,6 @@ static void multipath_status(struct dm_target *ti, status_type_t type,
DMEMIT("pg_init_retries %u ", m->pg_init_retries);
if (m->pg_init_delay_msecs != DM_PG_INIT_DELAY_DEFAULT)
DMEMIT("pg_init_delay_msecs %u ", m->pg_init_delay_msecs);
- if (test_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, &m->flags))
- DMEMIT("retain_attached_hw_handler ");
if (m->queue_mode != DM_TYPE_REQUEST_BASED) {
switch (m->queue_mode) {
case DM_TYPE_BIO_BASED:
@@ -2307,7 +2292,7 @@ static struct target_type multipath_target = {
.name = "multipath",
.version = {1, 15, 0},
.features = DM_TARGET_SINGLETON | DM_TARGET_IMMUTABLE |
- DM_TARGET_PASSES_INTEGRITY,
+ DM_TARGET_PASSES_INTEGRITY | DM_TARGET_ATOMIC_WRITES,
.module = THIS_MODULE,
.ctr = multipath_ctr,
.dtr = multipath_dtr,
diff --git a/drivers/md/dm-pcache/cache.c b/drivers/md/dm-pcache/cache.c
index 698697a7a73c..534bf07b794f 100644
--- a/drivers/md/dm-pcache/cache.c
+++ b/drivers/md/dm-pcache/cache.c
@@ -10,7 +10,8 @@ struct kmem_cache *key_cache;
static inline struct pcache_cache_info *get_cache_info_addr(struct pcache_cache *cache)
{
- return cache->cache_info_addr + cache->info_index;
+ return (struct pcache_cache_info *)((char *)cache->cache_info_addr +
+ (size_t)cache->info_index * PCACHE_CACHE_INFO_SIZE);
}
static void cache_info_write(struct pcache_cache *cache)
@@ -21,10 +22,10 @@ static void cache_info_write(struct pcache_cache *cache)
cache_info->header.crc = pcache_meta_crc(&cache_info->header,
sizeof(struct pcache_cache_info));
+ cache->info_index = (cache->info_index + 1) % PCACHE_META_INDEX_MAX;
memcpy_flushcache(get_cache_info_addr(cache), cache_info,
sizeof(struct pcache_cache_info));
-
- cache->info_index = (cache->info_index + 1) % PCACHE_META_INDEX_MAX;
+ pmem_wmb();
}
static void cache_info_init_default(struct pcache_cache *cache);
@@ -49,6 +50,8 @@ static int cache_info_init(struct pcache_cache *cache, struct pcache_cache_optio
return -EINVAL;
}
+ cache->info_index = ((char *)cache_info_addr - (char *)cache->cache_info_addr) / PCACHE_CACHE_INFO_SIZE;
+
return 0;
}
@@ -93,10 +96,10 @@ void cache_pos_encode(struct pcache_cache *cache,
pos_onmedia.header.seq = seq;
pos_onmedia.header.crc = cache_pos_onmedia_crc(&pos_onmedia);
+ *index = (*index + 1) % PCACHE_META_INDEX_MAX;
+
memcpy_flushcache(pos_onmedia_addr, &pos_onmedia, sizeof(struct pcache_cache_pos_onmedia));
pmem_wmb();
-
- *index = (*index + 1) % PCACHE_META_INDEX_MAX;
}
int cache_pos_decode(struct pcache_cache *cache,
diff --git a/drivers/md/dm-pcache/cache_segment.c b/drivers/md/dm-pcache/cache_segment.c
index f0b58980806e..9d92e2b067ed 100644
--- a/drivers/md/dm-pcache/cache_segment.c
+++ b/drivers/md/dm-pcache/cache_segment.c
@@ -26,11 +26,11 @@ static void cache_seg_info_write(struct pcache_cache_segment *cache_seg)
seg_info->header.seq++;
seg_info->header.crc = pcache_meta_crc(&seg_info->header, sizeof(struct pcache_segment_info));
+ cache_seg->info_index = (cache_seg->info_index + 1) % PCACHE_META_INDEX_MAX;
+
seg_info_addr = get_seg_info_addr(cache_seg);
memcpy_flushcache(seg_info_addr, seg_info, sizeof(struct pcache_segment_info));
pmem_wmb();
-
- cache_seg->info_index = (cache_seg->info_index + 1) % PCACHE_META_INDEX_MAX;
mutex_unlock(&cache_seg->info_lock);
}
@@ -56,7 +56,10 @@ static int cache_seg_info_load(struct pcache_cache_segment *cache_seg)
ret = -EIO;
goto out;
}
- cache_seg->info_index = cache_seg_info_addr - cache_seg_info_addr_base;
+
+ cache_seg->info_index =
+ ((char *)cache_seg_info_addr - (char *)cache_seg_info_addr_base) /
+ PCACHE_SEG_INFO_SIZE;
out:
mutex_unlock(&cache_seg->info_lock);
@@ -129,10 +132,10 @@ static void cache_seg_ctrl_write(struct pcache_cache_segment *cache_seg)
cache_seg_gen.header.crc = pcache_meta_crc(&cache_seg_gen.header,
sizeof(struct pcache_cache_seg_gen));
+ cache_seg->gen_index = (cache_seg->gen_index + 1) % PCACHE_META_INDEX_MAX;
+
memcpy_flushcache(get_cache_seg_gen_addr(cache_seg), &cache_seg_gen, sizeof(struct pcache_cache_seg_gen));
pmem_wmb();
-
- cache_seg->gen_index = (cache_seg->gen_index + 1) % PCACHE_META_INDEX_MAX;
}
static void cache_seg_ctrl_init(struct pcache_cache_segment *cache_seg)
diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c
index c6f7129e43d3..4bacdc499984 100644
--- a/drivers/md/dm-raid.c
+++ b/drivers/md/dm-raid.c
@@ -2287,6 +2287,8 @@ static int super_init_validation(struct raid_set *rs, struct md_rdev *rdev)
mddev->reshape_position = le64_to_cpu(sb->reshape_position);
rs->raid_type = get_raid_type_by_ll(mddev->level, mddev->layout);
+ if (!rs->raid_type)
+ return -EINVAL;
}
} else {
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index f40c18da4000..dbd148967de4 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -40,10 +40,15 @@ static const char dm_snapshot_merge_target_name[] = "snapshot-merge";
#define DM_TRACKED_CHUNK_HASH(x) ((unsigned long)(x) & \
(DM_TRACKED_CHUNK_HASH_SIZE - 1))
+struct dm_hlist_head {
+ struct hlist_head head;
+ spinlock_t lock;
+};
+
struct dm_exception_table {
uint32_t hash_mask;
unsigned int hash_shift;
- struct hlist_bl_head *table;
+ struct dm_hlist_head *table;
};
struct dm_snapshot {
@@ -628,8 +633,8 @@ static uint32_t exception_hash(struct dm_exception_table *et, chunk_t chunk);
/* Lock to protect access to the completed and pending exception hash tables. */
struct dm_exception_table_lock {
- struct hlist_bl_head *complete_slot;
- struct hlist_bl_head *pending_slot;
+ spinlock_t *complete_slot;
+ spinlock_t *pending_slot;
};
static void dm_exception_table_lock_init(struct dm_snapshot *s, chunk_t chunk,
@@ -638,20 +643,20 @@ static void dm_exception_table_lock_init(struct dm_snapshot *s, chunk_t chunk,
struct dm_exception_table *complete = &s->complete;
struct dm_exception_table *pending = &s->pending;
- lock->complete_slot = &complete->table[exception_hash(complete, chunk)];
- lock->pending_slot = &pending->table[exception_hash(pending, chunk)];
+ lock->complete_slot = &complete->table[exception_hash(complete, chunk)].lock;
+ lock->pending_slot = &pending->table[exception_hash(pending, chunk)].lock;
}
static void dm_exception_table_lock(struct dm_exception_table_lock *lock)
{
- hlist_bl_lock(lock->complete_slot);
- hlist_bl_lock(lock->pending_slot);
+ spin_lock_nested(lock->complete_slot, 1);
+ spin_lock_nested(lock->pending_slot, 2);
}
static void dm_exception_table_unlock(struct dm_exception_table_lock *lock)
{
- hlist_bl_unlock(lock->pending_slot);
- hlist_bl_unlock(lock->complete_slot);
+ spin_unlock(lock->pending_slot);
+ spin_unlock(lock->complete_slot);
}
static int dm_exception_table_init(struct dm_exception_table *et,
@@ -661,13 +666,15 @@ static int dm_exception_table_init(struct dm_exception_table *et,
et->hash_shift = hash_shift;
et->hash_mask = size - 1;
- et->table = kvmalloc_array(size, sizeof(struct hlist_bl_head),
+ et->table = kvmalloc_array(size, sizeof(struct dm_hlist_head),
GFP_KERNEL);
if (!et->table)
return -ENOMEM;
- for (i = 0; i < size; i++)
- INIT_HLIST_BL_HEAD(et->table + i);
+ for (i = 0; i < size; i++) {
+ INIT_HLIST_HEAD(&et->table[i].head);
+ spin_lock_init(&et->table[i].lock);
+ }
return 0;
}
@@ -675,16 +682,17 @@ static int dm_exception_table_init(struct dm_exception_table *et,
static void dm_exception_table_exit(struct dm_exception_table *et,
struct kmem_cache *mem)
{
- struct hlist_bl_head *slot;
+ struct dm_hlist_head *slot;
struct dm_exception *ex;
- struct hlist_bl_node *pos, *n;
+ struct hlist_node *pos;
int i, size;
size = et->hash_mask + 1;
for (i = 0; i < size; i++) {
slot = et->table + i;
- hlist_bl_for_each_entry_safe(ex, pos, n, slot, hash_list) {
+ hlist_for_each_entry_safe(ex, pos, &slot->head, hash_list) {
+ hlist_del(&ex->hash_list);
kmem_cache_free(mem, ex);
cond_resched();
}
@@ -700,7 +708,7 @@ static uint32_t exception_hash(struct dm_exception_table *et, chunk_t chunk)
static void dm_remove_exception(struct dm_exception *e)
{
- hlist_bl_del(&e->hash_list);
+ hlist_del(&e->hash_list);
}
/*
@@ -710,12 +718,11 @@ static void dm_remove_exception(struct dm_exception *e)
static struct dm_exception *dm_lookup_exception(struct dm_exception_table *et,
chunk_t chunk)
{
- struct hlist_bl_head *slot;
- struct hlist_bl_node *pos;
+ struct hlist_head *slot;
struct dm_exception *e;
- slot = &et->table[exception_hash(et, chunk)];
- hlist_bl_for_each_entry(e, pos, slot, hash_list)
+ slot = &et->table[exception_hash(et, chunk)].head;
+ hlist_for_each_entry(e, slot, hash_list)
if (chunk >= e->old_chunk &&
chunk <= e->old_chunk + dm_consecutive_chunk_count(e))
return e;
@@ -762,18 +769,17 @@ static void free_pending_exception(struct dm_snap_pending_exception *pe)
static void dm_insert_exception(struct dm_exception_table *eh,
struct dm_exception *new_e)
{
- struct hlist_bl_head *l;
- struct hlist_bl_node *pos;
+ struct hlist_head *l;
struct dm_exception *e = NULL;
- l = &eh->table[exception_hash(eh, new_e->old_chunk)];
+ l = &eh->table[exception_hash(eh, new_e->old_chunk)].head;
/* Add immediately if this table doesn't support consecutive chunks */
if (!eh->hash_shift)
goto out;
/* List is ordered by old_chunk */
- hlist_bl_for_each_entry(e, pos, l, hash_list) {
+ hlist_for_each_entry(e, l, hash_list) {
/* Insert after an existing chunk? */
if (new_e->old_chunk == (e->old_chunk +
dm_consecutive_chunk_count(e) + 1) &&
@@ -804,13 +810,13 @@ out:
* Either the table doesn't support consecutive chunks or slot
* l is empty.
*/
- hlist_bl_add_head(&new_e->hash_list, l);
+ hlist_add_head(&new_e->hash_list, l);
} else if (new_e->old_chunk < e->old_chunk) {
/* Add before an existing exception */
- hlist_bl_add_before(&new_e->hash_list, &e->hash_list);
+ hlist_add_before(&new_e->hash_list, &e->hash_list);
} else {
/* Add to l's tail: e is the last exception in this slot */
- hlist_bl_add_behind(&new_e->hash_list, &e->hash_list);
+ hlist_add_behind(&new_e->hash_list, &e->hash_list);
}
}
@@ -820,7 +826,6 @@ out:
*/
static int dm_add_exception(void *context, chunk_t old, chunk_t new)
{
- struct dm_exception_table_lock lock;
struct dm_snapshot *s = context;
struct dm_exception *e;
@@ -833,17 +838,7 @@ static int dm_add_exception(void *context, chunk_t old, chunk_t new)
/* Consecutive_count is implicitly initialised to zero */
e->new_chunk = new;
- /*
- * Although there is no need to lock access to the exception tables
- * here, if we don't then hlist_bl_add_head(), called by
- * dm_insert_exception(), will complain about accessing the
- * corresponding list without locking it first.
- */
- dm_exception_table_lock_init(s, old, &lock);
-
- dm_exception_table_lock(&lock);
dm_insert_exception(&s->complete, e);
- dm_exception_table_unlock(&lock);
return 0;
}
@@ -873,7 +868,7 @@ static int calc_max_buckets(void)
/* use a fixed size of 2MB */
unsigned long mem = 2 * 1024 * 1024;
- mem /= sizeof(struct hlist_bl_head);
+ mem /= sizeof(struct dm_hlist_head);
return mem;
}
diff --git a/drivers/md/dm-sysfs.c b/drivers/md/dm-sysfs.c
index bfaef27ca79f..22bc70923a83 100644
--- a/drivers/md/dm-sysfs.c
+++ b/drivers/md/dm-sysfs.c
@@ -86,17 +86,13 @@ static ssize_t dm_attr_uuid_show(struct mapped_device *md, char *buf)
static ssize_t dm_attr_suspended_show(struct mapped_device *md, char *buf)
{
- sprintf(buf, "%d\n", dm_suspended_md(md));
-
- return strlen(buf);
+ return sysfs_emit(buf, "%d\n", dm_suspended_md(md));
}
static ssize_t dm_attr_use_blk_mq_show(struct mapped_device *md, char *buf)
{
/* Purely for userspace compatibility */
- sprintf(buf, "%d\n", true);
-
- return strlen(buf);
+ return sysfs_emit(buf, "%d\n", true);
}
static DM_ATTR_RO(name);
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index ad0a60a07b93..0522cd700e0e 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -2043,6 +2043,10 @@ bool dm_table_supports_size_change(struct dm_table *t, sector_t old_size,
return true;
}
+/*
+ * This function will be skipped by noflush reloads of immutable request
+ * based devices (dm-mpath).
+ */
int dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
struct queue_limits *limits)
{
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c
index c84149ba4e38..52ffb495f5a8 100644
--- a/drivers/md/dm-thin.c
+++ b/drivers/md/dm-thin.c
@@ -395,13 +395,13 @@ static void begin_discard(struct discard_op *op, struct thin_c *tc, struct bio *
op->bio = NULL;
}
-static int issue_discard(struct discard_op *op, dm_block_t data_b, dm_block_t data_e)
+static void issue_discard(struct discard_op *op, dm_block_t data_b, dm_block_t data_e)
{
struct thin_c *tc = op->tc;
sector_t s = block_to_sectors(tc->pool, data_b);
sector_t len = block_to_sectors(tc->pool, data_e - data_b);
- return __blkdev_issue_discard(tc->pool_dev->bdev, s, len, GFP_NOIO, &op->bio);
+ __blkdev_issue_discard(tc->pool_dev->bdev, s, len, GFP_NOIO, &op->bio);
}
static void end_discard(struct discard_op *op, int r)
@@ -1113,9 +1113,7 @@ static void passdown_double_checking_shared_status(struct dm_thin_new_mapping *m
break;
}
- r = issue_discard(&op, b, e);
- if (r)
- goto out;
+ issue_discard(&op, b, e);
b = e;
}
@@ -1188,8 +1186,8 @@ static void process_prepared_discard_passdown_pt1(struct dm_thin_new_mapping *m)
struct discard_op op;
begin_discard(&op, tc, discard_parent);
- r = issue_discard(&op, m->data_block, data_end);
- end_discard(&op, r);
+ issue_discard(&op, m->data_block, data_end);
+ end_discard(&op, 0);
}
}
@@ -4383,11 +4381,8 @@ static void thin_postsuspend(struct dm_target *ti)
{
struct thin_c *tc = ti->private;
- /*
- * The dm_noflush_suspending flag has been cleared by now, so
- * unfortunately we must always run this.
- */
- noflush_work(tc, do_noflush_stop);
+ if (dm_noflush_suspending(ti))
+ noflush_work(tc, do_noflush_stop);
}
static int thin_preresume(struct dm_target *ti)
diff --git a/drivers/md/dm-vdo/action-manager.c b/drivers/md/dm-vdo/action-manager.c
index a0e5e7077d13..e3bba0b28aad 100644
--- a/drivers/md/dm-vdo/action-manager.c
+++ b/drivers/md/dm-vdo/action-manager.c
@@ -43,7 +43,7 @@ struct action {
* @actions: The two action slots.
* @current_action: The current action slot.
* @zones: The number of zones in which an action is to be applied.
- * @Scheduler: A function to schedule a default next action.
+ * @scheduler: A function to schedule a default next action.
* @get_zone_thread_id: A function to get the id of the thread on which to apply an action to a
* zone.
* @initiator_thread_id: The ID of the thread on which actions may be initiated.
diff --git a/drivers/md/dm-vdo/admin-state.c b/drivers/md/dm-vdo/admin-state.c
index 3f9dba525154..da153fef085e 100644
--- a/drivers/md/dm-vdo/admin-state.c
+++ b/drivers/md/dm-vdo/admin-state.c
@@ -149,7 +149,8 @@ const struct admin_state_code *VDO_ADMIN_STATE_RESUMING = &VDO_CODE_RESUMING;
/**
* get_next_state() - Determine the state which should be set after a given operation completes
* based on the operation and the current state.
- * @operation The operation to be started.
+ * @state: The current admin state.
+ * @operation: The operation to be started.
*
* Return: The state to set when the operation completes or NULL if the operation can not be
* started in the current state.
@@ -187,6 +188,8 @@ static const struct admin_state_code *get_next_state(const struct admin_state *s
/**
* vdo_finish_operation() - Finish the current operation.
+ * @state: The current admin state.
+ * @result: The result of the operation.
*
* Will notify the operation waiter if there is one. This method should be used for operations
* started with vdo_start_operation(). For operations which were started with vdo_start_draining(),
@@ -214,8 +217,10 @@ bool vdo_finish_operation(struct admin_state *state, int result)
/**
* begin_operation() - Begin an operation if it may be started given the current state.
- * @waiter A completion to notify when the operation is complete; may be NULL.
- * @initiator The vdo_admin_initiator_fn to call if the operation may begin; may be NULL.
+ * @state: The current admin state.
+ * @operation: The operation to be started.
+ * @waiter: A completion to notify when the operation is complete; may be NULL.
+ * @initiator: The vdo_admin_initiator_fn to call if the operation may begin; may be NULL.
*
* Return: VDO_SUCCESS or an error.
*/
@@ -259,8 +264,10 @@ static int __must_check begin_operation(struct admin_state *state,
/**
* start_operation() - Start an operation if it may be started given the current state.
- * @waiter A completion to notify when the operation is complete.
- * @initiator The vdo_admin_initiator_fn to call if the operation may begin; may be NULL.
+ * @state: The current admin state.
+ * @operation: The operation to be started.
+ * @waiter: A completion to notify when the operation is complete; may be NULL.
+ * @initiator: The vdo_admin_initiator_fn to call if the operation may begin; may be NULL.
*
* Return: true if the operation was started.
*/
@@ -274,10 +281,10 @@ static inline bool __must_check start_operation(struct admin_state *state,
/**
* check_code() - Check the result of a state validation.
- * @valid true if the code is of an appropriate type.
- * @code The code which failed to be of the correct type.
- * @what What the code failed to be, for logging.
- * @waiter The completion to notify of the error; may be NULL.
+ * @valid: True if the code is of an appropriate type.
+ * @code: The code which failed to be of the correct type.
+ * @what: What the code failed to be, for logging.
+ * @waiter: The completion to notify of the error; may be NULL.
*
* If the result failed, log an invalid state error and, if there is a waiter, notify it.
*
@@ -301,7 +308,8 @@ static bool check_code(bool valid, const struct admin_state_code *code, const ch
/**
* assert_vdo_drain_operation() - Check that an operation is a drain.
- * @waiter The completion to finish with an error if the operation is not a drain.
+ * @operation: The operation to check.
+ * @waiter: The completion to finish with an error if the operation is not a drain.
*
* Return: true if the specified operation is a drain.
*/
@@ -313,9 +321,10 @@ static bool __must_check assert_vdo_drain_operation(const struct admin_state_cod
/**
* vdo_start_draining() - Initiate a drain operation if the current state permits it.
- * @operation The type of drain to initiate.
- * @waiter The completion to notify when the drain is complete.
- * @initiator The vdo_admin_initiator_fn to call if the operation may begin; may be NULL.
+ * @state: The current admin state.
+ * @operation: The type of drain to initiate.
+ * @waiter: The completion to notify when the drain is complete.
+ * @initiator: The vdo_admin_initiator_fn to call if the operation may begin; may be NULL.
*
* Return: true if the drain was initiated, if not the waiter will be notified.
*/
@@ -345,6 +354,7 @@ bool vdo_start_draining(struct admin_state *state,
/**
* vdo_finish_draining() - Finish a drain operation if one was in progress.
+ * @state: The current admin state.
*
* Return: true if the state was draining; will notify the waiter if so.
*/
@@ -355,6 +365,8 @@ bool vdo_finish_draining(struct admin_state *state)
/**
* vdo_finish_draining_with_result() - Finish a drain operation with a status code.
+ * @state: The current admin state.
+ * @result: The result of the drain operation.
*
* Return: true if the state was draining; will notify the waiter if so.
*/
@@ -365,7 +377,8 @@ bool vdo_finish_draining_with_result(struct admin_state *state, int result)
/**
* vdo_assert_load_operation() - Check that an operation is a load.
- * @waiter The completion to finish with an error if the operation is not a load.
+ * @operation: The operation to check.
+ * @waiter: The completion to finish with an error if the operation is not a load.
*
* Return: true if the specified operation is a load.
*/
@@ -377,9 +390,10 @@ bool vdo_assert_load_operation(const struct admin_state_code *operation,
/**
* vdo_start_loading() - Initiate a load operation if the current state permits it.
- * @operation The type of load to initiate.
- * @waiter The completion to notify when the load is complete (may be NULL).
- * @initiator The vdo_admin_initiator_fn to call if the operation may begin; may be NULL.
+ * @state: The current admin state.
+ * @operation: The type of load to initiate.
+ * @waiter: The completion to notify when the load is complete; may be NULL.
+ * @initiator: The vdo_admin_initiator_fn to call if the operation may begin; may be NULL.
*
* Return: true if the load was initiated, if not the waiter will be notified.
*/
@@ -393,6 +407,7 @@ bool vdo_start_loading(struct admin_state *state,
/**
* vdo_finish_loading() - Finish a load operation if one was in progress.
+ * @state: The current admin state.
*
* Return: true if the state was loading; will notify the waiter if so.
*/
@@ -403,7 +418,8 @@ bool vdo_finish_loading(struct admin_state *state)
/**
* vdo_finish_loading_with_result() - Finish a load operation with a status code.
- * @result The result of the load operation.
+ * @state: The current admin state.
+ * @result: The result of the load operation.
*
* Return: true if the state was loading; will notify the waiter if so.
*/
@@ -414,7 +430,8 @@ bool vdo_finish_loading_with_result(struct admin_state *state, int result)
/**
* assert_vdo_resume_operation() - Check whether an admin_state_code is a resume operation.
- * @waiter The completion to notify if the operation is not a resume operation; may be NULL.
+ * @operation: The operation to check.
+ * @waiter: The completion to notify if the operation is not a resume operation; may be NULL.
*
* Return: true if the code is a resume operation.
*/
@@ -427,9 +444,10 @@ static bool __must_check assert_vdo_resume_operation(const struct admin_state_co
/**
* vdo_start_resuming() - Initiate a resume operation if the current state permits it.
- * @operation The type of resume to start.
- * @waiter The completion to notify when the resume is complete (may be NULL).
- * @initiator The vdo_admin_initiator_fn to call if the operation may begin; may be NULL.
+ * @state: The current admin state.
+ * @operation: The type of resume to start.
+ * @waiter: The completion to notify when the resume is complete; may be NULL.
+ * @initiator: The vdo_admin_initiator_fn to call if the operation may begin; may be NULL.
*
* Return: true if the resume was initiated, if not the waiter will be notified.
*/
@@ -443,6 +461,7 @@ bool vdo_start_resuming(struct admin_state *state,
/**
* vdo_finish_resuming() - Finish a resume operation if one was in progress.
+ * @state: The current admin state.
*
* Return: true if the state was resuming; will notify the waiter if so.
*/
@@ -453,7 +472,8 @@ bool vdo_finish_resuming(struct admin_state *state)
/**
* vdo_finish_resuming_with_result() - Finish a resume operation with a status code.
- * @result The result of the resume operation.
+ * @state: The current admin state.
+ * @result: The result of the resume operation.
*
* Return: true if the state was resuming; will notify the waiter if so.
*/
@@ -465,6 +485,7 @@ bool vdo_finish_resuming_with_result(struct admin_state *state, int result)
/**
* vdo_resume_if_quiescent() - Change the state to normal operation if the current state is
* quiescent.
+ * @state: The current admin state.
*
* Return: VDO_SUCCESS if the state resumed, VDO_INVALID_ADMIN_STATE otherwise.
*/
@@ -479,6 +500,8 @@ int vdo_resume_if_quiescent(struct admin_state *state)
/**
* vdo_start_operation() - Attempt to start an operation.
+ * @state: The current admin state.
+ * @operation: The operation to attempt to start.
*
* Return: VDO_SUCCESS if the operation was started, VDO_INVALID_ADMIN_STATE if not
*/
@@ -490,8 +513,10 @@ int vdo_start_operation(struct admin_state *state,
/**
* vdo_start_operation_with_waiter() - Attempt to start an operation.
- * @waiter the completion to notify when the operation completes or fails to start; may be NULL.
- * @initiator The vdo_admin_initiator_fn to call if the operation may begin; may be NULL.
+ * @state: The current admin state.
+ * @operation: The operation to attempt to start.
+ * @waiter: The completion to notify when the operation completes or fails to start; may be NULL.
+ * @initiator: The vdo_admin_initiator_fn to call if the operation may begin; may be NULL.
*
* Return: VDO_SUCCESS if the operation was started, VDO_INVALID_ADMIN_STATE if not
*/
diff --git a/drivers/md/dm-vdo/block-map.c b/drivers/md/dm-vdo/block-map.c
index baf683cabb1b..a7db5b41155e 100644
--- a/drivers/md/dm-vdo/block-map.c
+++ b/drivers/md/dm-vdo/block-map.c
@@ -174,6 +174,7 @@ static inline struct vdo_page_completion *page_completion_from_waiter(struct vdo
/**
* initialize_info() - Initialize all page info structures and put them on the free list.
+ * @cache: The page cache.
*
* Return: VDO_SUCCESS or an error.
*/
@@ -209,6 +210,7 @@ static int initialize_info(struct vdo_page_cache *cache)
/**
* allocate_cache_components() - Allocate components of the cache which require their own
* allocation.
+ * @cache: The page cache.
*
* The caller is responsible for all clean up on errors.
*
@@ -238,6 +240,8 @@ static int __must_check allocate_cache_components(struct vdo_page_cache *cache)
/**
* assert_on_cache_thread() - Assert that a function has been called on the VDO page cache's
* thread.
+ * @cache: The page cache.
+ * @function_name: The funtion name to report if the assertion fails.
*/
static inline void assert_on_cache_thread(struct vdo_page_cache *cache,
const char *function_name)
@@ -271,6 +275,7 @@ static void report_cache_pressure(struct vdo_page_cache *cache)
/**
* get_page_state_name() - Return the name of a page state.
+ * @state: The page state to describe.
*
* If the page state is invalid a static string is returned and the invalid state is logged.
*
@@ -342,6 +347,8 @@ static void update_lru(struct page_info *info)
/**
* set_info_state() - Set the state of a page_info and put it on the right list, adjusting
* counters.
+ * @info: The page info to update.
+ * @new_state: The new state to set.
*/
static void set_info_state(struct page_info *info, enum vdo_page_buffer_state new_state)
{
@@ -416,6 +423,7 @@ static int reset_page_info(struct page_info *info)
/**
* find_free_page() - Find a free page.
+ * @cache: The page cache.
*
* Return: A pointer to the page info structure (if found), NULL otherwise.
*/
@@ -433,6 +441,7 @@ static struct page_info * __must_check find_free_page(struct vdo_page_cache *cac
/**
* find_page() - Find the page info (if any) associated with a given pbn.
+ * @cache: The page cache.
* @pbn: The absolute physical block number of the page.
*
* Return: The page info for the page if available, or NULL if not.
@@ -449,6 +458,7 @@ static struct page_info * __must_check find_page(struct vdo_page_cache *cache,
/**
* select_lru_page() - Determine which page is least recently used.
+ * @cache: The page cache.
*
* Picks the least recently used from among the non-busy entries at the front of each of the lru
* list. Since whenever we mark a page busy we also put it to the end of the list it is unlikely
@@ -523,6 +533,8 @@ static void complete_waiter_with_page(struct vdo_waiter *waiter, void *page_info
/**
* distribute_page_over_waitq() - Complete a waitq of VDO page completions with a page result.
+ * @info: The loaded page info.
+ * @waitq: The list of waiting data_vios.
*
* Upon completion the waitq will be empty.
*
@@ -548,7 +560,9 @@ static unsigned int distribute_page_over_waitq(struct page_info *info,
/**
* set_persistent_error() - Set a persistent error which all requests will receive in the future.
+ * @cache: The page cache.
* @context: A string describing what triggered the error.
+ * @result: The error result to set on the cache.
*
* Once triggered, all enqueued completions will get this error. Any future requests will result in
* this error as well.
@@ -581,6 +595,7 @@ static void set_persistent_error(struct vdo_page_cache *cache, const char *conte
/**
* validate_completed_page() - Check that a page completion which is being freed to the cache
* referred to a valid page and is in a valid state.
+ * @completion: The page completion to check.
* @writable: Whether a writable page is required.
*
* Return: VDO_SUCCESS if the page was valid, otherwise as error
@@ -758,6 +773,8 @@ static void load_cache_page_endio(struct bio *bio)
/**
* launch_page_load() - Begin the process of loading a page.
+ * @info: The page info to launch.
+ * @pbn: The absolute physical block number of the page to load.
*
* Return: VDO_SUCCESS or an error code.
*/
@@ -836,6 +853,7 @@ static void save_pages(struct vdo_page_cache *cache)
/**
* schedule_page_save() - Add a page to the outgoing list of pages waiting to be saved.
+ * @info: The page info to save.
*
* Once in the list, a page may not be used until it has been written out.
*/
@@ -854,6 +872,7 @@ static void schedule_page_save(struct page_info *info)
/**
* launch_page_save() - Add a page to outgoing pages waiting to be saved, and then start saving
* pages if another save is not in progress.
+ * @info: The page info to save.
*/
static void launch_page_save(struct page_info *info)
{
@@ -864,6 +883,7 @@ static void launch_page_save(struct page_info *info)
/**
* completion_needs_page() - Determine whether a given vdo_page_completion (as a waiter) is
* requesting a given page number.
+ * @waiter: The page completion waiter to check.
* @context: A pointer to the pbn of the desired page.
*
* Implements waiter_match_fn.
@@ -880,6 +900,7 @@ static bool completion_needs_page(struct vdo_waiter *waiter, void *context)
/**
* allocate_free_page() - Allocate a free page to the first completion in the waiting queue, and
* any other completions that match it in page number.
+ * @info: The page info to allocate a page for.
*/
static void allocate_free_page(struct page_info *info)
{
@@ -925,6 +946,7 @@ static void allocate_free_page(struct page_info *info)
/**
* discard_a_page() - Begin the process of discarding a page.
+ * @cache: The page cache.
*
* If no page is discardable, increments a count of deferred frees so that the next release of a
* page which is no longer busy will kick off another discard cycle. This is an indication that the
@@ -955,10 +977,6 @@ static void discard_a_page(struct vdo_page_cache *cache)
launch_page_save(info);
}
-/**
- * discard_page_for_completion() - Helper used to trigger a discard so that the completion can get
- * a different page.
- */
static void discard_page_for_completion(struct vdo_page_completion *vdo_page_comp)
{
struct vdo_page_cache *cache = vdo_page_comp->cache;
@@ -1132,6 +1150,7 @@ static void write_pages(struct vdo_completion *flush_completion)
/**
* vdo_release_page_completion() - Release a VDO Page Completion.
+ * @completion: The page completion to release.
*
* The page referenced by this completion (if any) will no longer be held busy by this completion.
* If a page becomes discardable and there are completions awaiting free pages then a new round of
@@ -1172,10 +1191,6 @@ void vdo_release_page_completion(struct vdo_completion *completion)
}
}
-/**
- * load_page_for_completion() - Helper function to load a page as described by a VDO Page
- * Completion.
- */
static void load_page_for_completion(struct page_info *info,
struct vdo_page_completion *vdo_page_comp)
{
@@ -1319,6 +1334,7 @@ int vdo_get_cached_page(struct vdo_completion *completion,
/**
* vdo_invalidate_page_cache() - Invalidate all entries in the VDO page cache.
+ * @cache: The page cache.
*
* There must not be any dirty pages in the cache.
*
@@ -1345,6 +1361,10 @@ int vdo_invalidate_page_cache(struct vdo_page_cache *cache)
/**
* get_tree_page_by_index() - Get the tree page for a given height and page index.
+ * @forest: The block map forest.
+ * @root_index: The root index of the tree to search.
+ * @height: The height in the tree.
+ * @page_index: The page index.
*
* Return: The requested page.
*/
@@ -2211,6 +2231,7 @@ static void allocate_block_map_page(struct block_map_zone *zone,
/**
* vdo_find_block_map_slot() - Find the block map slot in which the block map entry for a data_vio
* resides and cache that result in the data_vio.
+ * @data_vio: The data vio.
*
* All ancestors in the tree will be allocated or loaded, as needed.
*/
@@ -2435,6 +2456,7 @@ static void deforest(struct forest *forest, size_t first_page_segment)
/**
* make_forest() - Make a collection of trees for a block_map, expanding the existing forest if
* there is one.
+ * @map: The block map.
* @entries: The number of entries the block map will hold.
*
* Return: VDO_SUCCESS or an error.
@@ -2476,6 +2498,7 @@ static int make_forest(struct block_map *map, block_count_t entries)
/**
* replace_forest() - Replace a block_map's forest with the already-prepared larger forest.
+ * @map: The block map.
*/
static void replace_forest(struct block_map *map)
{
@@ -2492,6 +2515,7 @@ static void replace_forest(struct block_map *map)
/**
* finish_cursor() - Finish the traversal of a single tree. If it was the last cursor, finish the
* traversal.
+ * @cursor: The cursor to complete.
*/
static void finish_cursor(struct cursor *cursor)
{
@@ -2549,6 +2573,7 @@ static void traversal_endio(struct bio *bio)
/**
* traverse() - Traverse a single block map tree.
+ * @cursor: A cursor tracking traversal progress.
*
* This is the recursive heart of the traversal process.
*/
@@ -2619,6 +2644,7 @@ static void traverse(struct cursor *cursor)
/**
* launch_cursor() - Start traversing a single block map tree now that the cursor has a VIO with
* which to load pages.
+ * @waiter: The parent of the cursor to launch.
* @context: The pooled_vio just acquired.
*
* Implements waiter_callback_fn.
@@ -2636,6 +2662,8 @@ static void launch_cursor(struct vdo_waiter *waiter, void *context)
/**
* compute_boundary() - Compute the number of pages used at each level of the given root's tree.
+ * @map: The block map.
+ * @root_index: The tree root index.
*
* Return: The list of page counts as a boundary structure.
*/
@@ -2668,6 +2696,7 @@ static struct boundary compute_boundary(struct block_map *map, root_count_t root
/**
* vdo_traverse_forest() - Walk the entire forest of a block map.
+ * @map: The block map.
* @callback: A function to call with the pbn of each allocated node in the forest.
* @completion: The completion to notify on each traversed PBN, and when traversal completes.
*/
@@ -2707,6 +2736,9 @@ void vdo_traverse_forest(struct block_map *map, vdo_entry_callback_fn callback,
/**
* initialize_block_map_zone() - Initialize the per-zone portions of the block map.
+ * @map: The block map.
+ * @zone_number: The zone to initialize.
+ * @cache_size: The total block map cache size.
* @maximum_age: The number of journal blocks before a dirtied page is considered old and must be
* written out.
*/
@@ -3091,6 +3123,7 @@ static void fetch_mapping_page(struct data_vio *data_vio, bool modifiable,
/**
* clear_mapped_location() - Clear a data_vio's mapped block location, setting it to be unmapped.
+ * @data_vio: The data vio.
*
* This indicates the block map entry for the logical block is either unmapped or corrupted.
*/
@@ -3104,6 +3137,8 @@ static void clear_mapped_location(struct data_vio *data_vio)
/**
* set_mapped_location() - Decode and validate a block map entry, and set the mapped location of a
* data_vio.
+ * @data_vio: The data vio.
+ * @entry: The new mapped entry to set.
*
* Return: VDO_SUCCESS or VDO_BAD_MAPPING if the map entry is invalid or an error code for any
* other failure
diff --git a/drivers/md/dm-vdo/completion.c b/drivers/md/dm-vdo/completion.c
index 5ad85334632d..2f00acbb3b2b 100644
--- a/drivers/md/dm-vdo/completion.c
+++ b/drivers/md/dm-vdo/completion.c
@@ -65,6 +65,8 @@ static inline void assert_incomplete(struct vdo_completion *completion)
/**
* vdo_set_completion_result() - Set the result of a completion.
+ * @completion: The completion to update.
+ * @result: The result to set.
*
* Older errors will not be masked.
*/
@@ -77,6 +79,7 @@ void vdo_set_completion_result(struct vdo_completion *completion, int result)
/**
* vdo_launch_completion_with_priority() - Run or enqueue a completion.
+ * @completion: The completion to launch.
* @priority: The priority at which to enqueue the completion.
*
* If called on the correct thread (i.e. the one specified in the completion's callback_thread_id
@@ -125,6 +128,8 @@ void vdo_enqueue_completion(struct vdo_completion *completion,
/**
* vdo_requeue_completion_if_needed() - Requeue a completion if not called on the specified thread.
+ * @completion: The completion to requeue.
+ * @callback_thread_id: The thread on which to requeue the completion.
*
* Return: True if the completion was requeued; callers may not access the completion in this case.
*/
diff --git a/drivers/md/dm-vdo/data-vio.c b/drivers/md/dm-vdo/data-vio.c
index 262e11581f2d..3333e1e5b02e 100644
--- a/drivers/md/dm-vdo/data-vio.c
+++ b/drivers/md/dm-vdo/data-vio.c
@@ -227,6 +227,7 @@ static inline u64 get_arrival_time(struct bio *bio)
/**
* check_for_drain_complete_locked() - Check whether a data_vio_pool has no outstanding data_vios
* or waiters while holding the pool's lock.
+ * @pool: The data_vio pool.
*/
static bool check_for_drain_complete_locked(struct data_vio_pool *pool)
{
@@ -387,6 +388,7 @@ struct data_vio_compression_status advance_data_vio_compression_stage(struct dat
/**
* cancel_data_vio_compression() - Prevent this data_vio from being compressed or packed.
+ * @data_vio: The data_vio.
*
* Return: true if the data_vio is in the packer and the caller was the first caller to cancel it.
*/
@@ -483,6 +485,8 @@ static void attempt_logical_block_lock(struct vdo_completion *completion)
/**
* launch_data_vio() - (Re)initialize a data_vio to have a new logical block number, keeping the
* same parent and other state and send it on its way.
+ * @data_vio: The data_vio to launch.
+ * @lbn: The logical block number.
*/
static void launch_data_vio(struct data_vio *data_vio, logical_block_number_t lbn)
{
@@ -641,6 +645,7 @@ static void update_limiter(struct limiter *limiter)
/**
* schedule_releases() - Ensure that release processing is scheduled.
+ * @pool: The data_vio pool.
*
* If this call switches the state to processing, enqueue. Otherwise, some other thread has already
* done so.
@@ -768,6 +773,8 @@ static void initialize_limiter(struct limiter *limiter, struct data_vio_pool *po
/**
* initialize_data_vio() - Allocate the components of a data_vio.
+ * @data_vio: The data_vio to initialize.
+ * @vdo: The vdo containing the data_vio.
*
* The caller is responsible for cleaning up the data_vio on error.
*
@@ -880,6 +887,7 @@ int make_data_vio_pool(struct vdo *vdo, data_vio_count_t pool_size,
/**
* free_data_vio_pool() - Free a data_vio_pool and the data_vios in it.
+ * @pool: The data_vio pool to free.
*
* All data_vios must be returned to the pool before calling this function.
*/
@@ -944,6 +952,8 @@ static void wait_permit(struct limiter *limiter, struct bio *bio)
/**
* vdo_launch_bio() - Acquire a data_vio from the pool, assign the bio to it, and launch it.
+ * @pool: The data_vio pool.
+ * @bio: The bio to launch.
*
* This will block if data_vios or discard permits are not available.
*/
@@ -994,6 +1004,7 @@ static void assert_on_vdo_cpu_thread(const struct vdo *vdo, const char *name)
/**
* drain_data_vio_pool() - Wait asynchronously for all data_vios to be returned to the pool.
+ * @pool: The data_vio pool.
* @completion: The completion to notify when the pool has drained.
*/
void drain_data_vio_pool(struct data_vio_pool *pool, struct vdo_completion *completion)
@@ -1005,6 +1016,7 @@ void drain_data_vio_pool(struct data_vio_pool *pool, struct vdo_completion *comp
/**
* resume_data_vio_pool() - Resume a data_vio pool.
+ * @pool: The data_vio pool.
* @completion: The completion to notify when the pool has resumed.
*/
void resume_data_vio_pool(struct data_vio_pool *pool, struct vdo_completion *completion)
@@ -1024,6 +1036,7 @@ static void dump_limiter(const char *name, struct limiter *limiter)
/**
* dump_data_vio_pool() - Dump a data_vio pool to the log.
+ * @pool: The data_vio pool.
* @dump_vios: Whether to dump the details of each busy data_vio as well.
*/
void dump_data_vio_pool(struct data_vio_pool *pool, bool dump_vios)
@@ -1114,6 +1127,7 @@ static void perform_cleanup_stage(struct data_vio *data_vio,
/**
* release_allocated_lock() - Release the PBN lock and/or the reference on the allocated block at
* the end of processing a data_vio.
+ * @completion: The data_vio holding the lock.
*/
static void release_allocated_lock(struct vdo_completion *completion)
{
@@ -1194,6 +1208,7 @@ static void transfer_lock(struct data_vio *data_vio, struct lbn_lock *lock)
/**
* release_logical_lock() - Release the logical block lock and flush generation lock at the end of
* processing a data_vio.
+ * @completion: The data_vio holding the lock.
*/
static void release_logical_lock(struct vdo_completion *completion)
{
@@ -1228,6 +1243,7 @@ static void clean_hash_lock(struct vdo_completion *completion)
/**
* finish_cleanup() - Make some assertions about a data_vio which has finished cleaning up.
+ * @data_vio: The data_vio.
*
* If it is part of a multi-block discard, starts on the next block, otherwise, returns it to the
* pool.
@@ -1342,6 +1358,7 @@ void handle_data_vio_error(struct vdo_completion *completion)
/**
* get_data_vio_operation_name() - Get the name of the last asynchronous operation performed on a
* data_vio.
+ * @data_vio: The data_vio.
*/
const char *get_data_vio_operation_name(struct data_vio *data_vio)
{
@@ -1355,7 +1372,7 @@ const char *get_data_vio_operation_name(struct data_vio *data_vio)
/**
* data_vio_allocate_data_block() - Allocate a data block.
- *
+ * @data_vio: The data_vio.
* @write_lock_type: The type of write lock to obtain on the block.
* @callback: The callback which will attempt an allocation in the current zone and continue if it
* succeeds.
@@ -1379,6 +1396,7 @@ void data_vio_allocate_data_block(struct data_vio *data_vio,
/**
* release_data_vio_allocation_lock() - Release the PBN lock on a data_vio's allocated block.
+ * @data_vio: The data_vio.
* @reset: If true, the allocation will be reset (i.e. any allocated pbn will be forgotten).
*
* If the reference to the locked block is still provisional, it will be released as well.
@@ -1399,6 +1417,7 @@ void release_data_vio_allocation_lock(struct data_vio *data_vio, bool reset)
/**
* uncompress_data_vio() - Uncompress the data a data_vio has just read.
+ * @data_vio: The data_vio.
* @mapping_state: The mapping state indicating which fragment to decompress.
* @buffer: The buffer to receive the uncompressed data.
*/
@@ -1519,6 +1538,7 @@ static void complete_zero_read(struct vdo_completion *completion)
/**
* read_block() - Read a block asynchronously.
+ * @completion: The data_vio doing the read.
*
* This is the callback registered in read_block_mapping().
*/
@@ -1675,6 +1695,7 @@ static void journal_remapping(struct vdo_completion *completion)
/**
* read_old_block_mapping() - Get the previous PBN/LBN mapping of an in-progress write.
+ * @completion: The data_vio doing the read.
*
* Gets the previous PBN mapped to this LBN from the block map, so as to make an appropriate
* journal entry referencing the removal of this LBN->PBN mapping.
@@ -1704,6 +1725,7 @@ void update_metadata_for_data_vio_write(struct data_vio *data_vio, struct pbn_lo
/**
* pack_compressed_data() - Attempt to pack the compressed data_vio into a block.
+ * @completion: The data_vio.
*
* This is the callback registered in launch_compress_data_vio().
*/
@@ -1725,6 +1747,7 @@ static void pack_compressed_data(struct vdo_completion *completion)
/**
* compress_data_vio() - Do the actual work of compressing the data on a CPU queue.
+ * @completion: The data_vio.
*
* This callback is registered in launch_compress_data_vio().
*/
@@ -1754,6 +1777,7 @@ static void compress_data_vio(struct vdo_completion *completion)
/**
* launch_compress_data_vio() - Continue a write by attempting to compress the data.
+ * @data_vio: The data_vio.
*
* This is a re-entry point to vio_write used by hash locks.
*/
@@ -1796,7 +1820,8 @@ void launch_compress_data_vio(struct data_vio *data_vio)
/**
* hash_data_vio() - Hash the data in a data_vio and set the hash zone (which also flags the record
* name as set).
-
+ * @completion: The data_vio.
+ *
* This callback is registered in prepare_for_dedupe().
*/
static void hash_data_vio(struct vdo_completion *completion)
@@ -1832,6 +1857,7 @@ static void prepare_for_dedupe(struct data_vio *data_vio)
/**
* write_bio_finished() - This is the bio_end_io function registered in write_block() to be called
* when a data_vio's write to the underlying storage has completed.
+ * @bio: The bio to update.
*/
static void write_bio_finished(struct bio *bio)
{
@@ -1884,6 +1910,7 @@ void write_data_vio(struct data_vio *data_vio)
/**
* acknowledge_write_callback() - Acknowledge a write to the requestor.
+ * @completion: The data_vio.
*
* This callback is registered in allocate_block() and continue_write_with_block_map_slot().
*/
@@ -1909,6 +1936,7 @@ static void acknowledge_write_callback(struct vdo_completion *completion)
/**
* allocate_block() - Attempt to allocate a block in the current allocation zone.
+ * @completion: The data_vio.
*
* This callback is registered in continue_write_with_block_map_slot().
*/
@@ -1941,6 +1969,7 @@ static void allocate_block(struct vdo_completion *completion)
/**
* handle_allocation_error() - Handle an error attempting to allocate a block.
+ * @completion: The data_vio.
*
* This error handler is registered in continue_write_with_block_map_slot().
*/
@@ -1970,6 +1999,7 @@ static int assert_is_discard(struct data_vio *data_vio)
/**
* continue_data_vio_with_block_map_slot() - Read the data_vio's mapping from the block map.
+ * @completion: The data_vio to continue.
*
* This callback is registered in launch_read_data_vio().
*/
diff --git a/drivers/md/dm-vdo/dedupe.c b/drivers/md/dm-vdo/dedupe.c
index 4d983092a152..75a26f3f4461 100644
--- a/drivers/md/dm-vdo/dedupe.c
+++ b/drivers/md/dm-vdo/dedupe.c
@@ -917,6 +917,8 @@ static int __must_check acquire_lock(struct hash_zone *zone,
/**
* enter_forked_lock() - Bind the data_vio to a new hash lock.
+ * @waiter: The data_vio's waiter link.
+ * @context: The new hash lock.
*
* Implements waiter_callback_fn. Binds the data_vio that was waiting to a new hash lock and waits
* on that lock.
@@ -971,7 +973,7 @@ static void fork_hash_lock(struct hash_lock *old_lock, struct data_vio *new_agen
* path.
* @lock: The hash lock.
* @data_vio: The data_vio to deduplicate using the hash lock.
- * @has_claim: true if the data_vio already has claimed an increment from the duplicate lock.
+ * @has_claim: True if the data_vio already has claimed an increment from the duplicate lock.
*
* If no increments are available, this will roll over to a new hash lock and launch the data_vio
* as the writing agent for that lock.
@@ -996,7 +998,7 @@ static void launch_dedupe(struct hash_lock *lock, struct data_vio *data_vio,
* true copy of their data on disk.
* @lock: The hash lock.
* @agent: The data_vio acting as the agent for the lock.
- * @agent_is_done: true only if the agent has already written or deduplicated against its data.
+ * @agent_is_done: True only if the agent has already written or deduplicated against its data.
*
* If the agent itself needs to deduplicate, an increment for it must already have been claimed
* from the duplicate lock, ensuring the hash lock will still have a data_vio holding it.
@@ -2146,8 +2148,8 @@ static void start_expiration_timer(struct dedupe_context *context)
/**
* report_dedupe_timeouts() - Record and eventually report that some dedupe requests reached their
* expiration time without getting answers, so we timed them out.
- * @zones: the hash zones.
- * @timeouts: the number of newly timed out requests.
+ * @zones: The hash zones.
+ * @timeouts: The number of newly timed out requests.
*/
static void report_dedupe_timeouts(struct hash_zones *zones, unsigned int timeouts)
{
@@ -2509,6 +2511,8 @@ static void initiate_suspend_index(struct admin_state *state)
/**
* suspend_index() - Suspend the UDS index prior to draining hash zones.
+ * @context: Not used.
+ * @completion: The completion for the suspend operation.
*
* Implements vdo_action_preamble_fn
*/
@@ -2521,21 +2525,13 @@ static void suspend_index(void *context, struct vdo_completion *completion)
initiate_suspend_index);
}
-/**
- * initiate_drain() - Initiate a drain.
- *
- * Implements vdo_admin_initiator_fn.
- */
+/** Implements vdo_admin_initiator_fn. */
static void initiate_drain(struct admin_state *state)
{
check_for_drain_complete(container_of(state, struct hash_zone, state));
}
-/**
- * drain_hash_zone() - Drain a hash zone.
- *
- * Implements vdo_zone_action_fn.
- */
+/** Implements vdo_zone_action_fn. */
static void drain_hash_zone(void *context, zone_count_t zone_number,
struct vdo_completion *parent)
{
@@ -2572,6 +2568,8 @@ static void launch_dedupe_state_change(struct hash_zones *zones)
/**
* resume_index() - Resume the UDS index prior to resuming hash zones.
+ * @context: Not used.
+ * @parent: The completion for the resume operation.
*
* Implements vdo_action_preamble_fn
*/
@@ -2602,11 +2600,7 @@ static void resume_index(void *context, struct vdo_completion *parent)
vdo_finish_completion(parent);
}
-/**
- * resume_hash_zone() - Resume a hash zone.
- *
- * Implements vdo_zone_action_fn.
- */
+/** Implements vdo_zone_action_fn. */
static void resume_hash_zone(void *context, zone_count_t zone_number,
struct vdo_completion *parent)
{
@@ -2634,7 +2628,7 @@ void vdo_resume_hash_zones(struct hash_zones *zones, struct vdo_completion *pare
/**
* get_hash_zone_statistics() - Add the statistics for this hash zone to the tally for all zones.
* @zone: The hash zone to query.
- * @tally: The tally
+ * @tally: The tally.
*/
static void get_hash_zone_statistics(const struct hash_zone *zone,
struct hash_lock_statistics *tally)
@@ -2680,8 +2674,8 @@ static void get_index_statistics(struct hash_zones *zones,
/**
* vdo_get_dedupe_statistics() - Tally the statistics from all the hash zones and the UDS index.
- * @zones: The hash zones to query
- * @stats: A structure to store the statistics
+ * @zones: The hash zones to query.
+ * @stats: A structure to store the statistics.
*
* Return: The sum of the hash lock statistics from all hash zones plus the statistics from the UDS
* index
@@ -2856,9 +2850,9 @@ void vdo_set_dedupe_index_min_timer_interval(unsigned int value)
/**
* acquire_context() - Acquire a dedupe context from a hash_zone if any are available.
- * @zone: the hash zone
+ * @zone: The hash zone.
*
- * Return: A dedupe_context or NULL if none are available
+ * Return: A dedupe_context or NULL if none are available.
*/
static struct dedupe_context * __must_check acquire_context(struct hash_zone *zone)
{
diff --git a/drivers/md/dm-vdo/dm-vdo-target.c b/drivers/md/dm-vdo/dm-vdo-target.c
index 0e04c2021682..6af40d40f255 100644
--- a/drivers/md/dm-vdo/dm-vdo-target.c
+++ b/drivers/md/dm-vdo/dm-vdo-target.c
@@ -1144,6 +1144,7 @@ static bool vdo_uses_device(struct vdo *vdo, const void *context)
/**
* get_thread_id_for_phase() - Get the thread id for the current phase of the admin operation in
* progress.
+ * @vdo: The vdo.
*/
static thread_id_t __must_check get_thread_id_for_phase(struct vdo *vdo)
{
@@ -1188,9 +1189,9 @@ static struct vdo_completion *prepare_admin_completion(struct vdo *vdo,
/**
* advance_phase() - Increment the phase of the current admin operation and prepare the admin
* completion to run on the thread for the next phase.
- * @vdo: The on which an admin operation is being performed
+ * @vdo: The vdo on which an admin operation is being performed.
*
- * Return: The current phase
+ * Return: The current phase.
*/
static u32 advance_phase(struct vdo *vdo)
{
diff --git a/drivers/md/dm-vdo/encodings.c b/drivers/md/dm-vdo/encodings.c
index b7cc0f41caca..dd59691be840 100644
--- a/drivers/md/dm-vdo/encodings.c
+++ b/drivers/md/dm-vdo/encodings.c
@@ -432,7 +432,10 @@ static void encode_block_map_state_2_0(u8 *buffer, size_t *offset,
/**
* vdo_compute_new_forest_pages() - Compute the number of pages which must be allocated at each
* level in order to grow the forest to a new number of entries.
+ * @root_count: The number of block map roots.
+ * @old_sizes: The sizes of the old tree segments.
* @entries: The new number of entries the block map must address.
+ * @new_sizes: The sizes of the new tree segments.
*
* Return: The total number of non-leaf pages required.
*/
@@ -462,6 +465,9 @@ block_count_t vdo_compute_new_forest_pages(root_count_t root_count,
/**
* encode_recovery_journal_state_7_0() - Encode the state of a recovery journal.
+ * @buffer: A buffer to store the encoding.
+ * @offset: The offset in the buffer at which to encode.
+ * @state: The recovery journal state to encode.
*
* Return: VDO_SUCCESS or an error code.
*/
@@ -484,6 +490,7 @@ static void encode_recovery_journal_state_7_0(u8 *buffer, size_t *offset,
/**
* decode_recovery_journal_state_7_0() - Decode the state of a recovery journal saved in a buffer.
* @buffer: The buffer containing the saved state.
+ * @offset: The offset to start decoding from.
* @state: A pointer to a recovery journal state to hold the result of a successful decode.
*
* Return: VDO_SUCCESS or an error code.
@@ -544,6 +551,9 @@ const char *vdo_get_journal_operation_name(enum journal_operation operation)
/**
* encode_slab_depot_state_2_0() - Encode the state of a slab depot into a buffer.
+ * @buffer: A buffer to store the encoding.
+ * @offset: The offset in the buffer at which to encode.
+ * @state: The slab depot state to encode.
*/
static void encode_slab_depot_state_2_0(u8 *buffer, size_t *offset,
struct slab_depot_state_2_0 state)
@@ -570,6 +580,9 @@ static void encode_slab_depot_state_2_0(u8 *buffer, size_t *offset,
/**
* decode_slab_depot_state_2_0() - Decode slab depot component state version 2.0 from a buffer.
+ * @buffer: The buffer being decoded.
+ * @offset: The offset to start decoding from.
+ * @state: A pointer to a slab depot state to hold the decoded result.
*
* Return: VDO_SUCCESS or an error code.
*/
@@ -1156,6 +1169,9 @@ static struct vdo_component unpack_vdo_component_41_0(struct packed_vdo_componen
/**
* decode_vdo_component() - Decode the component data for the vdo itself out of the super block.
+ * @buffer: The buffer being decoded.
+ * @offset: The offset to start decoding from.
+ * @component: The vdo component structure to decode into.
*
* Return: VDO_SUCCESS or an error.
*/
@@ -1290,7 +1306,7 @@ void vdo_destroy_component_states(struct vdo_component_states *states)
* understand.
* @buffer: The buffer being decoded.
* @offset: The offset to start decoding from.
- * @geometry: The vdo geometry
+ * @geometry: The vdo geometry.
* @states: An object to hold the successfully decoded state.
*
* Return: VDO_SUCCESS or an error.
@@ -1329,7 +1345,7 @@ static int __must_check decode_components(u8 *buffer, size_t *offset,
/**
* vdo_decode_component_states() - Decode the payload of a super block.
* @buffer: The buffer containing the encoded super block contents.
- * @geometry: The vdo geometry
+ * @geometry: The vdo geometry.
* @states: A pointer to hold the decoded states.
*
* Return: VDO_SUCCESS or an error.
@@ -1383,6 +1399,9 @@ int vdo_validate_component_states(struct vdo_component_states *states,
/**
* vdo_encode_component_states() - Encode the state of all vdo components in the super block.
+ * @buffer: A buffer to store the encoding.
+ * @offset: The offset into the buffer to start the encoding.
+ * @states: The component states to encode.
*/
static void vdo_encode_component_states(u8 *buffer, size_t *offset,
const struct vdo_component_states *states)
@@ -1402,6 +1421,8 @@ static void vdo_encode_component_states(u8 *buffer, size_t *offset,
/**
* vdo_encode_super_block() - Encode a super block into its on-disk representation.
+ * @buffer: A buffer to store the encoding.
+ * @states: The component states to encode.
*/
void vdo_encode_super_block(u8 *buffer, struct vdo_component_states *states)
{
@@ -1426,6 +1447,7 @@ void vdo_encode_super_block(u8 *buffer, struct vdo_component_states *states)
/**
* vdo_decode_super_block() - Decode a super block from its on-disk representation.
+ * @buffer: The buffer to decode from.
*/
int vdo_decode_super_block(u8 *buffer)
{
diff --git a/drivers/md/dm-vdo/flush.c b/drivers/md/dm-vdo/flush.c
index dd4fdee2ca0c..82a259ef1601 100644
--- a/drivers/md/dm-vdo/flush.c
+++ b/drivers/md/dm-vdo/flush.c
@@ -522,11 +522,7 @@ static void vdo_complete_flush(struct vdo_flush *flush)
vdo_enqueue_completion(completion, BIO_Q_FLUSH_PRIORITY);
}
-/**
- * initiate_drain() - Initiate a drain.
- *
- * Implements vdo_admin_initiator_fn.
- */
+/** Implements vdo_admin_initiator_fn. */
static void initiate_drain(struct admin_state *state)
{
check_for_drain_complete(container_of(state, struct flusher, state));
diff --git a/drivers/md/dm-vdo/funnel-workqueue.c b/drivers/md/dm-vdo/funnel-workqueue.c
index 0613c82bbe8e..8a79b33b8b09 100644
--- a/drivers/md/dm-vdo/funnel-workqueue.c
+++ b/drivers/md/dm-vdo/funnel-workqueue.c
@@ -372,6 +372,13 @@ static int make_simple_work_queue(const char *thread_name_prefix, const char *na
/**
* vdo_make_work_queue() - Create a work queue; if multiple threads are requested, completions will
* be distributed to them in round-robin fashion.
+ * @thread_name_prefix: A prefix for the thread names to identify them as a vdo thread.
+ * @name: A base name to identify this queue.
+ * @owner: The vdo_thread structure to manage this queue.
+ * @type: The type of queue to create.
+ * @thread_count: The number of actual threads handling this queue.
+ * @thread_privates: An array of private contexts, one for each thread; may be NULL.
+ * @queue_ptr: A pointer to return the new work queue.
*
* Each queue is associated with a struct vdo_thread which has a single vdo thread id. Regardless
* of the actual number of queues and threads allocated here, code outside of the queue
diff --git a/drivers/md/dm-vdo/io-submitter.c b/drivers/md/dm-vdo/io-submitter.c
index 11d47770b54d..e26d75f8366d 100644
--- a/drivers/md/dm-vdo/io-submitter.c
+++ b/drivers/md/dm-vdo/io-submitter.c
@@ -118,6 +118,7 @@ static void send_bio_to_device(struct vio *vio, struct bio *bio)
/**
* vdo_submit_vio() - Submits a vio's bio to the underlying block device. May block if the device
* is busy. This callback should be used by vios which did not attempt to merge.
+ * @completion: The vio to submit.
*/
void vdo_submit_vio(struct vdo_completion *completion)
{
@@ -133,7 +134,7 @@ void vdo_submit_vio(struct vdo_completion *completion)
* The list will always contain at least one entry (the bio for the vio on which it is called), but
* other bios may have been merged with it as well.
*
- * Return: bio The head of the bio list to submit.
+ * Return: The head of the bio list to submit.
*/
static struct bio *get_bio_list(struct vio *vio)
{
@@ -158,6 +159,7 @@ static struct bio *get_bio_list(struct vio *vio)
/**
* submit_data_vio() - Submit a data_vio's bio to the storage below along with
* any bios that have been merged with it.
+ * @completion: The vio to submit.
*
* Context: This call may block and so should only be called from a bio thread.
*/
@@ -184,7 +186,7 @@ static void submit_data_vio(struct vdo_completion *completion)
* There are two types of merging possible, forward and backward, which are distinguished by a flag
* that uses kernel elevator terminology.
*
- * Return: the vio to merge to, NULL if no merging is possible.
+ * Return: The vio to merge to, NULL if no merging is possible.
*/
static struct vio *get_mergeable_locked(struct int_map *map, struct vio *vio,
bool back_merge)
@@ -262,7 +264,7 @@ static int merge_to_next_head(struct int_map *bio_map, struct vio *vio,
*
* Currently this is only used for data_vios, but is broken out for future use with metadata vios.
*
- * Return: whether or not the vio was merged.
+ * Return: Whether or not the vio was merged.
*/
static bool try_bio_map_merge(struct vio *vio)
{
@@ -306,7 +308,7 @@ static bool try_bio_map_merge(struct vio *vio)
/**
* vdo_submit_data_vio() - Submit I/O for a data_vio.
- * @data_vio: the data_vio for which to issue I/O.
+ * @data_vio: The data_vio for which to issue I/O.
*
* If possible, this I/O will be merged other pending I/Os. Otherwise, the data_vio will be sent to
* the appropriate bio zone directly.
@@ -321,13 +323,13 @@ void vdo_submit_data_vio(struct data_vio *data_vio)
/**
* __submit_metadata_vio() - Submit I/O for a metadata vio.
- * @vio: the vio for which to issue I/O
- * @physical: the physical block number to read or write
- * @callback: the bio endio function which will be called after the I/O completes
- * @error_handler: the handler for submission or I/O errors (may be NULL)
- * @operation: the type of I/O to perform
- * @data: the buffer to read or write (may be NULL)
- * @size: the I/O amount in bytes
+ * @vio: The vio for which to issue I/O.
+ * @physical: The physical block number to read or write.
+ * @callback: The bio endio function which will be called after the I/O completes.
+ * @error_handler: The handler for submission or I/O errors; may be NULL.
+ * @operation: The type of I/O to perform.
+ * @data: The buffer to read or write; may be NULL.
+ * @size: The I/O amount in bytes.
*
* The vio is enqueued on a vdo bio queue so that bio submission (which may block) does not block
* other vdo threads.
@@ -441,7 +443,7 @@ int vdo_make_io_submitter(unsigned int thread_count, unsigned int rotation_inter
/**
* vdo_cleanup_io_submitter() - Tear down the io_submitter fields as needed for a physical layer.
- * @io_submitter: The I/O submitter data to tear down (may be NULL).
+ * @io_submitter: The I/O submitter data to tear down; may be NULL.
*/
void vdo_cleanup_io_submitter(struct io_submitter *io_submitter)
{
diff --git a/drivers/md/dm-vdo/logical-zone.c b/drivers/md/dm-vdo/logical-zone.c
index 026f031ffc9e..0a27e60a9dfd 100644
--- a/drivers/md/dm-vdo/logical-zone.c
+++ b/drivers/md/dm-vdo/logical-zone.c
@@ -159,21 +159,13 @@ static void check_for_drain_complete(struct logical_zone *zone)
vdo_finish_draining(&zone->state);
}
-/**
- * initiate_drain() - Initiate a drain.
- *
- * Implements vdo_admin_initiator_fn.
- */
+/** Implements vdo_admin_initiator_fn. */
static void initiate_drain(struct admin_state *state)
{
check_for_drain_complete(container_of(state, struct logical_zone, state));
}
-/**
- * drain_logical_zone() - Drain a logical zone.
- *
- * Implements vdo_zone_action_fn.
- */
+/** Implements vdo_zone_action_fn. */
static void drain_logical_zone(void *context, zone_count_t zone_number,
struct vdo_completion *parent)
{
@@ -192,11 +184,7 @@ void vdo_drain_logical_zones(struct logical_zones *zones,
parent);
}
-/**
- * resume_logical_zone() - Resume a logical zone.
- *
- * Implements vdo_zone_action_fn.
- */
+/** Implements vdo_zone_action_fn. */
static void resume_logical_zone(void *context, zone_count_t zone_number,
struct vdo_completion *parent)
{
@@ -356,7 +344,7 @@ struct physical_zone *vdo_get_next_allocation_zone(struct logical_zone *zone)
/**
* vdo_dump_logical_zone() - Dump information about a logical zone to the log for debugging.
- * @zone: The zone to dump
+ * @zone: The zone to dump.
*
* Context: the information is dumped in a thread-unsafe fashion.
*
diff --git a/drivers/md/dm-vdo/packer.c b/drivers/md/dm-vdo/packer.c
index f70f5edabc10..666be6d557e1 100644
--- a/drivers/md/dm-vdo/packer.c
+++ b/drivers/md/dm-vdo/packer.c
@@ -35,10 +35,10 @@ static const struct version_number COMPRESSED_BLOCK_1_0 = {
/**
* vdo_get_compressed_block_fragment() - Get a reference to a compressed fragment from a compressed
* block.
- * @mapping_state [in] The mapping state for the look up.
- * @compressed_block [in] The compressed block that was read from disk.
- * @fragment_offset [out] The offset of the fragment within a compressed block.
- * @fragment_size [out] The size of the fragment.
+ * @mapping_state: The mapping state describing the fragment.
+ * @block: The compressed block that was read from disk.
+ * @fragment_offset: The offset of the fragment within the compressed block.
+ * @fragment_size: The size of the fragment.
*
* Return: If a valid compressed fragment is found, VDO_SUCCESS; otherwise, VDO_INVALID_FRAGMENT if
* the fragment is invalid.
@@ -382,6 +382,7 @@ static void initialize_compressed_block(struct compressed_block *block, u16 size
* @compression: The agent's compression_state to pack in to.
* @data_vio: The data_vio to pack.
* @offset: The offset into the compressed block at which to pack the fragment.
+ * @slot: The slot number in the compressed block.
* @block: The compressed block which will be written out when batch is fully packed.
*
* Return: The new amount of space used.
@@ -705,11 +706,7 @@ void vdo_increment_packer_flush_generation(struct packer *packer)
vdo_flush_packer(packer);
}
-/**
- * initiate_drain() - Initiate a drain.
- *
- * Implements vdo_admin_initiator_fn.
- */
+/** Implements vdo_admin_initiator_fn. */
static void initiate_drain(struct admin_state *state)
{
struct packer *packer = container_of(state, struct packer, state);
diff --git a/drivers/md/dm-vdo/physical-zone.c b/drivers/md/dm-vdo/physical-zone.c
index a43b5c45fab7..686eb7d714e6 100644
--- a/drivers/md/dm-vdo/physical-zone.c
+++ b/drivers/md/dm-vdo/physical-zone.c
@@ -60,7 +60,7 @@ static inline bool has_lock_type(const struct pbn_lock *lock, enum pbn_lock_type
* vdo_is_pbn_read_lock() - Check whether a pbn_lock is a read lock.
* @lock: The lock to check.
*
- * Return: true if the lock is a read lock.
+ * Return: True if the lock is a read lock.
*/
bool vdo_is_pbn_read_lock(const struct pbn_lock *lock)
{
@@ -75,6 +75,7 @@ static inline void set_pbn_lock_type(struct pbn_lock *lock, enum pbn_lock_type t
/**
* vdo_downgrade_pbn_write_lock() - Downgrade a PBN write lock to a PBN read lock.
* @lock: The PBN write lock to downgrade.
+ * @compressed_write: True if the written block was a compressed block.
*
* The lock holder count is cleared and the caller is responsible for setting the new count.
*/
@@ -582,7 +583,7 @@ static bool continue_allocating(struct data_vio *data_vio)
* that fails try the next if possible.
* @data_vio: The data_vio needing an allocation.
*
- * Return: true if a block was allocated, if not the data_vio will have been dispatched so the
+ * Return: True if a block was allocated, if not the data_vio will have been dispatched so the
* caller must not touch it.
*/
bool vdo_allocate_block_in_zone(struct data_vio *data_vio)
diff --git a/drivers/md/dm-vdo/recovery-journal.c b/drivers/md/dm-vdo/recovery-journal.c
index de58184f538f..9cc0f0ff1664 100644
--- a/drivers/md/dm-vdo/recovery-journal.c
+++ b/drivers/md/dm-vdo/recovery-journal.c
@@ -109,7 +109,7 @@ static atomic_t *get_decrement_counter(struct recovery_journal *journal,
* @journal: The recovery journal.
* @lock_number: The lock to check.
*
- * Return: true if the journal zone is locked.
+ * Return: True if the journal zone is locked.
*/
static bool is_journal_zone_locked(struct recovery_journal *journal,
block_count_t lock_number)
@@ -217,7 +217,7 @@ static struct recovery_journal_block * __must_check pop_free_list(struct recover
* Indicates it has any uncommitted entries, which includes both entries not written and entries
* written but not yet acknowledged.
*
- * Return: true if the block has any uncommitted entries.
+ * Return: True if the block has any uncommitted entries.
*/
static inline bool __must_check is_block_dirty(const struct recovery_journal_block *block)
{
@@ -228,7 +228,7 @@ static inline bool __must_check is_block_dirty(const struct recovery_journal_blo
* is_block_empty() - Check whether a journal block is empty.
* @block: The block to check.
*
- * Return: true if the block has no entries.
+ * Return: True if the block has no entries.
*/
static inline bool __must_check is_block_empty(const struct recovery_journal_block *block)
{
@@ -239,7 +239,7 @@ static inline bool __must_check is_block_empty(const struct recovery_journal_blo
* is_block_full() - Check whether a journal block is full.
* @block: The block to check.
*
- * Return: true if the block is full.
+ * Return: True if the block is full.
*/
static inline bool __must_check is_block_full(const struct recovery_journal_block *block)
{
@@ -260,6 +260,8 @@ static void assert_on_journal_thread(struct recovery_journal *journal,
/**
* continue_waiter() - Release a data_vio from the journal.
+ * @waiter: The data_vio waiting on journal activity.
+ * @context: The result of the journal operation.
*
* Invoked whenever a data_vio is to be released from the journal, either because its entry was
* committed to disk, or because there was an error. Implements waiter_callback_fn.
@@ -273,7 +275,7 @@ static void continue_waiter(struct vdo_waiter *waiter, void *context)
* has_block_waiters() - Check whether the journal has any waiters on any blocks.
* @journal: The journal in question.
*
- * Return: true if any block has a waiter.
+ * Return: True if any block has a waiter.
*/
static inline bool has_block_waiters(struct recovery_journal *journal)
{
@@ -296,7 +298,7 @@ static void notify_commit_waiters(struct recovery_journal *journal);
* suspend_lock_counter() - Prevent the lock counter from notifying.
* @counter: The counter.
*
- * Return: true if the lock counter was not notifying and hence the suspend was efficacious.
+ * Return: True if the lock counter was not notifying and hence the suspend was efficacious.
*/
static bool suspend_lock_counter(struct lock_counter *counter)
{
@@ -416,7 +418,7 @@ sequence_number_t vdo_get_recovery_journal_current_sequence_number(struct recove
*
* The head is the lowest sequence number of the block map head and the slab journal head.
*
- * Return: the head of the journal.
+ * Return: The head of the journal.
*/
static inline sequence_number_t get_recovery_journal_head(const struct recovery_journal *journal)
{
@@ -535,7 +537,7 @@ static void initialize_journal_state(struct recovery_journal *journal)
* vdo_get_recovery_journal_length() - Get the number of usable recovery journal blocks.
* @journal_size: The size of the recovery journal in blocks.
*
- * Return: the number of recovery journal blocks usable for entries.
+ * Return: The number of recovery journal blocks usable for entries.
*/
block_count_t vdo_get_recovery_journal_length(block_count_t journal_size)
{
@@ -1078,6 +1080,8 @@ static void update_usages(struct recovery_journal *journal, struct data_vio *dat
/**
* assign_entry() - Assign an entry waiter to the active block.
+ * @waiter: The data_vio.
+ * @context: The recovery journal block.
*
* Implements waiter_callback_fn.
*/
@@ -1165,6 +1169,8 @@ static void recycle_journal_block(struct recovery_journal_block *block)
/**
* continue_committed_waiter() - invoked whenever a VIO is to be released from the journal because
* its entry was committed to disk.
+ * @waiter: The data_vio waiting on a journal write.
+ * @context: A pointer to the recovery journal.
*
* Implements waiter_callback_fn.
*/
@@ -1362,6 +1368,8 @@ static void add_queued_recovery_entries(struct recovery_journal_block *block)
/**
* write_block() - Issue a block for writing.
+ * @waiter: The recovery journal block to write.
+ * @context: Not used.
*
* Implements waiter_callback_fn.
*/
@@ -1611,11 +1619,7 @@ void vdo_release_journal_entry_lock(struct recovery_journal *journal,
smp_mb__after_atomic();
}
-/**
- * initiate_drain() - Initiate a drain.
- *
- * Implements vdo_admin_initiator_fn.
- */
+/** Implements vdo_admin_initiator_fn. */
static void initiate_drain(struct admin_state *state)
{
check_for_drain_complete(container_of(state, struct recovery_journal, state));
diff --git a/drivers/md/dm-vdo/slab-depot.c b/drivers/md/dm-vdo/slab-depot.c
index f3d80ff7bef5..034ecaa51f48 100644
--- a/drivers/md/dm-vdo/slab-depot.c
+++ b/drivers/md/dm-vdo/slab-depot.c
@@ -40,7 +40,7 @@ static const bool NORMAL_OPERATION = true;
/**
* get_lock() - Get the lock object for a slab journal block by sequence number.
- * @journal: vdo_slab journal to retrieve from.
+ * @journal: The vdo_slab journal to retrieve from.
* @sequence_number: Sequence number of the block.
*
* Return: The lock object for the given sequence number.
@@ -110,7 +110,7 @@ static void initialize_journal_state(struct slab_journal *journal)
* block_is_full() - Check whether a journal block is full.
* @journal: The slab journal for the block.
*
- * Return: true if the tail block is full.
+ * Return: True if the tail block is full.
*/
static bool __must_check block_is_full(struct slab_journal *journal)
{
@@ -127,10 +127,11 @@ static void release_journal_locks(struct vdo_waiter *waiter, void *context);
/**
* is_slab_journal_blank() - Check whether a slab's journal is blank.
+ * @slab: The slab to check.
*
* A slab journal is blank if it has never had any entries recorded in it.
*
- * Return: true if the slab's journal has never been modified.
+ * Return: True if the slab's journal has never been modified.
*/
static bool is_slab_journal_blank(const struct vdo_slab *slab)
{
@@ -227,6 +228,7 @@ static u8 __must_check compute_fullness_hint(struct slab_depot *depot,
/**
* check_summary_drain_complete() - Check whether an allocators summary has finished draining.
+ * @allocator: The allocator to check.
*/
static void check_summary_drain_complete(struct block_allocator *allocator)
{
@@ -349,7 +351,7 @@ static void launch_write(struct slab_summary_block *block)
/**
* update_slab_summary_entry() - Update the entry for a slab.
- * @slab: The slab whose entry is to be updated
+ * @slab: The slab whose entry is to be updated.
* @waiter: The waiter that is updating the summary.
* @tail_block_offset: The offset of the slab journal's tail block.
* @load_ref_counts: Whether the reference counts must be loaded from disk on the vdo load.
@@ -654,6 +656,7 @@ static void update_tail_block_location(struct slab_journal *journal)
/**
* reopen_slab_journal() - Reopen a slab's journal by emptying it and then adding pending entries.
+ * @slab: The slab to reopen.
*/
static void reopen_slab_journal(struct vdo_slab *slab)
{
@@ -839,8 +842,6 @@ static void commit_tail(struct slab_journal *journal)
* @sbn: The slab block number of the entry to encode.
* @operation: The type of the entry.
* @increment: True if this is an increment.
- *
- * Exposed for unit tests.
*/
static void encode_slab_journal_entry(struct slab_journal_block_header *tail_header,
slab_journal_payload *payload,
@@ -951,7 +952,7 @@ static inline block_count_t journal_length(const struct slab_journal *journal)
* @parent: The completion to notify when there is space to add the entry if the entry could not be
* added immediately.
*
- * Return: true if the entry was added immediately.
+ * Return: True if the entry was added immediately.
*/
bool vdo_attempt_replay_into_slab(struct vdo_slab *slab, physical_block_number_t pbn,
enum journal_operation operation, bool increment,
@@ -1003,7 +1004,7 @@ bool vdo_attempt_replay_into_slab(struct vdo_slab *slab, physical_block_number_t
* requires_reaping() - Check whether the journal must be reaped before adding new entries.
* @journal: The journal to check.
*
- * Return: true if the journal must be reaped.
+ * Return: True if the journal must be reaped.
*/
static bool requires_reaping(const struct slab_journal *journal)
{
@@ -1275,6 +1276,8 @@ static void dirty_block(struct reference_block *block)
/**
* get_reference_block() - Get the reference block that covers the given block index.
+ * @slab: The slab containing the references.
+ * @index: The index of the physical block.
*/
static struct reference_block * __must_check get_reference_block(struct vdo_slab *slab,
slab_block_number index)
@@ -1379,7 +1382,8 @@ static void prioritize_slab(struct vdo_slab *slab)
/**
* adjust_free_block_count() - Adjust the free block count and (if needed) reprioritize the slab.
- * @incremented: true if the free block count went up.
+ * @slab: The slab.
+ * @incremented: True if the free block count went up.
*/
static void adjust_free_block_count(struct vdo_slab *slab, bool incremented)
{
@@ -1885,6 +1889,7 @@ static void add_entries(struct slab_journal *journal)
/**
* reset_search_cursor() - Reset the free block search back to the first reference counter in the
* first reference block of a slab.
+ * @slab: The slab.
*/
static void reset_search_cursor(struct vdo_slab *slab)
{
@@ -1892,17 +1897,17 @@ static void reset_search_cursor(struct vdo_slab *slab)
cursor->block = cursor->first_block;
cursor->index = 0;
- /* Unit tests have slabs with only one reference block (and it's a runt). */
cursor->end_index = min_t(u32, COUNTS_PER_BLOCK, slab->block_count);
}
/**
* advance_search_cursor() - Advance the search cursor to the start of the next reference block in
- * a slab,
+ * a slab.
+ * @slab: The slab.
*
* Wraps around to the first reference block if the current block is the last reference block.
*
- * Return: true unless the cursor was at the last reference block.
+ * Return: True unless the cursor was at the last reference block.
*/
static bool advance_search_cursor(struct vdo_slab *slab)
{
@@ -1933,6 +1938,9 @@ static bool advance_search_cursor(struct vdo_slab *slab)
/**
* vdo_adjust_reference_count_for_rebuild() - Adjust the reference count of a block during rebuild.
+ * @depot: The slab depot.
+ * @pbn: The physical block number to adjust.
+ * @operation: The type opf operation.
*
* Return: VDO_SUCCESS or an error.
*/
@@ -2038,9 +2046,7 @@ static inline slab_block_number find_zero_byte_in_word(const u8 *word_ptr,
* @slab: The slab counters to scan.
* @index_ptr: A pointer to hold the array index of the free block.
*
- * Exposed for unit testing.
- *
- * Return: true if a free block was found in the specified range.
+ * Return: True if a free block was found in the specified range.
*/
static bool find_free_block(const struct vdo_slab *slab, slab_block_number *index_ptr)
{
@@ -2097,7 +2103,7 @@ static bool find_free_block(const struct vdo_slab *slab, slab_block_number *inde
* @slab: The slab to search.
* @free_index_ptr: A pointer to receive the array index of the zero reference count.
*
- * Return: true if an unreferenced counter was found.
+ * Return: True if an unreferenced counter was found.
*/
static bool search_current_reference_block(const struct vdo_slab *slab,
slab_block_number *free_index_ptr)
@@ -2116,7 +2122,7 @@ static bool search_current_reference_block(const struct vdo_slab *slab,
* counter index saved in the search cursor and searching up to the end of the last reference
* block. The search does not wrap.
*
- * Return: true if an unreferenced counter was found.
+ * Return: True if an unreferenced counter was found.
*/
static bool search_reference_blocks(struct vdo_slab *slab,
slab_block_number *free_index_ptr)
@@ -2136,6 +2142,8 @@ static bool search_reference_blocks(struct vdo_slab *slab,
/**
* make_provisional_reference() - Do the bookkeeping for making a provisional reference.
+ * @slab: The slab.
+ * @block_number: The index for the physical block to reference.
*/
static void make_provisional_reference(struct vdo_slab *slab,
slab_block_number block_number)
@@ -2155,6 +2163,7 @@ static void make_provisional_reference(struct vdo_slab *slab,
/**
* dirty_all_reference_blocks() - Mark all reference count blocks in a slab as dirty.
+ * @slab: The slab.
*/
static void dirty_all_reference_blocks(struct vdo_slab *slab)
{
@@ -2173,10 +2182,10 @@ static inline bool journal_points_equal(struct journal_point first,
/**
* match_bytes() - Check an 8-byte word for bytes matching the value specified
- * @input: A word to examine the bytes of
- * @match: The byte value sought
+ * @input: A word to examine the bytes of.
+ * @match: The byte value sought.
*
- * Return: 1 in each byte when the corresponding input byte matched, 0 otherwise
+ * Return: 1 in each byte when the corresponding input byte matched, 0 otherwise.
*/
static inline u64 match_bytes(u64 input, u8 match)
{
@@ -2191,12 +2200,12 @@ static inline u64 match_bytes(u64 input, u8 match)
/**
* count_valid_references() - Process a newly loaded refcount array
- * @counters: the array of counters from a metadata block
+ * @counters: The array of counters from a metadata block.
*
- * Scan a 8-byte-aligned array of counters, fixing up any "provisional" values that weren't
- * cleaned up at shutdown, changing them internally to "empty".
+ * Scan an 8-byte-aligned array of counters, fixing up any provisional values that
+ * weren't cleaned up at shutdown, changing them internally to zero.
*
- * Return: the number of blocks that are referenced (counters not "empty")
+ * Return: The number of blocks with a non-zero reference count.
*/
static unsigned int count_valid_references(vdo_refcount_t *counters)
{
@@ -2351,6 +2360,7 @@ static void load_reference_block_group(struct vdo_waiter *waiter, void *context)
/**
* load_reference_blocks() - Load a slab's reference blocks from the underlying storage into a
* pre-allocated reference counter.
+ * @slab: The slab.
*/
static void load_reference_blocks(struct vdo_slab *slab)
{
@@ -2375,6 +2385,7 @@ static void load_reference_blocks(struct vdo_slab *slab)
/**
* drain_slab() - Drain all reference count I/O.
+ * @slab: The slab.
*
* Depending upon the type of drain being performed (as recorded in the ref_count's vdo_slab), the
* reference blocks may be loaded from disk or dirty reference blocks may be written out.
@@ -2564,6 +2575,7 @@ static void read_slab_journal_tail(struct vdo_waiter *waiter, void *context)
/**
* load_slab_journal() - Load a slab's journal by reading the journal's tail.
+ * @slab: The slab.
*/
static void load_slab_journal(struct vdo_slab *slab)
{
@@ -2663,11 +2675,7 @@ static void queue_slab(struct vdo_slab *slab)
prioritize_slab(slab);
}
-/**
- * initiate_slab_action() - Initiate a slab action.
- *
- * Implements vdo_admin_initiator_fn.
- */
+/** Implements vdo_admin_initiator_fn. */
static void initiate_slab_action(struct admin_state *state)
{
struct vdo_slab *slab = container_of(state, struct vdo_slab, state);
@@ -2720,7 +2728,7 @@ static struct vdo_slab *get_next_slab(struct slab_scrubber *scrubber)
* has_slabs_to_scrub() - Check whether a scrubber has slabs to scrub.
* @scrubber: The scrubber to check.
*
- * Return: true if the scrubber has slabs to scrub.
+ * Return: True if the scrubber has slabs to scrub.
*/
static inline bool __must_check has_slabs_to_scrub(struct slab_scrubber *scrubber)
{
@@ -2741,6 +2749,7 @@ static void uninitialize_scrubber_vio(struct slab_scrubber *scrubber)
* finish_scrubbing() - Stop scrubbing, either because there are no more slabs to scrub or because
* there's been an error.
* @scrubber: The scrubber.
+ * @result: The result of the scrubbing operation.
*/
static void finish_scrubbing(struct slab_scrubber *scrubber, int result)
{
@@ -3132,11 +3141,13 @@ static struct vdo_slab *next_slab(struct slab_iterator *iterator)
/**
* abort_waiter() - Abort vios waiting to make journal entries when read-only.
+ * @waiter: A waiting data_vio.
+ * @context: Not used.
*
* This callback is invoked on all vios waiting to make slab journal entries after the VDO has gone
* into read-only mode. Implements waiter_callback_fn.
*/
-static void abort_waiter(struct vdo_waiter *waiter, void *context __always_unused)
+static void abort_waiter(struct vdo_waiter *waiter, void __always_unused *context)
{
struct reference_updater *updater =
container_of(waiter, struct reference_updater, waiter);
@@ -3536,7 +3547,7 @@ static void initiate_load(struct admin_state *state)
/**
* vdo_notify_slab_journals_are_recovered() - Inform a block allocator that its slab journals have
* been recovered from the recovery journal.
- * @completion The allocator completion
+ * @completion: The allocator completion.
*/
void vdo_notify_slab_journals_are_recovered(struct vdo_completion *completion)
{
@@ -3775,7 +3786,7 @@ static int initialize_slab_journal(struct vdo_slab *slab)
* in the slab.
* @allocator: The block allocator to which the slab belongs.
* @slab_number: The slab number of the slab.
- * @is_new: true if this slab is being allocated as part of a resize.
+ * @is_new: True if this slab is being allocated as part of a resize.
* @slab_ptr: A pointer to receive the new slab.
*
* Return: VDO_SUCCESS or an error code.
@@ -3894,11 +3905,7 @@ void vdo_abandon_new_slabs(struct slab_depot *depot)
vdo_free(vdo_forget(depot->new_slabs));
}
-/**
- * get_allocator_thread_id() - Get the ID of the thread on which a given allocator operates.
- *
- * Implements vdo_zone_thread_getter_fn.
- */
+/** Implements vdo_zone_thread_getter_fn. */
static thread_id_t get_allocator_thread_id(void *context, zone_count_t zone_number)
{
return ((struct slab_depot *) context)->allocators[zone_number].thread_id;
@@ -3911,7 +3918,7 @@ static thread_id_t get_allocator_thread_id(void *context, zone_count_t zone_numb
* @recovery_lock: The sequence number of the recovery journal block whose locks should be
* released.
*
- * Return: true if the journal does hold a lock on the specified block (which it will release).
+ * Return: True if the journal released a lock on the specified block.
*/
static bool __must_check release_recovery_journal_lock(struct slab_journal *journal,
sequence_number_t recovery_lock)
@@ -3955,6 +3962,8 @@ static void release_tail_block_locks(void *context, zone_count_t zone_number,
/**
* prepare_for_tail_block_commit() - Prepare to commit oldest tail blocks.
+ * @context: The slab depot.
+ * @parent: The parent operation.
*
* Implements vdo_action_preamble_fn.
*/
@@ -3968,6 +3977,7 @@ static void prepare_for_tail_block_commit(void *context, struct vdo_completion *
/**
* schedule_tail_block_commit() - Schedule a tail block commit if necessary.
+ * @context: The slab depot.
*
* This method should not be called directly. Rather, call vdo_schedule_default_action() on the
* depot's action manager.
@@ -4361,6 +4371,7 @@ struct slab_depot_state_2_0 vdo_record_slab_depot(const struct slab_depot *depot
/**
* vdo_allocate_reference_counters() - Allocate the reference counters for all slabs in the depot.
+ * @depot: The slab depot.
*
* Context: This method may be called only before entering normal operation from the load thread.
*
@@ -4615,7 +4626,9 @@ static void load_summary_endio(struct bio *bio)
}
/**
- * load_slab_summary() - The preamble of a load operation.
+ * load_slab_summary() - Load the slab summary before the slab data.
+ * @context: The slab depot.
+ * @parent: The load operation.
*
* Implements vdo_action_preamble_fn.
*/
@@ -4731,7 +4744,7 @@ void vdo_update_slab_depot_size(struct slab_depot *depot)
* vdo_prepare_to_grow_slab_depot() - Allocate new memory needed for a resize of a slab depot to
* the given size.
* @depot: The depot to prepare to resize.
- * @partition: The new depot partition
+ * @partition: The new depot partition.
*
* Return: VDO_SUCCESS or an error.
*/
@@ -4781,6 +4794,7 @@ int vdo_prepare_to_grow_slab_depot(struct slab_depot *depot,
/**
* finish_registration() - Finish registering new slabs now that all of the allocators have
* received their new slabs.
+ * @context: The slab depot.
*
* Implements vdo_action_conclusion_fn.
*/
diff --git a/drivers/md/dm-vdo/vdo.c b/drivers/md/dm-vdo/vdo.c
index 80b608674022..09fd0628d18c 100644
--- a/drivers/md/dm-vdo/vdo.c
+++ b/drivers/md/dm-vdo/vdo.c
@@ -181,6 +181,8 @@ static void assign_thread_ids(struct thread_config *config,
/**
* initialize_thread_config() - Initialize the thread mapping
+ * @counts: The number and types of threads to create.
+ * @config: The thread_config to initialize.
*
* If the logical, physical, and hash zone counts are all 0, a single thread will be shared by all
* three plus the packer and recovery journal. Otherwise, there must be at least one of each type,
@@ -884,6 +886,7 @@ const struct admin_state_code *vdo_get_admin_state(const struct vdo *vdo)
/**
* record_vdo() - Record the state of the VDO for encoding in the super block.
+ * @vdo: The vdo.
*/
static void record_vdo(struct vdo *vdo)
{
@@ -1277,7 +1280,7 @@ void vdo_enter_read_only_mode(struct vdo *vdo, int error_code)
* vdo_is_read_only() - Check whether the VDO is read-only.
* @vdo: The vdo.
*
- * Return: true if the vdo is read-only.
+ * Return: True if the vdo is read-only.
*
* This method may be called from any thread, as opposed to examining the VDO's state field which
* is only safe to check from the admin thread.
@@ -1291,7 +1294,7 @@ bool vdo_is_read_only(struct vdo *vdo)
* vdo_in_read_only_mode() - Check whether a vdo is in read-only mode.
* @vdo: The vdo to query.
*
- * Return: true if the vdo is in read-only mode.
+ * Return: True if the vdo is in read-only mode.
*/
bool vdo_in_read_only_mode(const struct vdo *vdo)
{
@@ -1302,7 +1305,7 @@ bool vdo_in_read_only_mode(const struct vdo *vdo)
* vdo_in_recovery_mode() - Check whether the vdo is in recovery mode.
* @vdo: The vdo to query.
*
- * Return: true if the vdo is in recovery mode.
+ * Return: True if the vdo is in recovery mode.
*/
bool vdo_in_recovery_mode(const struct vdo *vdo)
{
diff --git a/drivers/md/dm-vdo/vdo.h b/drivers/md/dm-vdo/vdo.h
index 483ae873e002..1aaba73997b7 100644
--- a/drivers/md/dm-vdo/vdo.h
+++ b/drivers/md/dm-vdo/vdo.h
@@ -279,8 +279,10 @@ static inline bool vdo_uses_bio_ack_queue(struct vdo *vdo)
/**
* typedef vdo_filter_fn - Method type for vdo matching methods.
+ * @vdo: The vdo to match.
+ * @context: A parameter for the filter to use.
*
- * A filter function returns false if the vdo doesn't match.
+ * Return: True if the vdo matches the filter criteria, false if it doesn't.
*/
typedef bool (*vdo_filter_fn)(struct vdo *vdo, const void *context);
diff --git a/drivers/md/dm-vdo/vio.c b/drivers/md/dm-vdo/vio.c
index 8fc22fb14196..5ffc867d9c5e 100644
--- a/drivers/md/dm-vdo/vio.c
+++ b/drivers/md/dm-vdo/vio.c
@@ -398,8 +398,9 @@ void free_vio_pool(struct vio_pool *pool)
/**
* is_vio_pool_busy() - Check whether an vio pool has outstanding entries.
+ * @pool: The vio pool.
*
- * Return: true if the pool is busy.
+ * Return: True if the pool is busy.
*/
bool is_vio_pool_busy(struct vio_pool *pool)
{
diff --git a/drivers/md/dm-vdo/vio.h b/drivers/md/dm-vdo/vio.h
index 4bfcb21901f1..7a8a6819aec4 100644
--- a/drivers/md/dm-vdo/vio.h
+++ b/drivers/md/dm-vdo/vio.h
@@ -156,8 +156,7 @@ static inline enum vdo_completion_priority get_metadata_priority(struct vio *vio
/**
* continue_vio() - Enqueue a vio to run its next callback.
* @vio: The vio to continue.
- *
- * Return: The result of the current operation.
+ * @result: The result of the current operation.
*/
static inline void continue_vio(struct vio *vio, int result)
{
@@ -172,6 +171,9 @@ void vdo_count_completed_bios(struct bio *bio);
/**
* continue_vio_after_io() - Continue a vio now that its I/O has returned.
+ * @vio: The vio to continue.
+ * @callback: The next operation for this vio.
+ * @thread: Which thread to run the next operation on.
*/
static inline void continue_vio_after_io(struct vio *vio, vdo_action_fn callback,
thread_id_t thread)
diff --git a/drivers/md/dm-verity-fec.c b/drivers/md/dm-verity-fec.c
index 72047b47a7a0..c79de517afee 100644
--- a/drivers/md/dm-verity-fec.c
+++ b/drivers/md/dm-verity-fec.c
@@ -177,9 +177,11 @@ error:
if (r < 0 && neras)
DMERR_LIMIT("%s: FEC %llu: failed to correct: %d",
v->data_dev->name, (unsigned long long)rsb, r);
- else if (r > 0)
+ else if (r > 0) {
DMWARN_LIMIT("%s: FEC %llu: corrected %d errors",
v->data_dev->name, (unsigned long long)rsb, r);
+ atomic64_inc(&v->fec->corrected);
+ }
return r;
}
@@ -188,14 +190,13 @@ error:
* Locate data block erasures using verity hashes.
*/
static int fec_is_erasure(struct dm_verity *v, struct dm_verity_io *io,
- u8 *want_digest, u8 *data)
+ const u8 *want_digest, const u8 *data)
{
if (unlikely(verity_hash(v, io, data, 1 << v->data_dev_block_bits,
- verity_io_real_digest(v, io))))
+ io->tmp_digest)))
return 0;
- return memcmp(verity_io_real_digest(v, io), want_digest,
- v->digest_size) != 0;
+ return memcmp(io->tmp_digest, want_digest, v->digest_size) != 0;
}
/*
@@ -328,7 +329,7 @@ static int fec_alloc_bufs(struct dm_verity *v, struct dm_verity_fec_io *fio)
if (fio->bufs[n])
continue;
- fio->bufs[n] = mempool_alloc(&v->fec->extra_pool, GFP_NOWAIT);
+ fio->bufs[n] = kmem_cache_alloc(v->fec->cache, GFP_NOWAIT);
/* we can manage with even one buffer if necessary */
if (unlikely(!fio->bufs[n]))
break;
@@ -362,7 +363,7 @@ static void fec_init_bufs(struct dm_verity *v, struct dm_verity_fec_io *fio)
*/
static int fec_decode_rsb(struct dm_verity *v, struct dm_verity_io *io,
struct dm_verity_fec_io *fio, u64 rsb, u64 offset,
- bool use_erasures)
+ const u8 *want_digest, bool use_erasures)
{
int r, neras = 0;
unsigned int pos;
@@ -388,12 +389,11 @@ static int fec_decode_rsb(struct dm_verity *v, struct dm_verity_io *io,
/* Always re-validate the corrected block against the expected hash */
r = verity_hash(v, io, fio->output, 1 << v->data_dev_block_bits,
- verity_io_real_digest(v, io));
+ io->tmp_digest);
if (unlikely(r < 0))
return r;
- if (memcmp(verity_io_real_digest(v, io), verity_io_want_digest(v, io),
- v->digest_size)) {
+ if (memcmp(io->tmp_digest, want_digest, v->digest_size)) {
DMERR_LIMIT("%s: FEC %llu: failed to correct (%d erasures)",
v->data_dev->name, (unsigned long long)rsb, neras);
return -EILSEQ;
@@ -404,7 +404,8 @@ static int fec_decode_rsb(struct dm_verity *v, struct dm_verity_io *io,
/* Correct errors in a block. Copies corrected block to dest. */
int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io,
- enum verity_block_type type, sector_t block, u8 *dest)
+ enum verity_block_type type, const u8 *want_digest,
+ sector_t block, u8 *dest)
{
int r;
struct dm_verity_fec_io *fio = fec_io(io);
@@ -413,10 +414,8 @@ int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io,
if (!verity_fec_is_enabled(v))
return -EOPNOTSUPP;
- if (fio->level >= DM_VERITY_FEC_MAX_RECURSION) {
- DMWARN_LIMIT("%s: FEC: recursion too deep", v->data_dev->name);
+ if (fio->level)
return -EIO;
- }
fio->level++;
@@ -447,9 +446,9 @@ int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io,
* them first. Do a second attempt with erasures if the corruption is
* bad enough.
*/
- r = fec_decode_rsb(v, io, fio, rsb, offset, false);
+ r = fec_decode_rsb(v, io, fio, rsb, offset, want_digest, false);
if (r < 0) {
- r = fec_decode_rsb(v, io, fio, rsb, offset, true);
+ r = fec_decode_rsb(v, io, fio, rsb, offset, want_digest, true);
if (r < 0)
goto done;
}
@@ -479,7 +478,8 @@ void verity_fec_finish_io(struct dm_verity_io *io)
mempool_free(fio->bufs[n], &f->prealloc_pool);
fec_for_each_extra_buffer(fio, n)
- mempool_free(fio->bufs[n], &f->extra_pool);
+ if (fio->bufs[n])
+ kmem_cache_free(f->cache, fio->bufs[n]);
mempool_free(fio->output, &f->output_pool);
}
@@ -531,7 +531,6 @@ void verity_fec_dtr(struct dm_verity *v)
mempool_exit(&f->rs_pool);
mempool_exit(&f->prealloc_pool);
- mempool_exit(&f->extra_pool);
mempool_exit(&f->output_pool);
kmem_cache_destroy(f->cache);
@@ -784,12 +783,6 @@ int verity_fec_ctr(struct dm_verity *v)
return ret;
}
- ret = mempool_init_slab_pool(&f->extra_pool, 0, f->cache);
- if (ret) {
- ti->error = "Cannot allocate FEC buffer extra pool";
- return ret;
- }
-
/* Preallocate an output buffer for each thread */
ret = mempool_init_kmalloc_pool(&f->output_pool, num_online_cpus(),
1 << v->data_dev_block_bits);
diff --git a/drivers/md/dm-verity-fec.h b/drivers/md/dm-verity-fec.h
index 09123a612953..5fd267873812 100644
--- a/drivers/md/dm-verity-fec.h
+++ b/drivers/md/dm-verity-fec.h
@@ -23,9 +23,6 @@
#define DM_VERITY_FEC_BUF_MAX \
(1 << (PAGE_SHIFT - DM_VERITY_FEC_BUF_RS_BITS))
-/* maximum recursion level for verity_fec_decode */
-#define DM_VERITY_FEC_MAX_RECURSION 4
-
#define DM_VERITY_OPT_FEC_DEV "use_fec_from_device"
#define DM_VERITY_OPT_FEC_BLOCKS "fec_blocks"
#define DM_VERITY_OPT_FEC_START "fec_start"
@@ -45,9 +42,9 @@ struct dm_verity_fec {
unsigned char rsn; /* N of RS(M, N) */
mempool_t rs_pool; /* mempool for fio->rs */
mempool_t prealloc_pool; /* mempool for preallocated buffers */
- mempool_t extra_pool; /* mempool for extra buffers */
mempool_t output_pool; /* mempool for output */
struct kmem_cache *cache; /* cache for buffers */
+ atomic64_t corrected; /* corrected errors */
};
/* per-bio data */
@@ -68,8 +65,8 @@ struct dm_verity_fec_io {
extern bool verity_fec_is_enabled(struct dm_verity *v);
extern int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io,
- enum verity_block_type type, sector_t block,
- u8 *dest);
+ enum verity_block_type type, const u8 *want_digest,
+ sector_t block, u8 *dest);
extern unsigned int verity_fec_status_table(struct dm_verity *v, unsigned int sz,
char *result, unsigned int maxlen);
@@ -99,6 +96,7 @@ static inline bool verity_fec_is_enabled(struct dm_verity *v)
static inline int verity_fec_decode(struct dm_verity *v,
struct dm_verity_io *io,
enum verity_block_type type,
+ const u8 *want_digest,
sector_t block, u8 *dest)
{
return -EOPNOTSUPP;
diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c
index 66a00a8ccb39..5c17472d7896 100644
--- a/drivers/md/dm-verity-target.c
+++ b/drivers/md/dm-verity-target.c
@@ -117,11 +117,25 @@ static sector_t verity_position_at_level(struct dm_verity *v, sector_t block,
int verity_hash(struct dm_verity *v, struct dm_verity_io *io,
const u8 *data, size_t len, u8 *digest)
{
- struct shash_desc *desc = &io->hash_desc;
+ struct shash_desc *desc;
int r;
+ if (likely(v->use_sha256_lib)) {
+ struct sha256_ctx *ctx = &io->hash_ctx.sha256;
+
+ /*
+ * Fast path using SHA-256 library. This is enabled only for
+ * verity version 1, where the salt is at the beginning.
+ */
+ *ctx = *v->initial_hashstate.sha256;
+ sha256_update(ctx, data, len);
+ sha256_final(ctx, digest);
+ return 0;
+ }
+
+ desc = &io->hash_ctx.shash;
desc->tfm = v->shash_tfm;
- if (unlikely(v->initial_hashstate == NULL)) {
+ if (unlikely(v->initial_hashstate.shash == NULL)) {
/* Version 0: salt at end */
r = crypto_shash_init(desc) ?:
crypto_shash_update(desc, data, len) ?:
@@ -129,7 +143,7 @@ int verity_hash(struct dm_verity *v, struct dm_verity_io *io,
crypto_shash_final(desc, digest);
} else {
/* Version 1: salt at beginning */
- r = crypto_shash_import(desc, v->initial_hashstate) ?:
+ r = crypto_shash_import(desc, v->initial_hashstate.shash) ?:
crypto_shash_finup(desc, data, len, digest);
}
if (unlikely(r))
@@ -215,12 +229,12 @@ out:
* Verify hash of a metadata block pertaining to the specified data block
* ("block" argument) at a specified level ("level" argument).
*
- * On successful return, verity_io_want_digest(v, io) contains the hash value
- * for a lower tree level or for the data block (if we're at the lowest level).
+ * On successful return, want_digest contains the hash value for a lower tree
+ * level or for the data block (if we're at the lowest level).
*
* If "skip_unverified" is true, unverified buffer is skipped and 1 is returned.
* If "skip_unverified" is false, unverified buffer is hashed and verified
- * against current value of verity_io_want_digest(v, io).
+ * against current value of want_digest.
*/
static int verity_verify_level(struct dm_verity *v, struct dm_verity_io *io,
sector_t block, int level, bool skip_unverified,
@@ -259,7 +273,7 @@ static int verity_verify_level(struct dm_verity *v, struct dm_verity_io *io,
if (IS_ERR(data))
return r;
if (verity_fec_decode(v, io, DM_VERITY_BLOCK_TYPE_METADATA,
- hash_block, data) == 0) {
+ want_digest, hash_block, data) == 0) {
aux = dm_bufio_get_aux_data(buf);
aux->hash_verified = 1;
goto release_ok;
@@ -279,11 +293,11 @@ static int verity_verify_level(struct dm_verity *v, struct dm_verity_io *io,
}
r = verity_hash(v, io, data, 1 << v->hash_dev_block_bits,
- verity_io_real_digest(v, io));
+ io->tmp_digest);
if (unlikely(r < 0))
goto release_ret_r;
- if (likely(memcmp(verity_io_real_digest(v, io), want_digest,
+ if (likely(memcmp(io->tmp_digest, want_digest,
v->digest_size) == 0))
aux->hash_verified = 1;
else if (static_branch_unlikely(&use_bh_wq_enabled) && io->in_bh) {
@@ -294,7 +308,7 @@ static int verity_verify_level(struct dm_verity *v, struct dm_verity_io *io,
r = -EAGAIN;
goto release_ret_r;
} else if (verity_fec_decode(v, io, DM_VERITY_BLOCK_TYPE_METADATA,
- hash_block, data) == 0)
+ want_digest, hash_block, data) == 0)
aux->hash_verified = 1;
else if (verity_handle_err(v,
DM_VERITY_BLOCK_TYPE_METADATA,
@@ -358,7 +372,8 @@ out:
}
static noinline int verity_recheck(struct dm_verity *v, struct dm_verity_io *io,
- sector_t cur_block, u8 *dest)
+ const u8 *want_digest, sector_t cur_block,
+ u8 *dest)
{
struct page *page;
void *buffer;
@@ -382,12 +397,11 @@ static noinline int verity_recheck(struct dm_verity *v, struct dm_verity_io *io,
goto free_ret;
r = verity_hash(v, io, buffer, 1 << v->data_dev_block_bits,
- verity_io_real_digest(v, io));
+ io->tmp_digest);
if (unlikely(r))
goto free_ret;
- if (memcmp(verity_io_real_digest(v, io),
- verity_io_want_digest(v, io), v->digest_size)) {
+ if (memcmp(io->tmp_digest, want_digest, v->digest_size)) {
r = -EIO;
goto free_ret;
}
@@ -402,9 +416,13 @@ free_ret:
static int verity_handle_data_hash_mismatch(struct dm_verity *v,
struct dm_verity_io *io,
- struct bio *bio, sector_t blkno,
- u8 *data)
+ struct bio *bio,
+ struct pending_block *block)
{
+ const u8 *want_digest = block->want_digest;
+ sector_t blkno = block->blkno;
+ u8 *data = block->data;
+
if (static_branch_unlikely(&use_bh_wq_enabled) && io->in_bh) {
/*
* Error handling code (FEC included) cannot be run in the
@@ -412,14 +430,14 @@ static int verity_handle_data_hash_mismatch(struct dm_verity *v,
*/
return -EAGAIN;
}
- if (verity_recheck(v, io, blkno, data) == 0) {
+ if (verity_recheck(v, io, want_digest, blkno, data) == 0) {
if (v->validated_blocks)
set_bit(blkno, v->validated_blocks);
return 0;
}
#if defined(CONFIG_DM_VERITY_FEC)
- if (verity_fec_decode(v, io, DM_VERITY_BLOCK_TYPE_DATA, blkno,
- data) == 0)
+ if (verity_fec_decode(v, io, DM_VERITY_BLOCK_TYPE_DATA, want_digest,
+ blkno, data) == 0)
return 0;
#endif
if (bio->bi_status)
@@ -433,6 +451,58 @@ static int verity_handle_data_hash_mismatch(struct dm_verity *v,
return 0;
}
+static void verity_clear_pending_blocks(struct dm_verity_io *io)
+{
+ int i;
+
+ for (i = io->num_pending - 1; i >= 0; i--) {
+ kunmap_local(io->pending_blocks[i].data);
+ io->pending_blocks[i].data = NULL;
+ }
+ io->num_pending = 0;
+}
+
+static int verity_verify_pending_blocks(struct dm_verity *v,
+ struct dm_verity_io *io,
+ struct bio *bio)
+{
+ const unsigned int block_size = 1 << v->data_dev_block_bits;
+ int i, r;
+
+ if (io->num_pending == 2) {
+ /* num_pending == 2 implies that the algorithm is SHA-256 */
+ sha256_finup_2x(v->initial_hashstate.sha256,
+ io->pending_blocks[0].data,
+ io->pending_blocks[1].data, block_size,
+ io->pending_blocks[0].real_digest,
+ io->pending_blocks[1].real_digest);
+ } else {
+ for (i = 0; i < io->num_pending; i++) {
+ r = verity_hash(v, io, io->pending_blocks[i].data,
+ block_size,
+ io->pending_blocks[i].real_digest);
+ if (unlikely(r))
+ return r;
+ }
+ }
+
+ for (i = 0; i < io->num_pending; i++) {
+ struct pending_block *block = &io->pending_blocks[i];
+
+ if (likely(memcmp(block->real_digest, block->want_digest,
+ v->digest_size) == 0)) {
+ if (v->validated_blocks)
+ set_bit(block->blkno, v->validated_blocks);
+ } else {
+ r = verity_handle_data_hash_mismatch(v, io, bio, block);
+ if (unlikely(r))
+ return r;
+ }
+ }
+ verity_clear_pending_blocks(io);
+ return 0;
+}
+
/*
* Verify one "dm_verity_io" structure.
*/
@@ -440,10 +510,14 @@ static int verity_verify_io(struct dm_verity_io *io)
{
struct dm_verity *v = io->v;
const unsigned int block_size = 1 << v->data_dev_block_bits;
+ const int max_pending = v->use_sha256_finup_2x ? 2 : 1;
struct bvec_iter iter_copy;
struct bvec_iter *iter;
struct bio *bio = dm_bio_from_per_bio_data(io, v->ti->per_io_data_size);
unsigned int b;
+ int r;
+
+ io->num_pending = 0;
if (static_branch_unlikely(&use_bh_wq_enabled) && io->in_bh) {
/*
@@ -457,21 +531,22 @@ static int verity_verify_io(struct dm_verity_io *io)
for (b = 0; b < io->n_blocks;
b++, bio_advance_iter(bio, iter, block_size)) {
- int r;
- sector_t cur_block = io->block + b;
+ sector_t blkno = io->block + b;
+ struct pending_block *block;
bool is_zero;
struct bio_vec bv;
void *data;
if (v->validated_blocks && bio->bi_status == BLK_STS_OK &&
- likely(test_bit(cur_block, v->validated_blocks)))
+ likely(test_bit(blkno, v->validated_blocks)))
continue;
- r = verity_hash_for_block(v, io, cur_block,
- verity_io_want_digest(v, io),
+ block = &io->pending_blocks[io->num_pending];
+
+ r = verity_hash_for_block(v, io, blkno, block->want_digest,
&is_zero);
if (unlikely(r < 0))
- return r;
+ goto error;
bv = bio_iter_iovec(bio, *iter);
if (unlikely(bv.bv_len < block_size)) {
@@ -482,7 +557,8 @@ static int verity_verify_io(struct dm_verity_io *io)
* data block size to be greater than PAGE_SIZE.
*/
DMERR_LIMIT("unaligned io (data block spans pages)");
- return -EIO;
+ r = -EIO;
+ goto error;
}
data = bvec_kmap_local(&bv);
@@ -496,29 +572,26 @@ static int verity_verify_io(struct dm_verity_io *io)
kunmap_local(data);
continue;
}
-
- r = verity_hash(v, io, data, block_size,
- verity_io_real_digest(v, io));
- if (unlikely(r < 0)) {
- kunmap_local(data);
- return r;
+ block->data = data;
+ block->blkno = blkno;
+ if (++io->num_pending == max_pending) {
+ r = verity_verify_pending_blocks(v, io, bio);
+ if (unlikely(r))
+ goto error;
}
+ }
- if (likely(memcmp(verity_io_real_digest(v, io),
- verity_io_want_digest(v, io), v->digest_size) == 0)) {
- if (v->validated_blocks)
- set_bit(cur_block, v->validated_blocks);
- kunmap_local(data);
- continue;
- }
- r = verity_handle_data_hash_mismatch(v, io, bio, cur_block,
- data);
- kunmap_local(data);
+ if (io->num_pending) {
+ r = verity_verify_pending_blocks(v, io, bio);
if (unlikely(r))
- return r;
+ goto error;
}
return 0;
+
+error:
+ verity_clear_pending_blocks(io);
+ return r;
}
/*
@@ -775,6 +848,10 @@ static void verity_status(struct dm_target *ti, status_type_t type,
switch (type) {
case STATUSTYPE_INFO:
DMEMIT("%c", v->hash_failed ? 'C' : 'V');
+ if (verity_fec_is_enabled(v))
+ DMEMIT(" %lld", atomic64_read(&v->fec->corrected));
+ else
+ DMEMIT(" -");
break;
case STATUSTYPE_TABLE:
DMEMIT("%u %s %s %u %u %llu %llu %s ",
@@ -1004,7 +1081,7 @@ static void verity_dtr(struct dm_target *ti)
kvfree(v->validated_blocks);
kfree(v->salt);
- kfree(v->initial_hashstate);
+ kfree(v->initial_hashstate.shash);
kfree(v->root_digest);
kfree(v->zero_digest);
verity_free_sig(v);
@@ -1069,8 +1146,7 @@ static int verity_alloc_zero_digest(struct dm_verity *v)
if (!v->zero_digest)
return r;
- io = kmalloc(sizeof(*io) + crypto_shash_descsize(v->shash_tfm),
- GFP_KERNEL);
+ io = kmalloc(v->ti->per_io_data_size, GFP_KERNEL);
if (!io)
return r; /* verity_dtr will free zero_digest */
@@ -1252,11 +1328,26 @@ static int verity_setup_hash_alg(struct dm_verity *v, const char *alg_name)
}
v->shash_tfm = shash;
v->digest_size = crypto_shash_digestsize(shash);
- DMINFO("%s using \"%s\"", alg_name, crypto_shash_driver_name(shash));
if ((1 << v->hash_dev_block_bits) < v->digest_size * 2) {
ti->error = "Digest size too big";
return -EINVAL;
}
+ if (likely(v->version && strcmp(alg_name, "sha256") == 0)) {
+ /*
+ * Fast path: use the library API for reduced overhead and
+ * interleaved hashing support.
+ */
+ v->use_sha256_lib = true;
+ if (sha256_finup_2x_is_optimized())
+ v->use_sha256_finup_2x = true;
+ ti->per_io_data_size =
+ offsetofend(struct dm_verity_io, hash_ctx.sha256);
+ } else {
+ /* Fallback case: use the generic crypto API. */
+ ti->per_io_data_size =
+ offsetofend(struct dm_verity_io, hash_ctx.shash) +
+ crypto_shash_descsize(shash);
+ }
return 0;
}
@@ -1277,7 +1368,18 @@ static int verity_setup_salt_and_hashstate(struct dm_verity *v, const char *arg)
return -EINVAL;
}
}
- if (v->version) { /* Version 1: salt at beginning */
+ if (likely(v->use_sha256_lib)) {
+ /* Implies version 1: salt at beginning */
+ v->initial_hashstate.sha256 =
+ kmalloc(sizeof(struct sha256_ctx), GFP_KERNEL);
+ if (!v->initial_hashstate.sha256) {
+ ti->error = "Cannot allocate initial hash state";
+ return -ENOMEM;
+ }
+ sha256_init(v->initial_hashstate.sha256);
+ sha256_update(v->initial_hashstate.sha256,
+ v->salt, v->salt_size);
+ } else if (v->version) { /* Version 1: salt at beginning */
SHASH_DESC_ON_STACK(desc, v->shash_tfm);
int r;
@@ -1285,16 +1387,16 @@ static int verity_setup_salt_and_hashstate(struct dm_verity *v, const char *arg)
* Compute the pre-salted hash state that can be passed to
* crypto_shash_import() for each block later.
*/
- v->initial_hashstate = kmalloc(
+ v->initial_hashstate.shash = kmalloc(
crypto_shash_statesize(v->shash_tfm), GFP_KERNEL);
- if (!v->initial_hashstate) {
+ if (!v->initial_hashstate.shash) {
ti->error = "Cannot allocate initial hash state";
return -ENOMEM;
}
desc->tfm = v->shash_tfm;
r = crypto_shash_init(desc) ?:
crypto_shash_update(desc, v->salt, v->salt_size) ?:
- crypto_shash_export(desc, v->initial_hashstate);
+ crypto_shash_export(desc, v->initial_hashstate.shash);
if (r) {
ti->error = "Cannot set up initial hash state";
return r;
@@ -1556,9 +1658,6 @@ static int verity_ctr(struct dm_target *ti, unsigned int argc, char **argv)
goto bad;
}
- ti->per_io_data_size = sizeof(struct dm_verity_io) +
- crypto_shash_descsize(v->shash_tfm);
-
r = verity_fec_ctr(v);
if (r)
goto bad;
@@ -1690,7 +1789,7 @@ static struct target_type verity_target = {
.name = "verity",
/* Note: the LSMs depend on the singleton and immutable features */
.features = DM_TARGET_SINGLETON | DM_TARGET_IMMUTABLE,
- .version = {1, 12, 0},
+ .version = {1, 13, 0},
.module = THIS_MODULE,
.ctr = verity_ctr,
.dtr = verity_dtr,
diff --git a/drivers/md/dm-verity.h b/drivers/md/dm-verity.h
index 6d141abd965c..f975a9e5c5d6 100644
--- a/drivers/md/dm-verity.h
+++ b/drivers/md/dm-verity.h
@@ -16,6 +16,7 @@
#include <linux/device-mapper.h>
#include <linux/interrupt.h>
#include <crypto/hash.h>
+#include <crypto/sha2.h>
#define DM_VERITY_MAX_LEVELS 63
@@ -42,7 +43,10 @@ struct dm_verity {
struct crypto_shash *shash_tfm;
u8 *root_digest; /* digest of the root block */
u8 *salt; /* salt: its size is salt_size */
- u8 *initial_hashstate; /* salted initial state, if version >= 1 */
+ union {
+ struct sha256_ctx *sha256; /* for use_sha256_lib=1 */
+ u8 *shash; /* for use_sha256_lib=0 */
+ } initial_hashstate; /* salted initial state, if version >= 1 */
u8 *zero_digest; /* digest for a zero block */
#ifdef CONFIG_SECURITY
u8 *root_digest_sig; /* signature of the root digest */
@@ -59,6 +63,8 @@ struct dm_verity {
unsigned char version;
bool hash_failed:1; /* set if hash of any block failed */
bool use_bh_wq:1; /* try to verify in BH wq before normal work-queue */
+ bool use_sha256_lib:1; /* use SHA-256 library instead of generic crypto API */
+ bool use_sha256_finup_2x:1; /* use interleaved hashing optimization */
unsigned int digest_size; /* digest size for the current hash algorithm */
enum verity_mode mode; /* mode for handling verification errors */
enum verity_mode error_mode;/* mode for handling I/O errors */
@@ -78,6 +84,13 @@ struct dm_verity {
mempool_t recheck_pool;
};
+struct pending_block {
+ void *data;
+ sector_t blkno;
+ u8 want_digest[HASH_MAX_DIGESTSIZE];
+ u8 real_digest[HASH_MAX_DIGESTSIZE];
+};
+
struct dm_verity_io {
struct dm_verity *v;
@@ -94,28 +107,29 @@ struct dm_verity_io {
struct work_struct work;
struct work_struct bh_work;
- u8 real_digest[HASH_MAX_DIGESTSIZE];
- u8 want_digest[HASH_MAX_DIGESTSIZE];
+ u8 tmp_digest[HASH_MAX_DIGESTSIZE];
/*
- * Temporary space for hashing. This is variable-length and must be at
- * the end of the struct. struct shash_desc is just the fixed part;
- * it's followed by a context of size crypto_shash_descsize(shash_tfm).
+ * This is the queue of data blocks that are pending verification. When
+ * the crypto layer supports interleaved hashing, we allow multiple
+ * blocks to be queued up in order to utilize it. This can improve
+ * performance significantly vs. sequential hashing of each block.
*/
- struct shash_desc hash_desc;
-};
+ int num_pending;
+ struct pending_block pending_blocks[2];
-static inline u8 *verity_io_real_digest(struct dm_verity *v,
- struct dm_verity_io *io)
-{
- return io->real_digest;
-}
-
-static inline u8 *verity_io_want_digest(struct dm_verity *v,
- struct dm_verity_io *io)
-{
- return io->want_digest;
-}
+ /*
+ * Temporary space for hashing. Either sha256 or shash is used,
+ * depending on the value of use_sha256_lib. If shash is used,
+ * then this field is variable-length, with total size
+ * sizeof(struct shash_desc) + crypto_shash_descsize(shash_tfm).
+ * For this reason, this field must be the end of the struct.
+ */
+ union {
+ struct sha256_ctx sha256;
+ struct shash_desc shash;
+ } hash_ctx;
+};
extern int verity_hash(struct dm_verity *v, struct dm_verity_io *io,
const u8 *data, size_t len, u8 *digest);
diff --git a/drivers/md/dm-zone.c b/drivers/md/dm-zone.c
index 5a840c4ae316..c95e417194b3 100644
--- a/drivers/md/dm-zone.c
+++ b/drivers/md/dm-zone.c
@@ -203,8 +203,6 @@ int dm_revalidate_zones(struct dm_table *t, struct request_queue *q)
return ret;
}
- md->nr_zones = disk->nr_zones;
-
return 0;
}
@@ -452,7 +450,6 @@ void dm_finalize_zone_settings(struct dm_table *t, struct queue_limits *lim)
set_bit(DMF_EMULATE_ZONE_APPEND, &md->flags);
} else {
clear_bit(DMF_EMULATE_ZONE_APPEND, &md->flags);
- md->nr_zones = 0;
md->disk->nr_zones = 0;
}
}
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 6c83ab940af7..b63279202260 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -272,7 +272,7 @@ static int __init dm_init(void)
int r, i;
#if (IS_ENABLED(CONFIG_IMA) && !IS_ENABLED(CONFIG_IMA_DISABLE_HTABLE))
- DMWARN("CONFIG_IMA_DISABLE_HTABLE is disabled."
+ DMINFO("CONFIG_IMA_DISABLE_HTABLE is disabled."
" Duplicate IMA measurements will not be recorded in the IMA log.");
#endif
@@ -1321,6 +1321,7 @@ void dm_accept_partial_bio(struct bio *bio, unsigned int n_sectors)
BUG_ON(dm_tio_flagged(tio, DM_TIO_IS_DUPLICATE_BIO));
BUG_ON(bio_sectors > *tio->len_ptr);
BUG_ON(n_sectors > bio_sectors);
+ BUG_ON(bio->bi_opf & REQ_ATOMIC);
if (static_branch_unlikely(&zoned_enabled) &&
unlikely(bdev_is_zoned(bio->bi_bdev))) {
@@ -1735,8 +1736,12 @@ static blk_status_t __split_and_process_bio(struct clone_info *ci)
ci->submit_as_polled = !!(ci->bio->bi_opf & REQ_POLLED);
len = min_t(sector_t, max_io_len(ti, ci->sector), ci->sector_count);
- if (ci->bio->bi_opf & REQ_ATOMIC && len != ci->sector_count)
- return BLK_STS_IOERR;
+ if (ci->bio->bi_opf & REQ_ATOMIC) {
+ if (unlikely(!dm_target_supports_atomic_writes(ti->type)))
+ return BLK_STS_IOERR;
+ if (unlikely(len != ci->sector_count))
+ return BLK_STS_IOERR;
+ }
setup_split_accounting(ci, len);
@@ -2439,7 +2444,6 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t,
{
struct dm_table *old_map;
sector_t size, old_size;
- int ret;
lockdep_assert_held(&md->suspend_lock);
@@ -2454,11 +2458,13 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t,
set_capacity(md->disk, size);
- ret = dm_table_set_restrictions(t, md->queue, limits);
- if (ret) {
- set_capacity(md->disk, old_size);
- old_map = ERR_PTR(ret);
- goto out;
+ if (limits) {
+ int ret = dm_table_set_restrictions(t, md->queue, limits);
+ if (ret) {
+ set_capacity(md->disk, old_size);
+ old_map = ERR_PTR(ret);
+ goto out;
+ }
}
/*
@@ -2836,6 +2842,7 @@ static void dm_wq_work(struct work_struct *work)
static void dm_queue_flush(struct mapped_device *md)
{
+ clear_bit(DMF_NOFLUSH_SUSPENDING, &md->flags);
clear_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags);
smp_mb__after_atomic();
queue_work(md->wq, &md->work);
@@ -2848,6 +2855,7 @@ struct dm_table *dm_swap_table(struct mapped_device *md, struct dm_table *table)
{
struct dm_table *live_map = NULL, *map = ERR_PTR(-EINVAL);
struct queue_limits limits;
+ bool update_limits = true;
int r;
mutex_lock(&md->suspend_lock);
@@ -2857,19 +2865,30 @@ struct dm_table *dm_swap_table(struct mapped_device *md, struct dm_table *table)
goto out;
/*
+ * To avoid a potential deadlock locking the queue limits, disallow
+ * updating the queue limits during a table swap, when updating an
+ * immutable request-based dm device (dm-multipath) during a noflush
+ * suspend. It is userspace's responsibility to make sure that the new
+ * table uses the same limits as the existing table, if it asks for a
+ * noflush suspend.
+ */
+ if (dm_request_based(md) && md->immutable_target &&
+ __noflush_suspending(md))
+ update_limits = false;
+ /*
* If the new table has no data devices, retain the existing limits.
* This helps multipath with queue_if_no_path if all paths disappear,
* then new I/O is queued based on these limits, and then some paths
* reappear.
*/
- if (dm_table_has_no_data_devices(table)) {
+ else if (dm_table_has_no_data_devices(table)) {
live_map = dm_get_live_table_fast(md);
if (live_map)
limits = md->queue->limits;
dm_put_live_table_fast(md);
}
- if (!live_map) {
+ if (update_limits && !live_map) {
r = dm_calculate_queue_limits(table, &limits);
if (r) {
map = ERR_PTR(r);
@@ -2877,7 +2896,7 @@ struct dm_table *dm_swap_table(struct mapped_device *md, struct dm_table *table)
}
}
- map = __bind(md, table, &limits);
+ map = __bind(md, table, update_limits ? &limits : NULL);
dm_issue_global_event();
out:
@@ -2930,7 +2949,6 @@ static int __dm_suspend(struct mapped_device *md, struct dm_table *map,
/*
* DMF_NOFLUSH_SUSPENDING must be set before presuspend.
- * This flag is cleared before dm_suspend returns.
*/
if (noflush)
set_bit(DMF_NOFLUSH_SUSPENDING, &md->flags);
@@ -2993,8 +3011,6 @@ static int __dm_suspend(struct mapped_device *md, struct dm_table *map,
if (!r)
set_bit(dmf_suspended_flag, &md->flags);
- if (noflush)
- clear_bit(DMF_NOFLUSH_SUSPENDING, &md->flags);
if (map)
synchronize_srcu(&md->io_barrier);
diff --git a/drivers/of/property.c b/drivers/of/property.c
index c1feb631e383..4e3524227720 100644
--- a/drivers/of/property.c
+++ b/drivers/of/property.c
@@ -148,6 +148,39 @@ static void *of_find_property_value_of_size(const struct device_node *np,
}
/**
+ * of_property_read_u8_index - Find and read a u8 from a multi-value property.
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @index: index of the u8 in the list of values
+ * @out_value: pointer to return value, modified only if no error.
+ *
+ * Search for a property in a device node and read nth 8-bit value from
+ * it.
+ *
+ * Return: 0 on success, -EINVAL if the property does not exist,
+ * -ENODATA if property does not have a value, and -EOVERFLOW if the
+ * property data isn't large enough.
+ *
+ * The out_value is modified only if a valid u8 value can be decoded.
+ */
+int of_property_read_u8_index(const struct device_node *np,
+ const char *propname,
+ u32 index, u8 *out_value)
+{
+ const u8 *val = of_find_property_value_of_size(np, propname,
+ ((index + 1) * sizeof(*out_value)),
+ 0, NULL);
+
+ if (IS_ERR(val))
+ return PTR_ERR(val);
+
+ *out_value = val[index];
+ return 0;
+}
+EXPORT_SYMBOL_GPL(of_property_read_u8_index);
+
+/**
* of_property_read_u16_index - Find and read a u16 from a multi-value property.
*
* @np: device node from which the property value is to be read.
diff --git a/drivers/pci/controller/pcie-rzg3s-host.c b/drivers/pci/controller/pcie-rzg3s-host.c
index 667e6d629474..83ec66a70823 100644
--- a/drivers/pci/controller/pcie-rzg3s-host.c
+++ b/drivers/pci/controller/pcie-rzg3s-host.c
@@ -479,7 +479,7 @@ static void rzg3s_pcie_intx_irq_handler(struct irq_desc *desc)
static irqreturn_t rzg3s_pcie_msi_irq(int irq, void *data)
{
u8 regs = RZG3S_PCI_MSI_INT_NR / RZG3S_PCI_MSI_INT_PER_REG;
- DECLARE_BITMAP(bitmap, RZG3S_PCI_MSI_INT_NR);
+ DECLARE_BITMAP(bitmap, RZG3S_PCI_MSI_INT_NR) = {0};
struct rzg3s_pcie_host *host = data;
struct rzg3s_pcie_msi *msi = &host->msi;
unsigned long bit;
diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig
index 324c69c63f76..312788f249c9 100644
--- a/drivers/platform/Kconfig
+++ b/drivers/platform/Kconfig
@@ -20,3 +20,5 @@ source "drivers/platform/x86/Kconfig"
source "drivers/platform/arm64/Kconfig"
source "drivers/platform/raspberrypi/Kconfig"
+
+source "drivers/platform/wmi/Kconfig"
diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile
index b0935c602ada..fa322e7f8716 100644
--- a/drivers/platform/Makefile
+++ b/drivers/platform/Makefile
@@ -14,3 +14,4 @@ obj-$(CONFIG_CZNIC_PLATFORMS) += cznic/
obj-$(CONFIG_SURFACE_PLATFORMS) += surface/
obj-$(CONFIG_ARM64_PLATFORM_DEVICES) += arm64/
obj-$(CONFIG_BCM2835_VCHIQ) += raspberrypi/
+obj-$(CONFIG_ACPI_WMI) += wmi/
diff --git a/drivers/platform/arm64/lenovo-thinkpad-t14s.c b/drivers/platform/arm64/lenovo-thinkpad-t14s.c
index cf6a1d3b2617..5590302a5694 100644
--- a/drivers/platform/arm64/lenovo-thinkpad-t14s.c
+++ b/drivers/platform/arm64/lenovo-thinkpad-t14s.c
@@ -20,19 +20,23 @@
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/slab.h>
+#include <linux/pm.h>
#define T14S_EC_CMD_ECRD 0x02
#define T14S_EC_CMD_ECWR 0x03
#define T14S_EC_CMD_EVT 0xf0
-#define T14S_EC_REG_LED 0x0c
-#define T14S_EC_REG_KBD_BL1 0x0d
-#define T14S_EC_REG_KBD_BL2 0xe1
-#define T14S_EC_KBD_BL1_MASK GENMASK_U8(7, 6)
-#define T14S_EC_KBD_BL2_MASK GENMASK_U8(3, 2)
-#define T14S_EC_REG_AUD 0x30
-#define T14S_EC_MIC_MUTE_LED BIT(5)
-#define T14S_EC_SPK_MUTE_LED BIT(6)
+#define T14S_EC_REG_LED 0x0c
+#define T14S_EC_REG_KBD_BL1 0x0d
+#define T14S_EC_REG_MODERN_STANDBY 0xe0
+#define T14S_EC_MODERN_STANDBY_ENTRY BIT(1)
+#define T14S_EC_MODERN_STANDBY_EXIT BIT(0)
+#define T14S_EC_REG_KBD_BL2 0xe1
+#define T14S_EC_KBD_BL1_MASK GENMASK_U8(7, 6)
+#define T14S_EC_KBD_BL2_MASK GENMASK_U8(3, 2)
+#define T14S_EC_REG_AUD 0x30
+#define T14S_EC_MIC_MUTE_LED BIT(5)
+#define T14S_EC_SPK_MUTE_LED BIT(6)
#define T14S_EC_EVT_NONE 0x00
#define T14S_EC_EVT_KEY_FN_4 0x13
@@ -202,6 +206,14 @@ out:
return ret;
}
+static void t14s_ec_write_sequence(struct t14s_ec *ec, u8 reg, u8 val, u8 cnt)
+{
+ int i;
+
+ for (i = 0; i < cnt; i++)
+ regmap_write(ec->regmap, reg, val);
+}
+
static int t14s_led_set_status(struct t14s_ec *ec,
struct t14s_ec_led_classdev *led,
const enum t14s_ec_led_status_t ledstatus)
@@ -554,6 +566,7 @@ static int t14s_ec_probe(struct i2c_client *client)
return -ENOMEM;
ec->dev = dev;
+ i2c_set_clientdata(client, ec);
ec->regmap = devm_regmap_init(dev, &t14s_ec_regmap_bus,
ec, &t14s_ec_regmap_config);
@@ -593,6 +606,30 @@ static int t14s_ec_probe(struct i2c_client *client)
return 0;
}
+static int t14s_ec_suspend(struct device *dev)
+{
+ struct t14s_ec *ec = dev_get_drvdata(dev);
+
+ led_classdev_suspend(&ec->kbd_backlight);
+
+ t14s_ec_write_sequence(ec, T14S_EC_REG_MODERN_STANDBY,
+ T14S_EC_MODERN_STANDBY_ENTRY, 3);
+
+ return 0;
+}
+
+static int t14s_ec_resume(struct device *dev)
+{
+ struct t14s_ec *ec = dev_get_drvdata(dev);
+
+ t14s_ec_write_sequence(ec, T14S_EC_REG_MODERN_STANDBY,
+ T14S_EC_MODERN_STANDBY_EXIT, 3);
+
+ led_classdev_resume(&ec->kbd_backlight);
+
+ return 0;
+}
+
static const struct of_device_id t14s_ec_of_match[] = {
{ .compatible = "lenovo,thinkpad-t14s-ec" },
{}
@@ -605,10 +642,15 @@ static const struct i2c_device_id t14s_ec_i2c_id_table[] = {
};
MODULE_DEVICE_TABLE(i2c, t14s_ec_i2c_id_table);
+static const struct dev_pm_ops t14s_ec_pm_ops = {
+ SYSTEM_SLEEP_PM_OPS(t14s_ec_suspend, t14s_ec_resume)
+};
+
static struct i2c_driver t14s_ec_i2c_driver = {
.driver = {
.name = "thinkpad-t14s-ec",
.of_match_table = t14s_ec_of_match,
+ .pm = &t14s_ec_pm_ops,
},
.probe = t14s_ec_probe,
.id_table = t14s_ec_i2c_id_table,
diff --git a/drivers/platform/surface/aggregator/core.c b/drivers/platform/surface/aggregator/core.c
index c58e1fdd1a5f..c7e05f7bc199 100644
--- a/drivers/platform/surface/aggregator/core.c
+++ b/drivers/platform/surface/aggregator/core.c
@@ -676,7 +676,7 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev)
status = ssam_serdev_setup(ssh, serdev);
if (status) {
- status = dev_err_probe(dev, status, "failed to setup serdev\n");
+ dev_err_probe(dev, status, "failed to setup serdev\n");
goto err_devinit;
}
diff --git a/drivers/platform/surface/aggregator/ssh_packet_layer.c b/drivers/platform/surface/aggregator/ssh_packet_layer.c
index 6081b0146d5f..3dd22856570f 100644
--- a/drivers/platform/surface/aggregator/ssh_packet_layer.c
+++ b/drivers/platform/surface/aggregator/ssh_packet_layer.c
@@ -671,7 +671,7 @@ static void ssh_ptl_timeout_reaper_mod(struct ssh_ptl *ptl, ktime_t now,
/* Re-adjust / schedule reaper only if it is above resolution delta. */
if (ktime_before(aexp, ptl->rtx_timeout.expires)) {
ptl->rtx_timeout.expires = expires;
- mod_delayed_work(system_wq, &ptl->rtx_timeout.reaper, delta);
+ mod_delayed_work(system_percpu_wq, &ptl->rtx_timeout.reaper, delta);
}
spin_unlock(&ptl->rtx_timeout.lock);
diff --git a/drivers/platform/surface/aggregator/ssh_request_layer.c b/drivers/platform/surface/aggregator/ssh_request_layer.c
index 879ca9ee7ff6..a356e4956562 100644
--- a/drivers/platform/surface/aggregator/ssh_request_layer.c
+++ b/drivers/platform/surface/aggregator/ssh_request_layer.c
@@ -434,7 +434,7 @@ static void ssh_rtl_timeout_reaper_mod(struct ssh_rtl *rtl, ktime_t now,
/* Re-adjust / schedule reaper only if it is above resolution delta. */
if (ktime_before(aexp, rtl->rtx_timeout.expires)) {
rtl->rtx_timeout.expires = expires;
- mod_delayed_work(system_wq, &rtl->rtx_timeout.reaper, delta);
+ mod_delayed_work(system_percpu_wq, &rtl->rtx_timeout.reaper, delta);
}
spin_unlock(&rtl->rtx_timeout.lock);
diff --git a/drivers/platform/surface/surface_acpi_notify.c b/drivers/platform/surface/surface_acpi_notify.c
index 3b30cfe3466b..a9dcb0bbe90e 100644
--- a/drivers/platform/surface/surface_acpi_notify.c
+++ b/drivers/platform/surface/surface_acpi_notify.c
@@ -862,7 +862,7 @@ static int __init san_init(void)
{
int ret;
- san_wq = alloc_workqueue("san_wq", 0, 0);
+ san_wq = alloc_workqueue("san_wq", WQ_PERCPU, 0);
if (!san_wq)
return -ENOMEM;
ret = platform_driver_register(&surface_acpi_notify);
diff --git a/drivers/platform/wmi/Kconfig b/drivers/platform/wmi/Kconfig
new file mode 100644
index 000000000000..77fcbb18746b
--- /dev/null
+++ b/drivers/platform/wmi/Kconfig
@@ -0,0 +1,34 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# ACPI WMI Core
+#
+
+menuconfig ACPI_WMI
+ tristate "ACPI-WMI support"
+ depends on ACPI && X86
+ help
+ This option enables support for the ACPI-WMI driver core.
+
+ The ACPI-WMI interface is a proprietary extension of ACPI allowing
+ the platform firmware to expose WMI (Windows Management Instrumentation)
+ objects used for managing various aspects of the underlying system.
+ Mapping between ACPI control methods and WMI objects happens through
+ special mapper devices (PNP0C14) defined inside the ACPI tables.
+
+ Enabling this option is necessary for building the vendor specific
+ ACPI-WMI client drivers for Acer, Dell an HP machines (among others).
+
+ It is safe to enable this option even for machines that do not contain
+ any ACPI-WMI mapper devices at all.
+
+if ACPI_WMI
+
+config ACPI_WMI_LEGACY_DEVICE_NAMES
+ bool "Use legacy WMI device naming scheme"
+ help
+ Say Y here to force the WMI driver core to use the old WMI device naming
+ scheme when creating WMI devices. Doing so might be necessary for some
+ userspace applications but will cause the registration of WMI devices with
+ the same GUID to fail in some corner cases.
+
+endif # ACPI_WMI
diff --git a/drivers/platform/wmi/Makefile b/drivers/platform/wmi/Makefile
new file mode 100644
index 000000000000..98393d7391ec
--- /dev/null
+++ b/drivers/platform/wmi/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Makefile for linux/drivers/platform/wmi
+# ACPI WMI core
+#
+
+wmi-y := core.o
+obj-$(CONFIG_ACPI_WMI) += wmi.o
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/wmi/core.c
index 4e86a422f05f..6878c4fcb0b5 100644
--- a/drivers/platform/x86/wmi.c
+++ b/drivers/platform/wmi/core.c
@@ -142,14 +142,6 @@ static inline void get_acpi_method_name(const struct wmi_block *wblock,
buffer[4] = '\0';
}
-static inline acpi_object_type get_param_acpi_type(const struct wmi_block *wblock)
-{
- if (wblock->gblock.flags & ACPI_WMI_STRING)
- return ACPI_TYPE_STRING;
- else
- return ACPI_TYPE_BUFFER;
-}
-
static int wmidev_match_guid(struct device *dev, const void *data)
{
struct wmi_block *wblock = dev_to_wblock(dev);
@@ -351,9 +343,16 @@ acpi_status wmidev_evaluate_method(struct wmi_device *wdev, u8 instance, u32 met
params[0].integer.value = instance;
params[1].type = ACPI_TYPE_INTEGER;
params[1].integer.value = method_id;
- params[2].type = get_param_acpi_type(wblock);
- params[2].buffer.length = in->length;
- params[2].buffer.pointer = in->pointer;
+
+ if (wblock->gblock.flags & ACPI_WMI_STRING) {
+ params[2].type = ACPI_TYPE_STRING;
+ params[2].string.length = in->length;
+ params[2].string.pointer = in->pointer;
+ } else {
+ params[2].type = ACPI_TYPE_BUFFER;
+ params[2].buffer.length = in->length;
+ params[2].buffer.pointer = in->pointer;
+ }
get_acpi_method_name(wblock, 'M', method);
@@ -519,9 +518,16 @@ acpi_status wmidev_block_set(struct wmi_device *wdev, u8 instance, const struct
input.pointer = params;
params[0].type = ACPI_TYPE_INTEGER;
params[0].integer.value = instance;
- params[1].type = get_param_acpi_type(wblock);
- params[1].buffer.length = in->length;
- params[1].buffer.pointer = in->pointer;
+
+ if (wblock->gblock.flags & ACPI_WMI_STRING) {
+ params[1].type = ACPI_TYPE_STRING;
+ params[1].string.length = in->length;
+ params[1].string.pointer = in->pointer;
+ } else {
+ params[1].type = ACPI_TYPE_BUFFER;
+ params[1].buffer.length = in->length;
+ params[1].buffer.pointer = in->pointer;
+ }
get_acpi_method_name(wblock, 'S', method);
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index c883a28e0916..4cb7d97a9fcc 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -16,36 +16,6 @@ menuconfig X86_PLATFORM_DEVICES
if X86_PLATFORM_DEVICES
-config ACPI_WMI
- tristate "WMI"
- depends on ACPI
- help
- This driver adds support for the ACPI-WMI (Windows Management
- Instrumentation) mapper device (PNP0C14) found on some systems.
-
- ACPI-WMI is a proprietary extension to ACPI to expose parts of the
- ACPI firmware to userspace - this is done through various vendor
- defined methods and data blocks in a PNP0C14 device, which are then
- made available for userspace to call.
-
- The implementation of this in Linux currently only exposes this to
- other kernel space drivers.
-
- This driver is a required dependency to build the firmware specific
- drivers needed on many machines, including Acer and HP laptops.
-
- It is safe to enable this driver even if your DSDT doesn't define
- any ACPI-WMI devices.
-
-config ACPI_WMI_LEGACY_DEVICE_NAMES
- bool "Use legacy WMI device naming scheme"
- depends on ACPI_WMI
- help
- Say Y here to force the WMI driver core to use the old WMI device naming
- scheme when creating WMI devices. Doing so might be necessary for some
- userspace applications but will cause the registration of WMI devices with
- the same GUID to fail in some corner cases.
-
config WMI_BMOF
tristate "WMI embedded Binary MOF driver"
depends on ACPI_WMI
@@ -74,6 +44,8 @@ config HUAWEI_WMI
To compile this driver as a module, choose M here: the module
will be called huawei-wmi.
+source "drivers/platform/x86/uniwill/Kconfig"
+
config UV_SYSFS
tristate "Sysfs structure for UV systems"
depends on X86_UV
@@ -262,6 +234,18 @@ config ASUS_WIRELESS
If you choose to compile this driver as a module the module will be
called asus-wireless.
+config ASUS_ARMOURY
+ tristate "ASUS Armoury driver"
+ depends on ASUS_WMI
+ select FW_ATTR_CLASS
+ help
+ Say Y here if you have a WMI aware Asus machine and would like to use the
+ firmware_attributes API to control various settings typically exposed in
+ the ASUS Armoury Crate application available on Windows.
+
+ To compile this driver as a module, choose M here: the module will
+ be called asus-armoury.
+
config ASUS_WMI
tristate "ASUS WMI Driver"
depends on ACPI_WMI
@@ -284,6 +268,17 @@ config ASUS_WMI
To compile this driver as a module, choose M here: the module will
be called asus-wmi.
+config ASUS_WMI_DEPRECATED_ATTRS
+ bool "BIOS option support in WMI platform (DEPRECATED)"
+ depends on ASUS_WMI
+ default y
+ help
+ Say Y to expose the configurable BIOS options through the asus-wmi
+ driver.
+
+ This can be used with or without the asus-armoury driver which
+ has the same attributes, but more, and better features.
+
config ASUS_NB_WMI
tristate "Asus Notebook WMI Driver"
depends on ASUS_WMI
@@ -316,6 +311,19 @@ config ASUS_TF103C_DOCK
If you have an Asus TF103C tablet say Y or M here, for a generic x86
distro config say M here.
+config AYANEO_EC
+ tristate "Ayaneo EC platform control"
+ depends on DMI
+ depends on ACPI_EC
+ depends on ACPI_BATTERY
+ depends on HWMON
+ help
+ Enables support for the platform EC of Ayaneo devices. This
+ includes fan control, fan speed, charge limit, magic
+ module detection, and controller power control.
+
+ If you have an Ayaneo device, say Y or M here.
+
config MERAKI_MX100
tristate "Cisco Meraki MX100 Platform Driver"
depends on GPIOLIB
@@ -1031,9 +1039,7 @@ config OXP_EC
help
Enables support for the platform EC of OneXPlayer and AOKZOE
handheld devices. This includes fan speed, fan controls, and
- disabling the default TDP behavior of the device. Due to legacy
- reasons, this driver also provides hwmon functionality to Ayaneo
- devices and the OrangePi Neo.
+ disabling the default TDP behavior of the device.
source "drivers/platform/x86/tuxedo/Kconfig"
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index c7db2a88c11a..d25762f7114f 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -5,7 +5,6 @@
#
# Windows Management Interface
-obj-$(CONFIG_ACPI_WMI) += wmi.o
obj-$(CONFIG_WMI_BMOF) += wmi-bmof.o
# WMI drivers
@@ -33,12 +32,16 @@ obj-$(CONFIG_APPLE_GMUX) += apple-gmux.o
# ASUS
obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
obj-$(CONFIG_ASUS_WIRELESS) += asus-wireless.o
+obj-$(CONFIG_ASUS_ARMOURY) += asus-armoury.o
obj-$(CONFIG_ASUS_WMI) += asus-wmi.o
obj-$(CONFIG_ASUS_NB_WMI) += asus-nb-wmi.o
obj-$(CONFIG_ASUS_TF103C_DOCK) += asus-tf103c-dock.o
obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o
obj-$(CONFIG_EEEPC_WMI) += eeepc-wmi.o
+# Ayaneo
+obj-$(CONFIG_AYANEO_EC) += ayaneo-ec.o
+
# Cisco/Meraki
obj-$(CONFIG_MERAKI_MX100) += meraki-mx100.o
@@ -110,6 +113,9 @@ obj-$(CONFIG_TOSHIBA_WMI) += toshiba-wmi.o
# before toshiba_acpi initializes
obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
+# Uniwill
+obj-y += uniwill/
+
# Inspur
obj-$(CONFIG_INSPUR_PLATFORM_PROFILE) += inspur_platform_profile.o
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index d848afc91f87..bf97381faf58 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -12,10 +12,12 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
+#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/dmi.h>
+#include <linux/fixp-arith.h>
#include <linux/backlight.h>
#include <linux/leds.h>
#include <linux/platform_device.h>
@@ -68,10 +70,27 @@ MODULE_LICENSE("GPL");
#define ACER_WMID_SET_GAMING_LED_METHODID 2
#define ACER_WMID_GET_GAMING_LED_METHODID 4
#define ACER_WMID_GET_GAMING_SYS_INFO_METHODID 5
-#define ACER_WMID_SET_GAMING_FAN_BEHAVIOR 14
+#define ACER_WMID_SET_GAMING_FAN_BEHAVIOR_METHODID 14
+#define ACER_WMID_GET_GAMING_FAN_BEHAVIOR_METHODID 15
+#define ACER_WMID_SET_GAMING_FAN_SPEED_METHODID 16
+#define ACER_WMID_GET_GAMING_FAN_SPEED_METHODID 17
#define ACER_WMID_SET_GAMING_MISC_SETTING_METHODID 22
#define ACER_WMID_GET_GAMING_MISC_SETTING_METHODID 23
+#define ACER_GAMING_FAN_BEHAVIOR_CPU BIT(0)
+#define ACER_GAMING_FAN_BEHAVIOR_GPU BIT(3)
+
+#define ACER_GAMING_FAN_BEHAVIOR_STATUS_MASK GENMASK_ULL(7, 0)
+#define ACER_GAMING_FAN_BEHAVIOR_ID_MASK GENMASK_ULL(15, 0)
+#define ACER_GAMING_FAN_BEHAVIOR_SET_CPU_MODE_MASK GENMASK(17, 16)
+#define ACER_GAMING_FAN_BEHAVIOR_SET_GPU_MODE_MASK GENMASK(23, 22)
+#define ACER_GAMING_FAN_BEHAVIOR_GET_CPU_MODE_MASK GENMASK(9, 8)
+#define ACER_GAMING_FAN_BEHAVIOR_GET_GPU_MODE_MASK GENMASK(15, 14)
+
+#define ACER_GAMING_FAN_SPEED_STATUS_MASK GENMASK_ULL(7, 0)
+#define ACER_GAMING_FAN_SPEED_ID_MASK GENMASK_ULL(7, 0)
+#define ACER_GAMING_FAN_SPEED_VALUE_MASK GENMASK_ULL(15, 8)
+
#define ACER_GAMING_MISC_SETTING_STATUS_MASK GENMASK_ULL(7, 0)
#define ACER_GAMING_MISC_SETTING_INDEX_MASK GENMASK_ULL(7, 0)
#define ACER_GAMING_MISC_SETTING_VALUE_MASK GENMASK_ULL(15, 8)
@@ -122,6 +141,17 @@ enum acer_wmi_predator_v4_sensor_id {
ACER_WMID_SENSOR_GPU_TEMPERATURE = 0x0A,
};
+enum acer_wmi_gaming_fan_id {
+ ACER_WMID_CPU_FAN = 0x01,
+ ACER_WMID_GPU_FAN = 0x04,
+};
+
+enum acer_wmi_gaming_fan_mode {
+ ACER_WMID_FAN_MODE_AUTO = 0x01,
+ ACER_WMID_FAN_MODE_TURBO = 0x02,
+ ACER_WMID_FAN_MODE_CUSTOM = 0x03,
+};
+
enum acer_wmi_predator_v4_oc {
ACER_WMID_OC_NORMAL = 0x0000,
ACER_WMID_OC_TURBO = 0x0002,
@@ -279,6 +309,7 @@ struct hotkey_function_type_aa {
#define ACER_CAP_TURBO_FAN BIT(9)
#define ACER_CAP_PLATFORM_PROFILE BIT(10)
#define ACER_CAP_HWMON BIT(11)
+#define ACER_CAP_PWM BIT(12)
/*
* Interface type flags
@@ -373,6 +404,7 @@ struct quirk_entry {
u8 cpu_fans;
u8 gpu_fans;
u8 predator_v4;
+ u8 pwm;
};
static struct quirk_entry *quirks;
@@ -392,6 +424,9 @@ static void __init set_quirks(void)
if (quirks->predator_v4)
interface->capability |= ACER_CAP_PLATFORM_PROFILE |
ACER_CAP_HWMON;
+
+ if (quirks->pwm)
+ interface->capability |= ACER_CAP_PWM;
}
static int __init dmi_matched(const struct dmi_system_id *dmi)
@@ -431,6 +466,7 @@ static struct quirk_entry quirk_acer_predator_ph16_72 = {
.cpu_fans = 1,
.gpu_fans = 1,
.predator_v4 = 1,
+ .pwm = 1,
};
static struct quirk_entry quirk_acer_predator_pt14_51 = {
@@ -438,6 +474,7 @@ static struct quirk_entry quirk_acer_predator_pt14_51 = {
.cpu_fans = 1,
.gpu_fans = 1,
.predator_v4 = 1,
+ .pwm = 1,
};
static struct quirk_entry quirk_acer_predator_v4 = {
@@ -658,6 +695,15 @@ static const struct dmi_system_id acer_quirks[] __initconst = {
},
{
.callback = dmi_matched,
+ .ident = "Acer Predator Helios Neo 16",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Predator PHN16-72"),
+ },
+ .driver_data = &quirk_acer_predator_ph16_72,
+ },
+ {
+ .callback = dmi_matched,
.ident = "Acer Predator PH18-71",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
@@ -1564,9 +1610,6 @@ static acpi_status WMID_gaming_set_u64(u64 value, u32 cap)
case ACER_CAP_TURBO_LED:
method_id = ACER_WMID_SET_GAMING_LED_METHODID;
break;
- case ACER_CAP_TURBO_FAN:
- method_id = ACER_WMID_SET_GAMING_FAN_BEHAVIOR;
- break;
default:
return AE_BAD_PARAMETER;
}
@@ -1617,25 +1660,125 @@ static int WMID_gaming_get_sys_info(u32 command, u64 *out)
return 0;
}
-static void WMID_gaming_set_fan_mode(u8 fan_mode)
+static int WMID_gaming_set_fan_behavior(u16 fan_bitmap, enum acer_wmi_gaming_fan_mode mode)
{
- /* fan_mode = 1 is used for auto, fan_mode = 2 used for turbo*/
- u64 gpu_fan_config1 = 0, gpu_fan_config2 = 0;
- int i;
+ acpi_status status;
+ u64 input = 0;
+ u64 result;
+
+ input |= FIELD_PREP(ACER_GAMING_FAN_BEHAVIOR_ID_MASK, fan_bitmap);
+
+ if (fan_bitmap & ACER_GAMING_FAN_BEHAVIOR_CPU)
+ input |= FIELD_PREP(ACER_GAMING_FAN_BEHAVIOR_SET_CPU_MODE_MASK, mode);
+
+ if (fan_bitmap & ACER_GAMING_FAN_BEHAVIOR_GPU)
+ input |= FIELD_PREP(ACER_GAMING_FAN_BEHAVIOR_SET_GPU_MODE_MASK, mode);
+
+ status = WMI_gaming_execute_u64(ACER_WMID_SET_GAMING_FAN_BEHAVIOR_METHODID, input,
+ &result);
+ if (ACPI_FAILURE(status))
+ return -EIO;
+
+ /* The return status must be zero for the operation to have succeeded */
+ if (FIELD_GET(ACER_GAMING_FAN_BEHAVIOR_STATUS_MASK, result))
+ return -EIO;
+
+ return 0;
+}
+
+static int WMID_gaming_get_fan_behavior(u16 fan_bitmap, enum acer_wmi_gaming_fan_mode *mode)
+{
+ acpi_status status;
+ u32 input = 0;
+ u64 result;
+ int value;
+
+ input |= FIELD_PREP(ACER_GAMING_FAN_BEHAVIOR_ID_MASK, fan_bitmap);
+ status = WMI_gaming_execute_u32_u64(ACER_WMID_GET_GAMING_FAN_BEHAVIOR_METHODID, input,
+ &result);
+ if (ACPI_FAILURE(status))
+ return -EIO;
+
+ /* The return status must be zero for the operation to have succeeded */
+ if (FIELD_GET(ACER_GAMING_FAN_BEHAVIOR_STATUS_MASK, result))
+ return -EIO;
+
+ /* Theoretically multiple fans can be specified, but this is currently unused */
+ if (fan_bitmap & ACER_GAMING_FAN_BEHAVIOR_CPU)
+ value = FIELD_GET(ACER_GAMING_FAN_BEHAVIOR_GET_CPU_MODE_MASK, result);
+ else if (fan_bitmap & ACER_GAMING_FAN_BEHAVIOR_GPU)
+ value = FIELD_GET(ACER_GAMING_FAN_BEHAVIOR_GET_GPU_MODE_MASK, result);
+ else
+ return -EINVAL;
+
+ if (value < ACER_WMID_FAN_MODE_AUTO || value > ACER_WMID_FAN_MODE_CUSTOM)
+ return -ENXIO;
+
+ *mode = value;
+
+ return 0;
+}
+
+static void WMID_gaming_set_fan_mode(enum acer_wmi_gaming_fan_mode mode)
+{
+ u16 fan_bitmap = 0;
if (quirks->cpu_fans > 0)
- gpu_fan_config2 |= 1;
- for (i = 0; i < (quirks->cpu_fans + quirks->gpu_fans); ++i)
- gpu_fan_config2 |= 1 << (i + 1);
- for (i = 0; i < quirks->gpu_fans; ++i)
- gpu_fan_config2 |= 1 << (i + 3);
- if (quirks->cpu_fans > 0)
- gpu_fan_config1 |= fan_mode;
- for (i = 0; i < (quirks->cpu_fans + quirks->gpu_fans); ++i)
- gpu_fan_config1 |= fan_mode << (2 * i + 2);
- for (i = 0; i < quirks->gpu_fans; ++i)
- gpu_fan_config1 |= fan_mode << (2 * i + 6);
- WMID_gaming_set_u64(gpu_fan_config2 | gpu_fan_config1 << 16, ACER_CAP_TURBO_FAN);
+ fan_bitmap |= ACER_GAMING_FAN_BEHAVIOR_CPU;
+
+ if (quirks->gpu_fans > 0)
+ fan_bitmap |= ACER_GAMING_FAN_BEHAVIOR_GPU;
+
+ WMID_gaming_set_fan_behavior(fan_bitmap, mode);
+}
+
+static int WMID_gaming_set_gaming_fan_speed(u8 fan, u8 speed)
+{
+ acpi_status status;
+ u64 input = 0;
+ u64 result;
+
+ if (speed > 100)
+ return -EINVAL;
+
+ input |= FIELD_PREP(ACER_GAMING_FAN_SPEED_ID_MASK, fan);
+ input |= FIELD_PREP(ACER_GAMING_FAN_SPEED_VALUE_MASK, speed);
+
+ status = WMI_gaming_execute_u64(ACER_WMID_SET_GAMING_FAN_SPEED_METHODID, input, &result);
+ if (ACPI_FAILURE(status))
+ return -EIO;
+
+ switch (FIELD_GET(ACER_GAMING_FAN_SPEED_STATUS_MASK, result)) {
+ case 0x00:
+ return 0;
+ case 0x01:
+ return -ENODEV;
+ case 0x02:
+ return -EINVAL;
+ default:
+ return -ENXIO;
+ }
+}
+
+static int WMID_gaming_get_gaming_fan_speed(u8 fan, u8 *speed)
+{
+ acpi_status status;
+ u32 input = 0;
+ u64 result;
+
+ input |= FIELD_PREP(ACER_GAMING_FAN_SPEED_ID_MASK, fan);
+
+ status = WMI_gaming_execute_u32_u64(ACER_WMID_GET_GAMING_FAN_SPEED_METHODID, input,
+ &result);
+ if (ACPI_FAILURE(status))
+ return -EIO;
+
+ if (FIELD_GET(ACER_GAMING_FAN_SPEED_STATUS_MASK, result))
+ return -ENODEV;
+
+ *speed = FIELD_GET(ACER_GAMING_FAN_SPEED_VALUE_MASK, result);
+
+ return 0;
}
static int WMID_gaming_set_misc_setting(enum acer_wmi_gaming_misc_setting setting, u8 value)
@@ -1922,7 +2065,7 @@ static int acer_toggle_turbo(void)
WMID_gaming_set_u64(0x1, ACER_CAP_TURBO_LED);
/* Set FAN mode to auto */
- WMID_gaming_set_fan_mode(0x1);
+ WMID_gaming_set_fan_mode(ACER_WMID_FAN_MODE_AUTO);
/* Set OC to normal */
if (has_cap(ACER_CAP_TURBO_OC)) {
@@ -1936,7 +2079,7 @@ static int acer_toggle_turbo(void)
WMID_gaming_set_u64(0x10001, ACER_CAP_TURBO_LED);
/* Set FAN mode to turbo */
- WMID_gaming_set_fan_mode(0x2);
+ WMID_gaming_set_fan_mode(ACER_WMID_FAN_MODE_TURBO);
/* Set OC to turbo mode */
if (has_cap(ACER_CAP_TURBO_OC)) {
@@ -2767,6 +2910,16 @@ static const enum acer_wmi_predator_v4_sensor_id acer_wmi_fan_channel_to_sensor_
[1] = ACER_WMID_SENSOR_GPU_FAN_SPEED,
};
+static const enum acer_wmi_gaming_fan_id acer_wmi_fan_channel_to_fan_id[] = {
+ [0] = ACER_WMID_CPU_FAN,
+ [1] = ACER_WMID_GPU_FAN,
+};
+
+static const u16 acer_wmi_fan_channel_to_fan_bitmap[] = {
+ [0] = ACER_GAMING_FAN_BEHAVIOR_CPU,
+ [1] = ACER_GAMING_FAN_BEHAVIOR_GPU,
+};
+
static umode_t acer_wmi_hwmon_is_visible(const void *data,
enum hwmon_sensor_types type, u32 attr,
int channel)
@@ -2778,6 +2931,11 @@ static umode_t acer_wmi_hwmon_is_visible(const void *data,
case hwmon_temp:
sensor_id = acer_wmi_temp_channel_to_sensor_id[channel];
break;
+ case hwmon_pwm:
+ if (!has_cap(ACER_CAP_PWM))
+ return 0;
+
+ fallthrough;
case hwmon_fan:
sensor_id = acer_wmi_fan_channel_to_sensor_id[channel];
break;
@@ -2785,8 +2943,12 @@ static umode_t acer_wmi_hwmon_is_visible(const void *data,
return 0;
}
- if (*supported_sensors & BIT(sensor_id - 1))
+ if (*supported_sensors & BIT(sensor_id - 1)) {
+ if (type == hwmon_pwm)
+ return 0644;
+
return 0444;
+ }
return 0;
}
@@ -2795,6 +2957,9 @@ static int acer_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{
u64 command = ACER_WMID_CMD_GET_PREDATOR_V4_SENSOR_READING;
+ enum acer_wmi_gaming_fan_mode mode;
+ u16 fan_bitmap;
+ u8 fan, speed;
u64 result;
int ret;
@@ -2820,6 +2985,80 @@ static int acer_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
*val = FIELD_GET(ACER_PREDATOR_V4_SENSOR_READING_BIT_MASK, result);
return 0;
+ case hwmon_pwm:
+ switch (attr) {
+ case hwmon_pwm_input:
+ fan = acer_wmi_fan_channel_to_fan_id[channel];
+ ret = WMID_gaming_get_gaming_fan_speed(fan, &speed);
+ if (ret < 0)
+ return ret;
+
+ *val = fixp_linear_interpolate(0, 0, 100, U8_MAX, speed);
+ return 0;
+ case hwmon_pwm_enable:
+ fan_bitmap = acer_wmi_fan_channel_to_fan_bitmap[channel];
+ ret = WMID_gaming_get_fan_behavior(fan_bitmap, &mode);
+ if (ret < 0)
+ return ret;
+
+ switch (mode) {
+ case ACER_WMID_FAN_MODE_AUTO:
+ *val = 2;
+ return 0;
+ case ACER_WMID_FAN_MODE_TURBO:
+ *val = 0;
+ return 0;
+ case ACER_WMID_FAN_MODE_CUSTOM:
+ *val = 1;
+ return 0;
+ default:
+ return -ENXIO;
+ }
+ default:
+ return -EOPNOTSUPP;
+ }
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int acer_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long val)
+{
+ enum acer_wmi_gaming_fan_mode mode;
+ u16 fan_bitmap;
+ u8 fan, speed;
+
+ switch (type) {
+ case hwmon_pwm:
+ switch (attr) {
+ case hwmon_pwm_input:
+ fan = acer_wmi_fan_channel_to_fan_id[channel];
+ speed = fixp_linear_interpolate(0, 0, U8_MAX, 100,
+ clamp_val(val, 0, U8_MAX));
+
+ return WMID_gaming_set_gaming_fan_speed(fan, speed);
+ case hwmon_pwm_enable:
+ fan_bitmap = acer_wmi_fan_channel_to_fan_bitmap[channel];
+
+ switch (val) {
+ case 0:
+ mode = ACER_WMID_FAN_MODE_TURBO;
+ break;
+ case 1:
+ mode = ACER_WMID_FAN_MODE_CUSTOM;
+ break;
+ case 2:
+ mode = ACER_WMID_FAN_MODE_AUTO;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return WMID_gaming_set_fan_behavior(fan_bitmap, mode);
+ default:
+ return -EOPNOTSUPP;
+ }
default:
return -EOPNOTSUPP;
}
@@ -2835,11 +3074,16 @@ static const struct hwmon_channel_info *const acer_wmi_hwmon_info[] = {
HWMON_F_INPUT,
HWMON_F_INPUT
),
+ HWMON_CHANNEL_INFO(pwm,
+ HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
+ HWMON_PWM_INPUT | HWMON_PWM_ENABLE
+ ),
NULL
};
static const struct hwmon_ops acer_wmi_hwmon_ops = {
.read = acer_wmi_hwmon_read,
+ .write = acer_wmi_hwmon_write,
.is_visible = acer_wmi_hwmon_is_visible,
};
diff --git a/drivers/platform/x86/amd/hfi/hfi.c b/drivers/platform/x86/amd/hfi/hfi.c
index a465ac6f607e..83863a5e0fbc 100644
--- a/drivers/platform/x86/amd/hfi/hfi.c
+++ b/drivers/platform/x86/amd/hfi/hfi.c
@@ -12,7 +12,6 @@
#include <linux/acpi.h>
#include <linux/cpu.h>
-#include <linux/cpumask.h>
#include <linux/debugfs.h>
#include <linux/gfp.h>
#include <linux/init.h>
@@ -95,7 +94,6 @@ struct amd_hfi_classes {
* struct amd_hfi_cpuinfo - HFI workload class info per CPU
* @cpu: CPU index
* @apic_id: APIC id of the current CPU
- * @cpus: mask of CPUs associated with amd_hfi_cpuinfo
* @class_index: workload class ID index
* @nr_class: max number of workload class supported
* @ipcc_scores: ipcc scores for each class
@@ -106,7 +104,6 @@ struct amd_hfi_classes {
struct amd_hfi_cpuinfo {
int cpu;
u32 apic_id;
- cpumask_var_t cpus;
s16 class_index;
u8 nr_class;
int *ipcc_scores;
@@ -295,11 +292,6 @@ static int amd_hfi_online(unsigned int cpu)
guard(mutex)(&hfi_cpuinfo_lock);
- if (!zalloc_cpumask_var(&hfi_info->cpus, GFP_KERNEL))
- return -ENOMEM;
-
- cpumask_set_cpu(cpu, hfi_info->cpus);
-
ret = amd_hfi_set_state(cpu, true);
if (ret)
pr_err("WCT enable failed for CPU %u\n", cpu);
@@ -329,8 +321,6 @@ static int amd_hfi_offline(unsigned int cpu)
if (ret)
pr_err("WCT disable failed for CPU %u\n", cpu);
- free_cpumask_var(hfi_info->cpus);
-
return ret;
}
@@ -515,7 +505,6 @@ static int amd_hfi_probe(struct platform_device *pdev)
static struct platform_driver amd_hfi_driver = {
.driver = {
.name = AMD_HFI_DRIVER,
- .owner = THIS_MODULE,
.pm = &amd_hfi_pm_ops,
.acpi_match_table = ACPI_PTR(amd_hfi_platform_match),
},
diff --git a/drivers/platform/x86/amd/hsmp/acpi.c b/drivers/platform/x86/amd/hsmp/acpi.c
index d0b74d243ce4..97ed71593bdf 100644
--- a/drivers/platform/x86/amd/hsmp/acpi.c
+++ b/drivers/platform/x86/amd/hsmp/acpi.c
@@ -22,12 +22,11 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/sysfs.h>
+#include <linux/topology.h>
#include <linux/uuid.h>
#include <uapi/asm-generic/errno-base.h>
-#include <asm/amd/node.h>
-
#include "hsmp.h"
#define DRIVER_NAME "hsmp_acpi"
@@ -586,9 +585,9 @@ static int hsmp_acpi_probe(struct platform_device *pdev)
return -ENOMEM;
if (!hsmp_pdev->is_probed) {
- hsmp_pdev->num_sockets = amd_num_nodes();
- if (hsmp_pdev->num_sockets == 0 || hsmp_pdev->num_sockets > MAX_AMD_NUM_NODES) {
- dev_err(&pdev->dev, "Wrong number of sockets\n");
+ hsmp_pdev->num_sockets = topology_max_packages();
+ if (!hsmp_pdev->num_sockets) {
+ dev_err(&pdev->dev, "No CPU sockets detected\n");
return -ENODEV;
}
diff --git a/drivers/platform/x86/amd/pmf/auto-mode.c b/drivers/platform/x86/amd/pmf/auto-mode.c
index a184922bba8d..faf15a8f74bb 100644
--- a/drivers/platform/x86/amd/pmf/auto-mode.c
+++ b/drivers/platform/x86/amd/pmf/auto-mode.c
@@ -114,14 +114,14 @@ static void amd_pmf_set_automode(struct amd_pmf_dev *dev, int idx,
{
struct power_table_control *pwr_ctrl = &config_store.mode_set[idx].power_control;
- amd_pmf_send_cmd(dev, SET_SPL, false, pwr_ctrl->spl, NULL);
- amd_pmf_send_cmd(dev, SET_FPPT, false, pwr_ctrl->fppt, NULL);
- amd_pmf_send_cmd(dev, SET_SPPT, false, pwr_ctrl->sppt, NULL);
- amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, pwr_ctrl->sppt_apu_only, NULL);
- amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, pwr_ctrl->stt_min, NULL);
- amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false,
+ amd_pmf_send_cmd(dev, SET_SPL, SET_CMD, pwr_ctrl->spl, NULL);
+ amd_pmf_send_cmd(dev, SET_FPPT, SET_CMD, pwr_ctrl->fppt, NULL);
+ amd_pmf_send_cmd(dev, SET_SPPT, SET_CMD, pwr_ctrl->sppt, NULL);
+ amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, SET_CMD, pwr_ctrl->sppt_apu_only, NULL);
+ amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, SET_CMD, pwr_ctrl->stt_min, NULL);
+ amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, SET_CMD,
fixp_q88_fromint(pwr_ctrl->stt_skin_temp[STT_TEMP_APU]), NULL);
- amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false,
+ amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, SET_CMD,
fixp_q88_fromint(pwr_ctrl->stt_skin_temp[STT_TEMP_HS2]), NULL);
if (is_apmf_func_supported(dev, APMF_FUNC_SET_FAN_IDX))
diff --git a/drivers/platform/x86/amd/pmf/cnqf.c b/drivers/platform/x86/amd/pmf/cnqf.c
index 207a0b33d8d3..5469fefb6001 100644
--- a/drivers/platform/x86/amd/pmf/cnqf.c
+++ b/drivers/platform/x86/amd/pmf/cnqf.c
@@ -76,14 +76,14 @@ static int amd_pmf_set_cnqf(struct amd_pmf_dev *dev, int src, int idx,
pc = &config_store.mode_set[src][idx].power_control;
- amd_pmf_send_cmd(dev, SET_SPL, false, pc->spl, NULL);
- amd_pmf_send_cmd(dev, SET_FPPT, false, pc->fppt, NULL);
- amd_pmf_send_cmd(dev, SET_SPPT, false, pc->sppt, NULL);
- amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, pc->sppt_apu_only, NULL);
- amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, pc->stt_min, NULL);
- amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false,
+ amd_pmf_send_cmd(dev, SET_SPL, SET_CMD, pc->spl, NULL);
+ amd_pmf_send_cmd(dev, SET_FPPT, SET_CMD, pc->fppt, NULL);
+ amd_pmf_send_cmd(dev, SET_SPPT, SET_CMD, pc->sppt, NULL);
+ amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, SET_CMD, pc->sppt_apu_only, NULL);
+ amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, SET_CMD, pc->stt_min, NULL);
+ amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, SET_CMD,
fixp_q88_fromint(pc->stt_skin_temp[STT_TEMP_APU]), NULL);
- amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false,
+ amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, SET_CMD,
fixp_q88_fromint(pc->stt_skin_temp[STT_TEMP_HS2]), NULL);
if (is_apmf_func_supported(dev, APMF_FUNC_SET_FAN_IDX))
diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c
index bc544a4a5266..8fc293c9c538 100644
--- a/drivers/platform/x86/amd/pmf/core.c
+++ b/drivers/platform/x86/amd/pmf/core.c
@@ -131,7 +131,7 @@ static void amd_pmf_get_metrics(struct work_struct *work)
/* Transfer table contents */
memset(dev->buf, 0, sizeof(dev->m_table));
- amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, 0, 7, NULL);
+ amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, SET_CMD, METRICS_TABLE_ID, NULL);
memcpy(&dev->m_table, dev->buf, sizeof(dev->m_table));
time_elapsed_ms = ktime_to_ms(ktime_get()) - dev->start_time;
@@ -289,8 +289,8 @@ int amd_pmf_set_dram_addr(struct amd_pmf_dev *dev, bool alloc_buffer)
hi = phys_addr >> 32;
low = phys_addr & GENMASK(31, 0);
- amd_pmf_send_cmd(dev, SET_DRAM_ADDR_HIGH, 0, hi, NULL);
- amd_pmf_send_cmd(dev, SET_DRAM_ADDR_LOW, 0, low, NULL);
+ amd_pmf_send_cmd(dev, SET_DRAM_ADDR_HIGH, SET_CMD, hi, NULL);
+ amd_pmf_send_cmd(dev, SET_DRAM_ADDR_LOW, SET_CMD, low, NULL);
return 0;
}
@@ -465,9 +465,17 @@ static int amd_pmf_probe(struct platform_device *pdev)
if (!dev->regbase)
return -ENOMEM;
- mutex_init(&dev->lock);
- mutex_init(&dev->update_mutex);
- mutex_init(&dev->cb_mutex);
+ err = devm_mutex_init(dev->dev, &dev->lock);
+ if (err)
+ return err;
+
+ err = devm_mutex_init(dev->dev, &dev->update_mutex);
+ if (err)
+ return err;
+
+ err = devm_mutex_init(dev->dev, &dev->cb_mutex);
+ if (err)
+ return err;
apmf_acpi_init(dev);
platform_set_drvdata(pdev, dev);
@@ -491,9 +499,6 @@ static void amd_pmf_remove(struct platform_device *pdev)
amd_pmf_notify_sbios_heartbeat_event_v2(dev, ON_UNLOAD);
apmf_acpi_deinit(dev);
amd_pmf_dbgfs_unregister(dev);
- mutex_destroy(&dev->lock);
- mutex_destroy(&dev->update_mutex);
- mutex_destroy(&dev->cb_mutex);
}
static const struct attribute_group *amd_pmf_driver_groups[] = {
diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h
index bd19f2a6bc78..9144c8c3bbaf 100644
--- a/drivers/platform/x86/amd/pmf/pmf.h
+++ b/drivers/platform/x86/amd/pmf/pmf.h
@@ -119,6 +119,13 @@ struct cookie_header {
#define APTS_MAX_STATES 16
#define CUSTOM_BIOS_INPUT_BITS GENMASK(16, 7)
+#define BIOS_INPUTS_MAX 10
+
+/* amd_pmf_send_cmd() set/get */
+#define SET_CMD false
+#define GET_CMD true
+
+#define METRICS_TABLE_ID 7
typedef void (*apmf_event_handler_t)(acpi_handle handle, u32 event, void *data);
@@ -204,7 +211,7 @@ struct apmf_sbios_req_v1 {
u8 skin_temp_apu;
u8 skin_temp_hs2;
u8 enable_cnqf;
- u32 custom_policy[10];
+ u32 custom_policy[BIOS_INPUTS_MAX];
} __packed;
struct apmf_sbios_req_v2 {
@@ -216,7 +223,7 @@ struct apmf_sbios_req_v2 {
u32 stt_min_limit;
u8 skin_temp_apu;
u8 skin_temp_hs2;
- u32 custom_policy[10];
+ u32 custom_policy[BIOS_INPUTS_MAX];
} __packed;
struct apmf_fan_idx {
@@ -243,12 +250,12 @@ struct smu_pmf_metrics_v2 {
u16 vclk_freq; /* MHz */
u16 vcn_activity; /* VCN busy % [0-100] */
u16 vpeclk_freq; /* MHz */
- u16 ipuclk_freq; /* MHz */
- u16 ipu_busy[8]; /* NPU busy % [0-100] */
+ u16 npuclk_freq; /* MHz */
+ u16 npu_busy[8]; /* NPU busy % [0-100] */
u16 dram_reads; /* MB/sec */
u16 dram_writes; /* MB/sec */
u16 core_c0residency[16]; /* C0 residency % [0-100] */
- u16 ipu_power; /* mW */
+ u16 npu_power; /* mW */
u32 apu_power; /* mW */
u32 gfx_power; /* mW */
u32 dgpu_power; /* mW */
@@ -257,9 +264,9 @@ struct smu_pmf_metrics_v2 {
u32 filter_alpha_value; /* time constant [us] */
u32 metrics_counter;
u16 memclk_freq; /* MHz */
- u16 mpipuclk_freq; /* MHz */
- u16 ipu_reads; /* MB/sec */
- u16 ipu_writes; /* MB/sec */
+ u16 mpnpuclk_freq; /* MHz */
+ u16 npu_reads; /* MB/sec */
+ u16 npu_writes; /* MB/sec */
u32 throttle_residency_prochot;
u32 throttle_residency_spl;
u32 throttle_residency_fppt;
@@ -355,7 +362,7 @@ enum power_modes_v2 {
};
struct pmf_bios_inputs_prev {
- u32 custom_bios_inputs[10];
+ u32 custom_bios_inputs[BIOS_INPUTS_MAX];
};
struct amd_pmf_dev {
@@ -451,7 +458,7 @@ struct os_power_slider {
struct amd_pmf_notify_smart_pc_update {
u16 size;
u32 pending_req;
- u32 custom_bios[10];
+ u32 custom_bios[BIOS_INPUTS_MAX];
} __packed;
struct fan_table_control {
diff --git a/drivers/platform/x86/amd/pmf/spc.c b/drivers/platform/x86/amd/pmf/spc.c
index 85192c7536b8..0a37dc6a7950 100644
--- a/drivers/platform/x86/amd/pmf/spc.c
+++ b/drivers/platform/x86/amd/pmf/spc.c
@@ -202,7 +202,7 @@ static void amd_pmf_get_smu_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_ta
{
/* Get the updated metrics table data */
memset(dev->buf, 0, dev->mtable_size);
- amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, 0, 7, NULL);
+ amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, SET_CMD, METRICS_TABLE_ID, NULL);
switch (dev->cpu_id) {
case AMD_CPU_ID_PS:
diff --git a/drivers/platform/x86/amd/pmf/sps.c b/drivers/platform/x86/amd/pmf/sps.c
index c28f3c5744c2..0b70a5153f46 100644
--- a/drivers/platform/x86/amd/pmf/sps.c
+++ b/drivers/platform/x86/amd/pmf/sps.c
@@ -192,15 +192,15 @@ static void amd_pmf_load_defaults_sps(struct amd_pmf_dev *dev)
static void amd_pmf_update_slider_v2(struct amd_pmf_dev *dev, int idx)
{
- amd_pmf_send_cmd(dev, SET_PMF_PPT, false, apts_config_store.val[idx].pmf_ppt, NULL);
- amd_pmf_send_cmd(dev, SET_PMF_PPT_APU_ONLY, false,
+ amd_pmf_send_cmd(dev, SET_PMF_PPT, SET_CMD, apts_config_store.val[idx].pmf_ppt, NULL);
+ amd_pmf_send_cmd(dev, SET_PMF_PPT_APU_ONLY, SET_CMD,
apts_config_store.val[idx].ppt_pmf_apu_only, NULL);
- amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false,
+ amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, SET_CMD,
apts_config_store.val[idx].stt_min_limit, NULL);
- amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false,
+ amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, SET_CMD,
fixp_q88_fromint(apts_config_store.val[idx].stt_skin_temp_limit_apu),
NULL);
- amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false,
+ amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, SET_CMD,
fixp_q88_fromint(apts_config_store.val[idx].stt_skin_temp_limit_hs2),
NULL);
}
@@ -211,30 +211,30 @@ void amd_pmf_update_slider(struct amd_pmf_dev *dev, bool op, int idx,
int src = amd_pmf_get_power_source();
if (op == SLIDER_OP_SET) {
- amd_pmf_send_cmd(dev, SET_SPL, false, config_store.prop[src][idx].spl, NULL);
- amd_pmf_send_cmd(dev, SET_FPPT, false, config_store.prop[src][idx].fppt, NULL);
- amd_pmf_send_cmd(dev, SET_SPPT, false, config_store.prop[src][idx].sppt, NULL);
- amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false,
+ amd_pmf_send_cmd(dev, SET_SPL, SET_CMD, config_store.prop[src][idx].spl, NULL);
+ amd_pmf_send_cmd(dev, SET_FPPT, SET_CMD, config_store.prop[src][idx].fppt, NULL);
+ amd_pmf_send_cmd(dev, SET_SPPT, SET_CMD, config_store.prop[src][idx].sppt, NULL);
+ amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, SET_CMD,
config_store.prop[src][idx].sppt_apu_only, NULL);
- amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false,
+ amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, SET_CMD,
config_store.prop[src][idx].stt_min, NULL);
- amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false,
+ amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, SET_CMD,
fixp_q88_fromint(config_store.prop[src][idx].stt_skin_temp[STT_TEMP_APU]),
NULL);
- amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false,
+ amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, SET_CMD,
fixp_q88_fromint(config_store.prop[src][idx].stt_skin_temp[STT_TEMP_HS2]),
NULL);
} else if (op == SLIDER_OP_GET) {
- amd_pmf_send_cmd(dev, GET_SPL, true, ARG_NONE, &table->prop[src][idx].spl);
- amd_pmf_send_cmd(dev, GET_FPPT, true, ARG_NONE, &table->prop[src][idx].fppt);
- amd_pmf_send_cmd(dev, GET_SPPT, true, ARG_NONE, &table->prop[src][idx].sppt);
- amd_pmf_send_cmd(dev, GET_SPPT_APU_ONLY, true, ARG_NONE,
+ amd_pmf_send_cmd(dev, GET_SPL, GET_CMD, ARG_NONE, &table->prop[src][idx].spl);
+ amd_pmf_send_cmd(dev, GET_FPPT, GET_CMD, ARG_NONE, &table->prop[src][idx].fppt);
+ amd_pmf_send_cmd(dev, GET_SPPT, GET_CMD, ARG_NONE, &table->prop[src][idx].sppt);
+ amd_pmf_send_cmd(dev, GET_SPPT_APU_ONLY, GET_CMD, ARG_NONE,
&table->prop[src][idx].sppt_apu_only);
- amd_pmf_send_cmd(dev, GET_STT_MIN_LIMIT, true, ARG_NONE,
+ amd_pmf_send_cmd(dev, GET_STT_MIN_LIMIT, GET_CMD, ARG_NONE,
&table->prop[src][idx].stt_min);
- amd_pmf_send_cmd(dev, GET_STT_LIMIT_APU, true, ARG_NONE,
+ amd_pmf_send_cmd(dev, GET_STT_LIMIT_APU, GET_CMD, ARG_NONE,
(u32 *)&table->prop[src][idx].stt_skin_temp[STT_TEMP_APU]);
- amd_pmf_send_cmd(dev, GET_STT_LIMIT_HS2, true, ARG_NONE,
+ amd_pmf_send_cmd(dev, GET_STT_LIMIT_HS2, GET_CMD, ARG_NONE,
(u32 *)&table->prop[src][idx].stt_skin_temp[STT_TEMP_HS2]);
}
}
diff --git a/drivers/platform/x86/amd/pmf/tee-if.c b/drivers/platform/x86/amd/pmf/tee-if.c
index 6e8116bef4f6..0abce76f89ff 100644
--- a/drivers/platform/x86/amd/pmf/tee-if.c
+++ b/drivers/platform/x86/amd/pmf/tee-if.c
@@ -73,17 +73,56 @@ static void amd_pmf_update_uevents(struct amd_pmf_dev *dev, u16 event)
input_sync(dev->pmf_idev);
}
+static int amd_pmf_get_bios_output_idx(u32 action_idx)
+{
+ switch (action_idx) {
+ case PMF_POLICY_BIOS_OUTPUT_1:
+ return 0;
+ case PMF_POLICY_BIOS_OUTPUT_2:
+ return 1;
+ case PMF_POLICY_BIOS_OUTPUT_3:
+ return 2;
+ case PMF_POLICY_BIOS_OUTPUT_4:
+ return 3;
+ case PMF_POLICY_BIOS_OUTPUT_5:
+ return 4;
+ case PMF_POLICY_BIOS_OUTPUT_6:
+ return 5;
+ case PMF_POLICY_BIOS_OUTPUT_7:
+ return 6;
+ case PMF_POLICY_BIOS_OUTPUT_8:
+ return 7;
+ case PMF_POLICY_BIOS_OUTPUT_9:
+ return 8;
+ case PMF_POLICY_BIOS_OUTPUT_10:
+ return 9;
+ default:
+ return -EINVAL;
+ }
+}
+
+static void amd_pmf_update_bios_output(struct amd_pmf_dev *pdev, struct ta_pmf_action *action)
+{
+ u32 bios_idx;
+
+ bios_idx = amd_pmf_get_bios_output_idx(action->action_index);
+
+ amd_pmf_smartpc_apply_bios_output(pdev, action->value, BIT(bios_idx), bios_idx);
+}
+
static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_result *out)
{
+ struct ta_pmf_action *action;
u32 val;
int idx;
for (idx = 0; idx < out->actions_count; idx++) {
- val = out->actions_list[idx].value;
- switch (out->actions_list[idx].action_index) {
+ action = &out->actions_list[idx];
+ val = action->value;
+ switch (action->action_index) {
case PMF_POLICY_SPL:
if (dev->prev_data->spl != val) {
- amd_pmf_send_cmd(dev, SET_SPL, false, val, NULL);
+ amd_pmf_send_cmd(dev, SET_SPL, SET_CMD, val, NULL);
dev_dbg(dev->dev, "update SPL: %u\n", val);
dev->prev_data->spl = val;
}
@@ -91,7 +130,7 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_
case PMF_POLICY_SPPT:
if (dev->prev_data->sppt != val) {
- amd_pmf_send_cmd(dev, SET_SPPT, false, val, NULL);
+ amd_pmf_send_cmd(dev, SET_SPPT, SET_CMD, val, NULL);
dev_dbg(dev->dev, "update SPPT: %u\n", val);
dev->prev_data->sppt = val;
}
@@ -99,7 +138,7 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_
case PMF_POLICY_FPPT:
if (dev->prev_data->fppt != val) {
- amd_pmf_send_cmd(dev, SET_FPPT, false, val, NULL);
+ amd_pmf_send_cmd(dev, SET_FPPT, SET_CMD, val, NULL);
dev_dbg(dev->dev, "update FPPT: %u\n", val);
dev->prev_data->fppt = val;
}
@@ -107,7 +146,7 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_
case PMF_POLICY_SPPT_APU_ONLY:
if (dev->prev_data->sppt_apuonly != val) {
- amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, val, NULL);
+ amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, SET_CMD, val, NULL);
dev_dbg(dev->dev, "update SPPT_APU_ONLY: %u\n", val);
dev->prev_data->sppt_apuonly = val;
}
@@ -115,7 +154,7 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_
case PMF_POLICY_STT_MIN:
if (dev->prev_data->stt_minlimit != val) {
- amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, val, NULL);
+ amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, SET_CMD, val, NULL);
dev_dbg(dev->dev, "update STT_MIN: %u\n", val);
dev->prev_data->stt_minlimit = val;
}
@@ -123,7 +162,7 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_
case PMF_POLICY_STT_SKINTEMP_APU:
if (dev->prev_data->stt_skintemp_apu != val) {
- amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false,
+ amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, SET_CMD,
fixp_q88_fromint(val), NULL);
dev_dbg(dev->dev, "update STT_SKINTEMP_APU: %u\n", val);
dev->prev_data->stt_skintemp_apu = val;
@@ -132,7 +171,7 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_
case PMF_POLICY_STT_SKINTEMP_HS2:
if (dev->prev_data->stt_skintemp_hs2 != val) {
- amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false,
+ amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, SET_CMD,
fixp_q88_fromint(val), NULL);
dev_dbg(dev->dev, "update STT_SKINTEMP_HS2: %u\n", val);
dev->prev_data->stt_skintemp_hs2 = val;
@@ -141,7 +180,7 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_
case PMF_POLICY_P3T:
if (dev->prev_data->p3t_limit != val) {
- amd_pmf_send_cmd(dev, SET_P3T, false, val, NULL);
+ amd_pmf_send_cmd(dev, SET_P3T, SET_CMD, val, NULL);
dev_dbg(dev->dev, "update P3T: %u\n", val);
dev->prev_data->p3t_limit = val;
}
@@ -149,7 +188,7 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_
case PMF_POLICY_PMF_PPT:
if (dev->prev_data->pmf_ppt != val) {
- amd_pmf_send_cmd(dev, SET_PMF_PPT, false, val, NULL);
+ amd_pmf_send_cmd(dev, SET_PMF_PPT, SET_CMD, val, NULL);
dev_dbg(dev->dev, "update PMF PPT: %u\n", val);
dev->prev_data->pmf_ppt = val;
}
@@ -157,7 +196,7 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_
case PMF_POLICY_PMF_PPT_APU_ONLY:
if (dev->prev_data->pmf_ppt_apu_only != val) {
- amd_pmf_send_cmd(dev, SET_PMF_PPT_APU_ONLY, false, val, NULL);
+ amd_pmf_send_cmd(dev, SET_PMF_PPT_APU_ONLY, SET_CMD, val, NULL);
dev_dbg(dev->dev, "update PMF PPT APU ONLY: %u\n", val);
dev->prev_data->pmf_ppt_apu_only = val;
}
@@ -183,43 +222,16 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_
break;
case PMF_POLICY_BIOS_OUTPUT_1:
- amd_pmf_smartpc_apply_bios_output(dev, val, BIT(0), 0);
- break;
-
case PMF_POLICY_BIOS_OUTPUT_2:
- amd_pmf_smartpc_apply_bios_output(dev, val, BIT(1), 1);
- break;
-
case PMF_POLICY_BIOS_OUTPUT_3:
- amd_pmf_smartpc_apply_bios_output(dev, val, BIT(2), 2);
- break;
-
case PMF_POLICY_BIOS_OUTPUT_4:
- amd_pmf_smartpc_apply_bios_output(dev, val, BIT(3), 3);
- break;
-
case PMF_POLICY_BIOS_OUTPUT_5:
- amd_pmf_smartpc_apply_bios_output(dev, val, BIT(4), 4);
- break;
-
case PMF_POLICY_BIOS_OUTPUT_6:
- amd_pmf_smartpc_apply_bios_output(dev, val, BIT(5), 5);
- break;
-
case PMF_POLICY_BIOS_OUTPUT_7:
- amd_pmf_smartpc_apply_bios_output(dev, val, BIT(6), 6);
- break;
-
case PMF_POLICY_BIOS_OUTPUT_8:
- amd_pmf_smartpc_apply_bios_output(dev, val, BIT(7), 7);
- break;
-
case PMF_POLICY_BIOS_OUTPUT_9:
- amd_pmf_smartpc_apply_bios_output(dev, val, BIT(8), 8);
- break;
-
case PMF_POLICY_BIOS_OUTPUT_10:
- amd_pmf_smartpc_apply_bios_output(dev, val, BIT(9), 9);
+ amd_pmf_update_bios_output(dev, action);
break;
}
}
diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c
new file mode 100644
index 000000000000..9c1a9ad42bc4
--- /dev/null
+++ b/drivers/platform/x86/asus-armoury.c
@@ -0,0 +1,1161 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Asus Armoury (WMI) attributes driver.
+ *
+ * This driver uses the fw_attributes class to expose various WMI functions
+ * that are present in many gaming and some non-gaming ASUS laptops.
+ *
+ * These typically don't fit anywhere else in the sysfs such as under LED class,
+ * hwmon or others, and are set in Windows using the ASUS Armoury Crate tool.
+ *
+ * Copyright(C) 2024 Luke Jones <luke@ljones.dev>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/acpi.h>
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
+#include <linux/device.h>
+#include <linux/dmi.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/kmod.h>
+#include <linux/kobject.h>
+#include <linux/kstrtox.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/pci.h>
+#include <linux/platform_data/x86/asus-wmi.h>
+#include <linux/printk.h>
+#include <linux/power_supply.h>
+#include <linux/sysfs.h>
+
+#include "asus-armoury.h"
+#include "firmware_attributes_class.h"
+
+#define ASUS_NB_WMI_EVENT_GUID "0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C"
+
+#define ASUS_MINI_LED_MODE_MASK GENMASK(1, 0)
+/* Standard modes for devices with only on/off */
+#define ASUS_MINI_LED_OFF 0x00
+#define ASUS_MINI_LED_ON 0x01
+/* Like "on" but the effect is more vibrant or brighter */
+#define ASUS_MINI_LED_STRONG_MODE 0x02
+/* New modes for devices with 3 mini-led mode types */
+#define ASUS_MINI_LED_2024_WEAK 0x00
+#define ASUS_MINI_LED_2024_STRONG 0x01
+#define ASUS_MINI_LED_2024_OFF 0x02
+
+/* Power tunable attribute name defines */
+#define ATTR_PPT_PL1_SPL "ppt_pl1_spl"
+#define ATTR_PPT_PL2_SPPT "ppt_pl2_sppt"
+#define ATTR_PPT_PL3_FPPT "ppt_pl3_fppt"
+#define ATTR_PPT_APU_SPPT "ppt_apu_sppt"
+#define ATTR_PPT_PLATFORM_SPPT "ppt_platform_sppt"
+#define ATTR_NV_DYNAMIC_BOOST "nv_dynamic_boost"
+#define ATTR_NV_TEMP_TARGET "nv_temp_target"
+#define ATTR_NV_BASE_TGP "nv_base_tgp"
+#define ATTR_NV_TGP "nv_tgp"
+
+#define ASUS_ROG_TUNABLE_DC 0
+#define ASUS_ROG_TUNABLE_AC 1
+
+struct rog_tunables {
+ const struct power_limits *power_limits;
+ u32 ppt_pl1_spl; // cpu
+ u32 ppt_pl2_sppt; // cpu
+ u32 ppt_pl3_fppt; // cpu
+ u32 ppt_apu_sppt; // plat
+ u32 ppt_platform_sppt; // plat
+
+ u32 nv_dynamic_boost;
+ u32 nv_temp_target;
+ u32 nv_tgp;
+};
+
+struct asus_armoury_priv {
+ struct device *fw_attr_dev;
+ struct kset *fw_attr_kset;
+
+ /*
+ * Mutex to protect eGPU activation/deactivation
+ * sequences and dGPU connection status:
+ * do not allow concurrent changes or changes
+ * before a reboot if dGPU got disabled.
+ */
+ struct mutex egpu_mutex;
+
+ /* Index 0 for DC, 1 for AC */
+ struct rog_tunables *rog_tunables[2];
+
+ u32 mini_led_dev_id;
+ u32 gpu_mux_dev_id;
+};
+
+static struct asus_armoury_priv asus_armoury = {
+ .egpu_mutex = __MUTEX_INITIALIZER(asus_armoury.egpu_mutex),
+};
+
+struct fw_attrs_group {
+ bool pending_reboot;
+};
+
+static struct fw_attrs_group fw_attrs = {
+ .pending_reboot = false,
+};
+
+struct asus_attr_group {
+ const struct attribute_group *attr_group;
+ u32 wmi_devid;
+};
+
+static void asus_set_reboot_and_signal_event(void)
+{
+ fw_attrs.pending_reboot = true;
+ kobject_uevent(&asus_armoury.fw_attr_dev->kobj, KOBJ_CHANGE);
+}
+
+static ssize_t pending_reboot_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+ return sysfs_emit(buf, "%d\n", fw_attrs.pending_reboot);
+}
+
+static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot);
+
+static bool asus_bios_requires_reboot(struct kobj_attribute *attr)
+{
+ return !strcmp(attr->attr.name, "gpu_mux_mode") ||
+ !strcmp(attr->attr.name, "panel_hd_mode");
+}
+
+/**
+ * armoury_has_devstate() - Check presence of the WMI function state.
+ *
+ * @dev_id: The WMI method ID to check for presence.
+ *
+ * Returns: true iif method is supported.
+ */
+static bool armoury_has_devstate(u32 dev_id)
+{
+ u32 retval;
+ int status;
+
+ status = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, dev_id, 0, &retval);
+ pr_debug("%s called (0x%08x), retval: 0x%08x\n", __func__, dev_id, retval);
+
+ return status == 0 && (retval & ASUS_WMI_DSTS_PRESENCE_BIT);
+}
+
+/**
+ * armoury_get_devstate() - Get the WMI function state.
+ * @attr: NULL or the kobj_attribute associated to called WMI function.
+ * @dev_id: The WMI method ID to call.
+ * @retval:
+ * * non-NULL pointer to where to store the value returned from WMI
+ * * with the function presence bit cleared.
+ *
+ * Intended usage is from sysfs attribute checking associated WMI function.
+ *
+ * Returns:
+ * * %-ENODEV - method ID is unsupported.
+ * * %0 - successful and retval is filled.
+ * * %other - error from WMI call.
+ */
+static int armoury_get_devstate(struct kobj_attribute *attr, u32 *retval, u32 dev_id)
+{
+ int err;
+
+ err = asus_wmi_get_devstate_dsts(dev_id, retval);
+ if (err) {
+ if (attr)
+ pr_err("Failed to get %s: %d\n", attr->attr.name, err);
+ else
+ pr_err("Failed to get devstate for 0x%x: %d\n", dev_id, err);
+
+ return err;
+ }
+
+ /*
+ * asus_wmi_get_devstate_dsts will populate retval with WMI return, but
+ * the true value is expressed when ASUS_WMI_DSTS_PRESENCE_BIT is clear.
+ */
+ *retval &= ~ASUS_WMI_DSTS_PRESENCE_BIT;
+
+ return 0;
+}
+
+/**
+ * armoury_set_devstate() - Set the WMI function state.
+ * @attr: The kobj_attribute associated to called WMI function.
+ * @dev_id: The WMI method ID to call.
+ * @value: The new value to be set.
+ * @retval: Where to store the value returned from WMI or NULL.
+ *
+ * Intended usage is from sysfs attribute setting associated WMI function.
+ * Before calling the presence of the function should be checked.
+ *
+ * Every WMI write MUST go through this function to enforce safety checks.
+ *
+ * Results !1 is usually considered a fail by ASUS, but some WMI methods
+ * (like eGPU or CPU cores) do use > 1 to return a status code or similar:
+ * in these cases caller is interested in the actual return value
+ * and should perform relevant checks.
+ *
+ * Returns:
+ * * %-EINVAL - attempt to set a dangerous or unsupported value.
+ * * %-EIO - WMI function returned an error.
+ * * %0 - successful and retval is filled.
+ * * %other - error from WMI call.
+ */
+static int armoury_set_devstate(struct kobj_attribute *attr,
+ u32 value, u32 *retval, u32 dev_id)
+{
+ u32 result;
+ int err;
+
+ /*
+ * Prevent developers from bricking devices or issuing dangerous
+ * commands that can be difficult or impossible to recover from.
+ */
+ switch (dev_id) {
+ case ASUS_WMI_DEVID_APU_MEM:
+ /*
+ * A hard reset might suffice to save the device,
+ * but there is no value in sending these commands.
+ */
+ if (value == 0x100 || value == 0x101) {
+ pr_err("Refusing to set APU memory to unsafe value: 0x%x\n", value);
+ return -EINVAL;
+ }
+ break;
+ default:
+ /* No problems are known for this dev_id */
+ break;
+ }
+
+ err = asus_wmi_set_devstate(dev_id, value, retval ? retval : &result);
+ if (err) {
+ if (attr)
+ pr_err("Failed to set %s: %d\n", attr->attr.name, err);
+ else
+ pr_err("Failed to set devstate for 0x%x: %d\n", dev_id, err);
+
+ return err;
+ }
+
+ /*
+ * If retval == NULL caller is uninterested in return value:
+ * perform the most common result check here.
+ */
+ if ((retval == NULL) && (result == 0)) {
+ pr_err("Failed to set %s: (result): 0x%x\n", attr->attr.name, result);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int armoury_attr_enum_list(char *buf, size_t enum_values)
+{
+ size_t i;
+ int len = 0;
+
+ for (i = 0; i < enum_values; i++) {
+ if (i == 0)
+ len += sysfs_emit_at(buf, len, "%zu", i);
+ else
+ len += sysfs_emit_at(buf, len, ";%zu", i);
+ }
+ len += sysfs_emit_at(buf, len, "\n");
+
+ return len;
+}
+
+ssize_t armoury_attr_uint_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count, u32 min, u32 max,
+ u32 *store_value, u32 wmi_dev)
+{
+ u32 value;
+ int err;
+
+ err = kstrtou32(buf, 10, &value);
+ if (err)
+ return err;
+
+ if (value < min || value > max)
+ return -EINVAL;
+
+ err = armoury_set_devstate(attr, value, NULL, wmi_dev);
+ if (err)
+ return err;
+
+ if (store_value != NULL)
+ *store_value = value;
+ sysfs_notify(kobj, NULL, attr->attr.name);
+
+ if (asus_bios_requires_reboot(attr))
+ asus_set_reboot_and_signal_event();
+
+ return count;
+}
+
+ssize_t armoury_attr_uint_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf, u32 wmi_dev)
+{
+ u32 result;
+ int err;
+
+ err = armoury_get_devstate(attr, &result, wmi_dev);
+ if (err)
+ return err;
+
+ return sysfs_emit(buf, "%u\n", result);
+}
+
+static ssize_t enum_type_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ return sysfs_emit(buf, "enumeration\n");
+}
+
+static ssize_t int_type_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ return sysfs_emit(buf, "integer\n");
+}
+
+/* Mini-LED mode **************************************************************/
+
+/* Values map for mini-led modes on 2023 and earlier models. */
+static u32 mini_led_mode1_map[] = {
+ [0] = ASUS_MINI_LED_OFF,
+ [1] = ASUS_MINI_LED_ON,
+};
+
+/* Values map for mini-led modes on 2024 and later models. */
+static u32 mini_led_mode2_map[] = {
+ [0] = ASUS_MINI_LED_2024_OFF,
+ [1] = ASUS_MINI_LED_2024_WEAK,
+ [2] = ASUS_MINI_LED_2024_STRONG,
+};
+
+static ssize_t mini_led_mode_current_value_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ u32 *mini_led_mode_map;
+ size_t mini_led_mode_map_size;
+ u32 i, mode;
+ int err;
+
+ switch (asus_armoury.mini_led_dev_id) {
+ case ASUS_WMI_DEVID_MINI_LED_MODE:
+ mini_led_mode_map = mini_led_mode1_map;
+ mini_led_mode_map_size = ARRAY_SIZE(mini_led_mode1_map);
+ break;
+
+ case ASUS_WMI_DEVID_MINI_LED_MODE2:
+ mini_led_mode_map = mini_led_mode2_map;
+ mini_led_mode_map_size = ARRAY_SIZE(mini_led_mode2_map);
+ break;
+
+ default:
+ pr_err("Unrecognized mini-LED device: %u\n", asus_armoury.mini_led_dev_id);
+ return -ENODEV;
+ }
+
+ err = armoury_get_devstate(attr, &mode, asus_armoury.mini_led_dev_id);
+ if (err)
+ return err;
+
+ mode = FIELD_GET(ASUS_MINI_LED_MODE_MASK, 0);
+
+ for (i = 0; i < mini_led_mode_map_size; i++)
+ if (mode == mini_led_mode_map[i])
+ return sysfs_emit(buf, "%u\n", i);
+
+ pr_warn("Unrecognized mini-LED mode: %u", mode);
+ return -EINVAL;
+}
+
+static ssize_t mini_led_mode_current_value_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ u32 *mini_led_mode_map;
+ size_t mini_led_mode_map_size;
+ u32 mode;
+ int err;
+
+ err = kstrtou32(buf, 10, &mode);
+ if (err)
+ return err;
+
+ switch (asus_armoury.mini_led_dev_id) {
+ case ASUS_WMI_DEVID_MINI_LED_MODE:
+ mini_led_mode_map = mini_led_mode1_map;
+ mini_led_mode_map_size = ARRAY_SIZE(mini_led_mode1_map);
+ break;
+
+ case ASUS_WMI_DEVID_MINI_LED_MODE2:
+ mini_led_mode_map = mini_led_mode2_map;
+ mini_led_mode_map_size = ARRAY_SIZE(mini_led_mode2_map);
+ break;
+
+ default:
+ pr_err("Unrecognized mini-LED devid: %u\n", asus_armoury.mini_led_dev_id);
+ return -EINVAL;
+ }
+
+ if (mode >= mini_led_mode_map_size) {
+ pr_warn("mini-LED mode unrecognized device: %u\n", mode);
+ return -ENODEV;
+ }
+
+ return armoury_attr_uint_store(kobj, attr, buf, count,
+ 0, mini_led_mode_map[mode],
+ NULL, asus_armoury.mini_led_dev_id);
+}
+
+static ssize_t mini_led_mode_possible_values_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ switch (asus_armoury.mini_led_dev_id) {
+ case ASUS_WMI_DEVID_MINI_LED_MODE:
+ return armoury_attr_enum_list(buf, ARRAY_SIZE(mini_led_mode1_map));
+ case ASUS_WMI_DEVID_MINI_LED_MODE2:
+ return armoury_attr_enum_list(buf, ARRAY_SIZE(mini_led_mode2_map));
+ default:
+ return -ENODEV;
+ }
+}
+ASUS_ATTR_GROUP_ENUM(mini_led_mode, "mini_led_mode", "Set the mini-LED backlight mode");
+
+static ssize_t gpu_mux_mode_current_value_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ int result, err;
+ bool optimus;
+
+ err = kstrtobool(buf, &optimus);
+ if (err)
+ return err;
+
+ if (armoury_has_devstate(ASUS_WMI_DEVID_DGPU)) {
+ err = armoury_get_devstate(NULL, &result, ASUS_WMI_DEVID_DGPU);
+ if (err)
+ return err;
+ if (result && !optimus) {
+ pr_warn("Cannot switch MUX to dGPU mode when dGPU is disabled: %02X\n",
+ result);
+ return -ENODEV;
+ }
+ }
+
+ if (armoury_has_devstate(ASUS_WMI_DEVID_EGPU)) {
+ err = armoury_get_devstate(NULL, &result, ASUS_WMI_DEVID_EGPU);
+ if (err)
+ return err;
+ if (result && !optimus) {
+ pr_warn("Cannot switch MUX to dGPU mode when eGPU is enabled\n");
+ return -EBUSY;
+ }
+ }
+
+ err = armoury_set_devstate(attr, optimus ? 1 : 0, NULL, asus_armoury.gpu_mux_dev_id);
+ if (err)
+ return err;
+
+ sysfs_notify(kobj, NULL, attr->attr.name);
+ asus_set_reboot_and_signal_event();
+
+ return count;
+}
+ASUS_WMI_SHOW_INT(gpu_mux_mode_current_value, asus_armoury.gpu_mux_dev_id);
+ASUS_ATTR_GROUP_BOOL(gpu_mux_mode, "gpu_mux_mode", "Set the GPU display MUX mode");
+
+static ssize_t dgpu_disable_current_value_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf,
+ size_t count)
+{
+ int result, err;
+ bool disable;
+
+ err = kstrtobool(buf, &disable);
+ if (err)
+ return err;
+
+ if (asus_armoury.gpu_mux_dev_id) {
+ err = armoury_get_devstate(NULL, &result, asus_armoury.gpu_mux_dev_id);
+ if (err)
+ return err;
+ if (!result && disable) {
+ pr_warn("Cannot disable dGPU when the MUX is in dGPU mode\n");
+ return -EBUSY;
+ }
+ }
+
+ scoped_guard(mutex, &asus_armoury.egpu_mutex) {
+ err = armoury_set_devstate(attr, disable ? 1 : 0, NULL, ASUS_WMI_DEVID_DGPU);
+ if (err)
+ return err;
+ }
+
+ sysfs_notify(kobj, NULL, attr->attr.name);
+
+ return count;
+}
+ASUS_WMI_SHOW_INT(dgpu_disable_current_value, ASUS_WMI_DEVID_DGPU);
+ASUS_ATTR_GROUP_BOOL(dgpu_disable, "dgpu_disable", "Disable the dGPU");
+
+/* Values map for eGPU activation requests. */
+static u32 egpu_status_map[] = {
+ [0] = 0x00000000U,
+ [1] = 0x00000001U,
+ [2] = 0x00000101U,
+ [3] = 0x00000201U,
+};
+
+/*
+ * armoury_pci_rescan() - Performs a PCI rescan
+ *
+ * Bring up any GPU that has been hotplugged in the system.
+ */
+static void armoury_pci_rescan(void)
+{
+ struct pci_bus *b = NULL;
+
+ pci_lock_rescan_remove();
+ while ((b = pci_find_next_bus(b)) != NULL)
+ pci_rescan_bus(b);
+ pci_unlock_rescan_remove();
+}
+
+/*
+ * The ACPI call to enable the eGPU might also disable the internal dGPU,
+ * but this is not always the case and on certain models enabling the eGPU
+ * when the dGPU is either still active or has been disabled without rebooting
+ * will make both GPUs malfunction and the kernel will detect many
+ * PCI AER unrecoverable errors.
+ */
+static ssize_t egpu_enable_current_value_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ int err;
+ u32 requested, enable, result;
+
+ err = kstrtou32(buf, 10, &requested);
+ if (err)
+ return err;
+
+ if (requested >= ARRAY_SIZE(egpu_status_map))
+ return -EINVAL;
+ enable = egpu_status_map[requested];
+
+ scoped_guard(mutex, &asus_armoury.egpu_mutex) {
+ /* Ensure the eGPU is connected before attempting to activate it. */
+ if (enable) {
+ err = armoury_get_devstate(NULL, &result, ASUS_WMI_DEVID_EGPU_CONNECTED);
+ if (err) {
+ pr_warn("Failed to get eGPU connection status: %d\n", err);
+ return err;
+ }
+ if (!result) {
+ pr_warn("Cannot activate eGPU while undetected\n");
+ return -ENOENT;
+ }
+ }
+
+ if (asus_armoury.gpu_mux_dev_id) {
+ err = armoury_get_devstate(NULL, &result, asus_armoury.gpu_mux_dev_id);
+ if (err)
+ return err;
+
+ if (!result && enable) {
+ pr_warn("Cannot enable eGPU when the MUX is in dGPU mode\n");
+ return -ENODEV;
+ }
+ }
+
+ err = armoury_set_devstate(attr, enable, &result, ASUS_WMI_DEVID_EGPU);
+ if (err) {
+ pr_err("Failed to set %s: %d\n", attr->attr.name, err);
+ return err;
+ }
+
+ /*
+ * ACPI returns value 0x01 on success and 0x02 on a partial activation:
+ * performing a pci rescan will bring up the device in pci-e 3.0 speed,
+ * after a reboot the device will work at full speed.
+ */
+ switch (result) {
+ case 0x01:
+ /*
+ * When a GPU is in use it does not get disconnected even if
+ * the ACPI call returns a success.
+ */
+ if (!enable) {
+ err = armoury_get_devstate(attr, &result, ASUS_WMI_DEVID_EGPU);
+ if (err) {
+ pr_warn("Failed to ensure eGPU is deactivated: %d\n", err);
+ return err;
+ }
+
+ if (result != 0)
+ return -EBUSY;
+ }
+
+ pr_debug("Success changing the eGPU status\n");
+ break;
+ case 0x02:
+ pr_info("Success changing the eGPU status, a reboot is strongly advised\n");
+ asus_set_reboot_and_signal_event();
+ break;
+ default:
+ pr_err("Failed to change the eGPU status: wmi result is 0x%x\n", result);
+ return -EIO;
+ }
+ }
+
+ /*
+ * Perform a PCI rescan: on every tested model this is necessary
+ * to make the eGPU visible on the bus without rebooting.
+ */
+ armoury_pci_rescan();
+
+ sysfs_notify(kobj, NULL, attr->attr.name);
+
+ return count;
+}
+
+static ssize_t egpu_enable_current_value_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ int i, err;
+ u32 status;
+
+ scoped_guard(mutex, &asus_armoury.egpu_mutex) {
+ err = armoury_get_devstate(attr, &status, ASUS_WMI_DEVID_EGPU);
+ if (err)
+ return err;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(egpu_status_map); i++) {
+ if (egpu_status_map[i] == status)
+ return sysfs_emit(buf, "%u\n", i);
+ }
+
+ return -EIO;
+}
+
+static ssize_t egpu_enable_possible_values_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ return armoury_attr_enum_list(buf, ARRAY_SIZE(egpu_status_map));
+}
+ASUS_ATTR_GROUP_ENUM(egpu_enable, "egpu_enable", "Enable the eGPU (also disables dGPU)");
+
+/* Device memory available to APU */
+
+/*
+ * Values map for APU reserved memory (index + 1 number of GB).
+ * Some looks out of order, but are actually correct.
+ */
+static u32 apu_mem_map[] = {
+ [0] = 0x000, /* called "AUTO" on the BIOS, is the minimum available */
+ [1] = 0x102,
+ [2] = 0x103,
+ [3] = 0x104,
+ [4] = 0x105,
+ [5] = 0x107,
+ [6] = 0x108,
+ [7] = 0x109,
+ [8] = 0x106,
+};
+
+static ssize_t apu_mem_current_value_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ int err;
+ u32 mem;
+
+ err = armoury_get_devstate(attr, &mem, ASUS_WMI_DEVID_APU_MEM);
+ if (err)
+ return err;
+
+ /* After 0x000 is set, a read will return 0x100 */
+ if (mem == 0x100)
+ return sysfs_emit(buf, "0\n");
+
+ for (unsigned int i = 0; i < ARRAY_SIZE(apu_mem_map); i++) {
+ if (apu_mem_map[i] == mem)
+ return sysfs_emit(buf, "%u\n", i);
+ }
+
+ pr_warn("Unrecognised value for APU mem 0x%08x\n", mem);
+ return -EIO;
+}
+
+static ssize_t apu_mem_current_value_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ int result, err;
+ u32 requested, mem;
+
+ result = kstrtou32(buf, 10, &requested);
+ if (result)
+ return result;
+
+ if (requested >= ARRAY_SIZE(apu_mem_map))
+ return -EINVAL;
+ mem = apu_mem_map[requested];
+
+ err = armoury_set_devstate(attr, mem, NULL, ASUS_WMI_DEVID_APU_MEM);
+ if (err) {
+ pr_warn("Failed to set apu_mem 0x%x: %d\n", mem, err);
+ return err;
+ }
+
+ pr_info("APU memory changed to %uGB, reboot required\n", requested + 1);
+ sysfs_notify(kobj, NULL, attr->attr.name);
+
+ asus_set_reboot_and_signal_event();
+
+ return count;
+}
+
+static ssize_t apu_mem_possible_values_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ return armoury_attr_enum_list(buf, ARRAY_SIZE(apu_mem_map));
+}
+ASUS_ATTR_GROUP_ENUM(apu_mem, "apu_mem", "Set available system RAM (in GB) for the APU to use");
+
+/* Define helper to access the current power mode tunable values */
+static inline struct rog_tunables *get_current_tunables(void)
+{
+ if (power_supply_is_system_supplied())
+ return asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC];
+
+ return asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC];
+}
+
+/* Simple attribute creation */
+ASUS_ATTR_GROUP_ENUM_INT_RO(charge_mode, "charge_mode", ASUS_WMI_DEVID_CHARGE_MODE, "0;1;2\n",
+ "Show the current mode of charging");
+ASUS_ATTR_GROUP_BOOL_RW(boot_sound, "boot_sound", ASUS_WMI_DEVID_BOOT_SOUND,
+ "Set the boot POST sound");
+ASUS_ATTR_GROUP_BOOL_RW(mcu_powersave, "mcu_powersave", ASUS_WMI_DEVID_MCU_POWERSAVE,
+ "Set MCU powersaving mode");
+ASUS_ATTR_GROUP_BOOL_RW(panel_od, "panel_overdrive", ASUS_WMI_DEVID_PANEL_OD,
+ "Set the panel refresh overdrive");
+ASUS_ATTR_GROUP_BOOL_RW(panel_hd_mode, "panel_hd_mode", ASUS_WMI_DEVID_PANEL_HD,
+ "Set the panel HD mode to UHD<0> or FHD<1>");
+ASUS_ATTR_GROUP_BOOL_RW(screen_auto_brightness, "screen_auto_brightness",
+ ASUS_WMI_DEVID_SCREEN_AUTO_BRIGHTNESS,
+ "Set the panel brightness to Off<0> or On<1>");
+ASUS_ATTR_GROUP_BOOL_RO(egpu_connected, "egpu_connected", ASUS_WMI_DEVID_EGPU_CONNECTED,
+ "Show the eGPU connection status");
+ASUS_ATTR_GROUP_ROG_TUNABLE(ppt_pl1_spl, ATTR_PPT_PL1_SPL, ASUS_WMI_DEVID_PPT_PL1_SPL,
+ "Set the CPU slow package limit");
+ASUS_ATTR_GROUP_ROG_TUNABLE(ppt_pl2_sppt, ATTR_PPT_PL2_SPPT, ASUS_WMI_DEVID_PPT_PL2_SPPT,
+ "Set the CPU fast package limit");
+ASUS_ATTR_GROUP_ROG_TUNABLE(ppt_pl3_fppt, ATTR_PPT_PL3_FPPT, ASUS_WMI_DEVID_PPT_PL3_FPPT,
+ "Set the CPU fastest package limit");
+ASUS_ATTR_GROUP_ROG_TUNABLE(ppt_apu_sppt, ATTR_PPT_APU_SPPT, ASUS_WMI_DEVID_PPT_APU_SPPT,
+ "Set the APU package limit");
+ASUS_ATTR_GROUP_ROG_TUNABLE(ppt_platform_sppt, ATTR_PPT_PLATFORM_SPPT, ASUS_WMI_DEVID_PPT_PLAT_SPPT,
+ "Set the platform package limit");
+ASUS_ATTR_GROUP_ROG_TUNABLE(nv_dynamic_boost, ATTR_NV_DYNAMIC_BOOST, ASUS_WMI_DEVID_NV_DYN_BOOST,
+ "Set the Nvidia dynamic boost limit");
+ASUS_ATTR_GROUP_ROG_TUNABLE(nv_temp_target, ATTR_NV_TEMP_TARGET, ASUS_WMI_DEVID_NV_THERM_TARGET,
+ "Set the Nvidia max thermal limit");
+ASUS_ATTR_GROUP_ROG_TUNABLE(nv_tgp, "nv_tgp", ASUS_WMI_DEVID_DGPU_SET_TGP,
+ "Set the additional TGP on top of the base TGP");
+ASUS_ATTR_GROUP_INT_VALUE_ONLY_RO(nv_base_tgp, ATTR_NV_BASE_TGP, ASUS_WMI_DEVID_DGPU_BASE_TGP,
+ "Read the base TGP value");
+
+/* If an attribute does not require any special case handling add it here */
+static const struct asus_attr_group armoury_attr_groups[] = {
+ { &egpu_connected_attr_group, ASUS_WMI_DEVID_EGPU_CONNECTED },
+ { &egpu_enable_attr_group, ASUS_WMI_DEVID_EGPU },
+ { &dgpu_disable_attr_group, ASUS_WMI_DEVID_DGPU },
+ { &apu_mem_attr_group, ASUS_WMI_DEVID_APU_MEM },
+
+ { &ppt_pl1_spl_attr_group, ASUS_WMI_DEVID_PPT_PL1_SPL },
+ { &ppt_pl2_sppt_attr_group, ASUS_WMI_DEVID_PPT_PL2_SPPT },
+ { &ppt_pl3_fppt_attr_group, ASUS_WMI_DEVID_PPT_PL3_FPPT },
+ { &ppt_apu_sppt_attr_group, ASUS_WMI_DEVID_PPT_APU_SPPT },
+ { &ppt_platform_sppt_attr_group, ASUS_WMI_DEVID_PPT_PLAT_SPPT },
+ { &nv_dynamic_boost_attr_group, ASUS_WMI_DEVID_NV_DYN_BOOST },
+ { &nv_temp_target_attr_group, ASUS_WMI_DEVID_NV_THERM_TARGET },
+ { &nv_base_tgp_attr_group, ASUS_WMI_DEVID_DGPU_BASE_TGP },
+ { &nv_tgp_attr_group, ASUS_WMI_DEVID_DGPU_SET_TGP },
+
+ { &charge_mode_attr_group, ASUS_WMI_DEVID_CHARGE_MODE },
+ { &boot_sound_attr_group, ASUS_WMI_DEVID_BOOT_SOUND },
+ { &mcu_powersave_attr_group, ASUS_WMI_DEVID_MCU_POWERSAVE },
+ { &panel_od_attr_group, ASUS_WMI_DEVID_PANEL_OD },
+ { &panel_hd_mode_attr_group, ASUS_WMI_DEVID_PANEL_HD },
+ { &screen_auto_brightness_attr_group, ASUS_WMI_DEVID_SCREEN_AUTO_BRIGHTNESS },
+};
+
+/**
+ * is_power_tunable_attr - Determines if an attribute is a power-related tunable
+ * @name: The name of the attribute to check
+ *
+ * This function checks if the given attribute name is related to power tuning.
+ *
+ * Return: true if the attribute is a power-related tunable, false otherwise
+ */
+static bool is_power_tunable_attr(const char *name)
+{
+ static const char * const power_tunable_attrs[] = {
+ ATTR_PPT_PL1_SPL, ATTR_PPT_PL2_SPPT,
+ ATTR_PPT_PL3_FPPT, ATTR_PPT_APU_SPPT,
+ ATTR_PPT_PLATFORM_SPPT, ATTR_NV_DYNAMIC_BOOST,
+ ATTR_NV_TEMP_TARGET, ATTR_NV_BASE_TGP,
+ ATTR_NV_TGP
+ };
+
+ for (unsigned int i = 0; i < ARRAY_SIZE(power_tunable_attrs); i++) {
+ if (!strcmp(name, power_tunable_attrs[i]))
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * has_valid_limit - Checks if a power-related attribute has a valid limit value
+ * @name: The name of the attribute to check
+ * @limits: Pointer to the power_limits structure containing limit values
+ *
+ * This function checks if a power-related attribute has a valid limit value.
+ * It returns false if limits is NULL or if the corresponding limit value is zero.
+ *
+ * Return: true if the attribute has a valid limit value, false otherwise
+ */
+static bool has_valid_limit(const char *name, const struct power_limits *limits)
+{
+ u32 limit_value = 0;
+
+ if (!limits)
+ return false;
+
+ if (!strcmp(name, ATTR_PPT_PL1_SPL))
+ limit_value = limits->ppt_pl1_spl_max;
+ else if (!strcmp(name, ATTR_PPT_PL2_SPPT))
+ limit_value = limits->ppt_pl2_sppt_max;
+ else if (!strcmp(name, ATTR_PPT_PL3_FPPT))
+ limit_value = limits->ppt_pl3_fppt_max;
+ else if (!strcmp(name, ATTR_PPT_APU_SPPT))
+ limit_value = limits->ppt_apu_sppt_max;
+ else if (!strcmp(name, ATTR_PPT_PLATFORM_SPPT))
+ limit_value = limits->ppt_platform_sppt_max;
+ else if (!strcmp(name, ATTR_NV_DYNAMIC_BOOST))
+ limit_value = limits->nv_dynamic_boost_max;
+ else if (!strcmp(name, ATTR_NV_TEMP_TARGET))
+ limit_value = limits->nv_temp_target_max;
+ else if (!strcmp(name, ATTR_NV_BASE_TGP) ||
+ !strcmp(name, ATTR_NV_TGP))
+ limit_value = limits->nv_tgp_max;
+
+ return limit_value > 0;
+}
+
+static int asus_fw_attr_add(void)
+{
+ const struct rog_tunables *const ac_rog_tunables =
+ asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC];
+ const struct power_limits *limits;
+ bool should_create;
+ const char *name;
+ int err, i;
+
+ asus_armoury.fw_attr_dev = device_create(&firmware_attributes_class, NULL, MKDEV(0, 0),
+ NULL, "%s", DRIVER_NAME);
+ if (IS_ERR(asus_armoury.fw_attr_dev)) {
+ err = PTR_ERR(asus_armoury.fw_attr_dev);
+ goto fail_class_get;
+ }
+
+ asus_armoury.fw_attr_kset = kset_create_and_add("attributes", NULL,
+ &asus_armoury.fw_attr_dev->kobj);
+ if (!asus_armoury.fw_attr_kset) {
+ err = -ENOMEM;
+ goto err_destroy_classdev;
+ }
+
+ err = sysfs_create_file(&asus_armoury.fw_attr_kset->kobj, &pending_reboot.attr);
+ if (err) {
+ pr_err("Failed to create sysfs level attributes\n");
+ goto err_destroy_kset;
+ }
+
+ asus_armoury.mini_led_dev_id = 0;
+ if (armoury_has_devstate(ASUS_WMI_DEVID_MINI_LED_MODE))
+ asus_armoury.mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE;
+ else if (armoury_has_devstate(ASUS_WMI_DEVID_MINI_LED_MODE2))
+ asus_armoury.mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE2;
+
+ if (asus_armoury.mini_led_dev_id) {
+ err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj,
+ &mini_led_mode_attr_group);
+ if (err) {
+ pr_err("Failed to create sysfs-group for mini_led\n");
+ goto err_remove_file;
+ }
+ }
+
+ asus_armoury.gpu_mux_dev_id = 0;
+ if (armoury_has_devstate(ASUS_WMI_DEVID_GPU_MUX))
+ asus_armoury.gpu_mux_dev_id = ASUS_WMI_DEVID_GPU_MUX;
+ else if (armoury_has_devstate(ASUS_WMI_DEVID_GPU_MUX_VIVO))
+ asus_armoury.gpu_mux_dev_id = ASUS_WMI_DEVID_GPU_MUX_VIVO;
+
+ if (asus_armoury.gpu_mux_dev_id) {
+ err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj,
+ &gpu_mux_mode_attr_group);
+ if (err) {
+ pr_err("Failed to create sysfs-group for gpu_mux\n");
+ goto err_remove_mini_led_group;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(armoury_attr_groups); i++) {
+ if (!armoury_has_devstate(armoury_attr_groups[i].wmi_devid))
+ continue;
+
+ /* Always create by default, unless PPT is not present */
+ should_create = true;
+ name = armoury_attr_groups[i].attr_group->name;
+
+ /* Check if this is a power-related tunable requiring limits */
+ if (ac_rog_tunables && ac_rog_tunables->power_limits &&
+ is_power_tunable_attr(name)) {
+ limits = ac_rog_tunables->power_limits;
+ /* Check only AC: if not present then DC won't be either */
+ should_create = has_valid_limit(name, limits);
+ if (!should_create)
+ pr_debug("Missing max value for tunable %s\n", name);
+ }
+
+ if (should_create) {
+ err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj,
+ armoury_attr_groups[i].attr_group);
+ if (err) {
+ pr_err("Failed to create sysfs-group for %s\n",
+ armoury_attr_groups[i].attr_group->name);
+ goto err_remove_groups;
+ }
+ }
+ }
+
+ return 0;
+
+err_remove_groups:
+ while (i--) {
+ if (armoury_has_devstate(armoury_attr_groups[i].wmi_devid))
+ sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj,
+ armoury_attr_groups[i].attr_group);
+ }
+ if (asus_armoury.gpu_mux_dev_id)
+ sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &gpu_mux_mode_attr_group);
+err_remove_mini_led_group:
+ if (asus_armoury.mini_led_dev_id)
+ sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &mini_led_mode_attr_group);
+err_remove_file:
+ sysfs_remove_file(&asus_armoury.fw_attr_kset->kobj, &pending_reboot.attr);
+err_destroy_kset:
+ kset_unregister(asus_armoury.fw_attr_kset);
+err_destroy_classdev:
+fail_class_get:
+ device_destroy(&firmware_attributes_class, MKDEV(0, 0));
+ return err;
+}
+
+/* Init / exit ****************************************************************/
+
+/* Set up the min/max and defaults for ROG tunables */
+static void init_rog_tunables(void)
+{
+ const struct power_limits *ac_limits, *dc_limits;
+ struct rog_tunables *ac_rog_tunables = NULL, *dc_rog_tunables = NULL;
+ const struct power_data *power_data;
+ const struct dmi_system_id *dmi_id;
+
+ /* Match the system against the power_limits table */
+ dmi_id = dmi_first_match(power_limits);
+ if (!dmi_id) {
+ pr_warn("No matching power limits found for this system\n");
+ return;
+ }
+
+ /* Get the power data for this system */
+ power_data = dmi_id->driver_data;
+ if (!power_data) {
+ pr_info("No power data available for this system\n");
+ return;
+ }
+
+ /* Initialize AC power tunables */
+ ac_limits = power_data->ac_data;
+ if (ac_limits) {
+ ac_rog_tunables = kzalloc(sizeof(*asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC]),
+ GFP_KERNEL);
+ if (!ac_rog_tunables)
+ goto err_nomem;
+
+ asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC] = ac_rog_tunables;
+ ac_rog_tunables->power_limits = ac_limits;
+
+ /* Set initial AC values */
+ ac_rog_tunables->ppt_pl1_spl =
+ ac_limits->ppt_pl1_spl_def ?
+ ac_limits->ppt_pl1_spl_def :
+ ac_limits->ppt_pl1_spl_max;
+
+ ac_rog_tunables->ppt_pl2_sppt =
+ ac_limits->ppt_pl2_sppt_def ?
+ ac_limits->ppt_pl2_sppt_def :
+ ac_limits->ppt_pl2_sppt_max;
+
+ ac_rog_tunables->ppt_pl3_fppt =
+ ac_limits->ppt_pl3_fppt_def ?
+ ac_limits->ppt_pl3_fppt_def :
+ ac_limits->ppt_pl3_fppt_max;
+
+ ac_rog_tunables->ppt_apu_sppt =
+ ac_limits->ppt_apu_sppt_def ?
+ ac_limits->ppt_apu_sppt_def :
+ ac_limits->ppt_apu_sppt_max;
+
+ ac_rog_tunables->ppt_platform_sppt =
+ ac_limits->ppt_platform_sppt_def ?
+ ac_limits->ppt_platform_sppt_def :
+ ac_limits->ppt_platform_sppt_max;
+
+ ac_rog_tunables->nv_dynamic_boost =
+ ac_limits->nv_dynamic_boost_max;
+ ac_rog_tunables->nv_temp_target =
+ ac_limits->nv_temp_target_max;
+ ac_rog_tunables->nv_tgp = ac_limits->nv_tgp_max;
+
+ pr_debug("AC power limits initialized for %s\n", dmi_id->matches[0].substr);
+ } else {
+ pr_debug("No AC PPT limits defined\n");
+ }
+
+ /* Initialize DC power tunables */
+ dc_limits = power_data->dc_data;
+ if (dc_limits) {
+ dc_rog_tunables = kzalloc(sizeof(*asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC]),
+ GFP_KERNEL);
+ if (!dc_rog_tunables) {
+ kfree(ac_rog_tunables);
+ goto err_nomem;
+ }
+
+ asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC] = dc_rog_tunables;
+ dc_rog_tunables->power_limits = dc_limits;
+
+ /* Set initial DC values */
+ dc_rog_tunables->ppt_pl1_spl =
+ dc_limits->ppt_pl1_spl_def ?
+ dc_limits->ppt_pl1_spl_def :
+ dc_limits->ppt_pl1_spl_max;
+
+ dc_rog_tunables->ppt_pl2_sppt =
+ dc_limits->ppt_pl2_sppt_def ?
+ dc_limits->ppt_pl2_sppt_def :
+ dc_limits->ppt_pl2_sppt_max;
+
+ dc_rog_tunables->ppt_pl3_fppt =
+ dc_limits->ppt_pl3_fppt_def ?
+ dc_limits->ppt_pl3_fppt_def :
+ dc_limits->ppt_pl3_fppt_max;
+
+ dc_rog_tunables->ppt_apu_sppt =
+ dc_limits->ppt_apu_sppt_def ?
+ dc_limits->ppt_apu_sppt_def :
+ dc_limits->ppt_apu_sppt_max;
+
+ dc_rog_tunables->ppt_platform_sppt =
+ dc_limits->ppt_platform_sppt_def ?
+ dc_limits->ppt_platform_sppt_def :
+ dc_limits->ppt_platform_sppt_max;
+
+ dc_rog_tunables->nv_dynamic_boost =
+ dc_limits->nv_dynamic_boost_max;
+ dc_rog_tunables->nv_temp_target =
+ dc_limits->nv_temp_target_max;
+ dc_rog_tunables->nv_tgp = dc_limits->nv_tgp_max;
+
+ pr_debug("DC power limits initialized for %s\n", dmi_id->matches[0].substr);
+ } else {
+ pr_debug("No DC PPT limits defined\n");
+ }
+
+ return;
+
+err_nomem:
+ pr_err("Failed to allocate memory for tunables\n");
+}
+
+static int __init asus_fw_init(void)
+{
+ char *wmi_uid;
+
+ wmi_uid = wmi_get_acpi_device_uid(ASUS_WMI_MGMT_GUID);
+ if (!wmi_uid)
+ return -ENODEV;
+
+ /*
+ * if equal to "ASUSWMI" then it's DCTS that can't be used for this
+ * driver, DSTS is required.
+ */
+ if (!strcmp(wmi_uid, ASUS_ACPI_UID_ASUSWMI))
+ return -ENODEV;
+
+ init_rog_tunables();
+
+ /* Must always be last step to ensure data is available */
+ return asus_fw_attr_add();
+}
+
+static void __exit asus_fw_exit(void)
+{
+ int i;
+
+ for (i = ARRAY_SIZE(armoury_attr_groups) - 1; i >= 0; i--) {
+ if (armoury_has_devstate(armoury_attr_groups[i].wmi_devid))
+ sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj,
+ armoury_attr_groups[i].attr_group);
+ }
+
+ if (asus_armoury.gpu_mux_dev_id)
+ sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &gpu_mux_mode_attr_group);
+
+ if (asus_armoury.mini_led_dev_id)
+ sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &mini_led_mode_attr_group);
+
+ sysfs_remove_file(&asus_armoury.fw_attr_kset->kobj, &pending_reboot.attr);
+ kset_unregister(asus_armoury.fw_attr_kset);
+ device_destroy(&firmware_attributes_class, MKDEV(0, 0));
+
+ kfree(asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC]);
+ kfree(asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC]);
+}
+
+module_init(asus_fw_init);
+module_exit(asus_fw_exit);
+
+MODULE_IMPORT_NS("ASUS_WMI");
+MODULE_AUTHOR("Luke Jones <luke@ljones.dev>");
+MODULE_DESCRIPTION("ASUS BIOS Configuration Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("wmi:" ASUS_NB_WMI_EVENT_GUID);
diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h
new file mode 100644
index 000000000000..a1bb2005c3f3
--- /dev/null
+++ b/drivers/platform/x86/asus-armoury.h
@@ -0,0 +1,1541 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Definitions for kernel modules using asus-armoury driver
+ *
+ * Copyright (c) 2024 Luke Jones <luke@ljones.dev>
+ */
+
+#ifndef _ASUS_ARMOURY_H_
+#define _ASUS_ARMOURY_H_
+
+#include <linux/dmi.h>
+#include <linux/platform_device.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+
+#define DRIVER_NAME "asus-armoury"
+
+/**
+ * armoury_attr_uint_store() - Send an uint to WMI method if within min/max.
+ * @kobj: Pointer to the driver object.
+ * @attr: Pointer to the attribute calling this function.
+ * @buf: The buffer to read from, this is parsed to `uint` type.
+ * @count: Required by sysfs attribute macros, pass in from the callee attr.
+ * @min: Minimum accepted value. Below this returns -EINVAL.
+ * @max: Maximum accepted value. Above this returns -EINVAL.
+ * @store_value: Pointer to where the parsed value should be stored.
+ * @wmi_dev: The WMI function ID to use.
+ *
+ * This function is intended to be generic so it can be called from any "_store"
+ * attribute which works only with integers.
+ *
+ * Integers to be sent to the WMI method is inclusive range checked and
+ * an error returned if out of range.
+ *
+ * If the value is valid and WMI is success then the sysfs attribute is notified
+ * and if asus_bios_requires_reboot() is true then reboot attribute
+ * is also notified.
+ *
+ * Returns: Either count, or an error.
+ */
+ssize_t armoury_attr_uint_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count, u32 min, u32 max,
+ u32 *store_value, u32 wmi_dev);
+
+/**
+ * armoury_attr_uint_show() - Receive an uint from a WMI method.
+ * @kobj: Pointer to the driver object.
+ * @attr: Pointer to the attribute calling this function.
+ * @buf: The buffer to write to, as an `uint` type.
+ * @wmi_dev: The WMI function ID to use.
+ *
+ * This function is intended to be generic so it can be called from any "_show"
+ * attribute which works only with integers.
+ *
+ * Returns: Either count, or an error.
+ */
+ssize_t armoury_attr_uint_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf, u32 wmi_dev);
+
+#define __ASUS_ATTR_RO(_func, _name) \
+ { \
+ .attr = { .name = __stringify(_name), .mode = 0444 }, \
+ .show = _func##_##_name##_show, \
+ }
+
+#define __ASUS_ATTR_RO_AS(_name, _show) \
+ { \
+ .attr = { .name = __stringify(_name), .mode = 0444 }, \
+ .show = _show, \
+ }
+
+#define __ASUS_ATTR_RW(_func, _name) \
+ __ATTR(_name, 0644, _func##_##_name##_show, _func##_##_name##_store)
+
+#define __WMI_STORE_INT(_attr, _min, _max, _wmi) \
+ static ssize_t _attr##_store(struct kobject *kobj, \
+ struct kobj_attribute *attr, \
+ const char *buf, size_t count) \
+ { \
+ return armoury_attr_uint_store(kobj, attr, buf, count, _min, \
+ _max, NULL, _wmi); \
+ }
+
+#define ASUS_WMI_SHOW_INT(_attr, _wmi) \
+ static ssize_t _attr##_show(struct kobject *kobj, \
+ struct kobj_attribute *attr, char *buf) \
+ { \
+ return armoury_attr_uint_show(kobj, attr, buf, _wmi); \
+ }
+
+/* Create functions and attributes for use in other macros or on their own */
+
+/* Shows a formatted static variable */
+#define __ATTR_SHOW_FMT(_prop, _attrname, _fmt, _val) \
+ static ssize_t _attrname##_##_prop##_show( \
+ struct kobject *kobj, struct kobj_attribute *attr, char *buf) \
+ { \
+ return sysfs_emit(buf, _fmt, _val); \
+ } \
+ static struct kobj_attribute attr_##_attrname##_##_prop = \
+ __ASUS_ATTR_RO(_attrname, _prop)
+
+#define __ATTR_RO_INT_GROUP_ENUM(_attrname, _wmi, _fsname, _possible, _dispname)\
+ ASUS_WMI_SHOW_INT(_attrname##_current_value, _wmi); \
+ static struct kobj_attribute attr_##_attrname##_current_value = \
+ __ASUS_ATTR_RO(_attrname, current_value); \
+ __ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \
+ __ATTR_SHOW_FMT(possible_values, _attrname, "%s\n", _possible); \
+ static struct kobj_attribute attr_##_attrname##_type = \
+ __ASUS_ATTR_RO_AS(type, enum_type_show); \
+ static struct attribute *_attrname##_attrs[] = { \
+ &attr_##_attrname##_current_value.attr, \
+ &attr_##_attrname##_display_name.attr, \
+ &attr_##_attrname##_possible_values.attr, \
+ &attr_##_attrname##_type.attr, \
+ NULL \
+ }; \
+ static const struct attribute_group _attrname##_attr_group = { \
+ .name = _fsname, .attrs = _attrname##_attrs \
+ }
+
+#define __ATTR_RW_INT_GROUP_ENUM(_attrname, _minv, _maxv, _wmi, _fsname,\
+ _possible, _dispname) \
+ __WMI_STORE_INT(_attrname##_current_value, _minv, _maxv, _wmi); \
+ ASUS_WMI_SHOW_INT(_attrname##_current_value, _wmi); \
+ static struct kobj_attribute attr_##_attrname##_current_value = \
+ __ASUS_ATTR_RW(_attrname, current_value); \
+ __ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \
+ __ATTR_SHOW_FMT(possible_values, _attrname, "%s\n", _possible); \
+ static struct kobj_attribute attr_##_attrname##_type = \
+ __ASUS_ATTR_RO_AS(type, enum_type_show); \
+ static struct attribute *_attrname##_attrs[] = { \
+ &attr_##_attrname##_current_value.attr, \
+ &attr_##_attrname##_display_name.attr, \
+ &attr_##_attrname##_possible_values.attr, \
+ &attr_##_attrname##_type.attr, \
+ NULL \
+ }; \
+ static const struct attribute_group _attrname##_attr_group = { \
+ .name = _fsname, .attrs = _attrname##_attrs \
+ }
+
+/* Boolean style enumeration, base macro. Requires adding show/store */
+#define __ATTR_GROUP_ENUM(_attrname, _fsname, _possible, _dispname) \
+ __ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \
+ __ATTR_SHOW_FMT(possible_values, _attrname, "%s\n", _possible); \
+ static struct kobj_attribute attr_##_attrname##_type = \
+ __ASUS_ATTR_RO_AS(type, enum_type_show); \
+ static struct attribute *_attrname##_attrs[] = { \
+ &attr_##_attrname##_current_value.attr, \
+ &attr_##_attrname##_display_name.attr, \
+ &attr_##_attrname##_possible_values.attr, \
+ &attr_##_attrname##_type.attr, \
+ NULL \
+ }; \
+ static const struct attribute_group _attrname##_attr_group = { \
+ .name = _fsname, .attrs = _attrname##_attrs \
+ }
+
+#define ASUS_ATTR_GROUP_BOOL_RO(_attrname, _fsname, _wmi, _dispname) \
+ __ATTR_RO_INT_GROUP_ENUM(_attrname, _wmi, _fsname, "0;1", _dispname)
+
+
+#define ASUS_ATTR_GROUP_BOOL_RW(_attrname, _fsname, _wmi, _dispname) \
+ __ATTR_RW_INT_GROUP_ENUM(_attrname, 0, 1, _wmi, _fsname, "0;1", _dispname)
+
+#define ASUS_ATTR_GROUP_ENUM_INT_RO(_attrname, _fsname, _wmi, _possible, _dispname) \
+ __ATTR_RO_INT_GROUP_ENUM(_attrname, _wmi, _fsname, _possible, _dispname)
+
+/*
+ * Requires <name>_current_value_show(), <name>_current_value_show()
+ */
+#define ASUS_ATTR_GROUP_BOOL(_attrname, _fsname, _dispname) \
+ static struct kobj_attribute attr_##_attrname##_current_value = \
+ __ASUS_ATTR_RW(_attrname, current_value); \
+ __ATTR_GROUP_ENUM(_attrname, _fsname, "0;1", _dispname)
+
+/*
+ * Requires <name>_current_value_show(), <name>_current_value_show()
+ * and <name>_possible_values_show()
+ */
+#define ASUS_ATTR_GROUP_ENUM(_attrname, _fsname, _dispname) \
+ __ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \
+ static struct kobj_attribute attr_##_attrname##_current_value = \
+ __ASUS_ATTR_RW(_attrname, current_value); \
+ static struct kobj_attribute attr_##_attrname##_possible_values = \
+ __ASUS_ATTR_RO(_attrname, possible_values); \
+ static struct kobj_attribute attr_##_attrname##_type = \
+ __ASUS_ATTR_RO_AS(type, enum_type_show); \
+ static struct attribute *_attrname##_attrs[] = { \
+ &attr_##_attrname##_current_value.attr, \
+ &attr_##_attrname##_display_name.attr, \
+ &attr_##_attrname##_possible_values.attr, \
+ &attr_##_attrname##_type.attr, \
+ NULL \
+ }; \
+ static const struct attribute_group _attrname##_attr_group = { \
+ .name = _fsname, .attrs = _attrname##_attrs \
+ }
+
+#define ASUS_ATTR_GROUP_INT_VALUE_ONLY_RO(_attrname, _fsname, _wmi, _dispname) \
+ ASUS_WMI_SHOW_INT(_attrname##_current_value, _wmi); \
+ static struct kobj_attribute attr_##_attrname##_current_value = \
+ __ASUS_ATTR_RO(_attrname, current_value); \
+ __ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \
+ static struct kobj_attribute attr_##_attrname##_type = \
+ __ASUS_ATTR_RO_AS(type, int_type_show); \
+ static struct attribute *_attrname##_attrs[] = { \
+ &attr_##_attrname##_current_value.attr, \
+ &attr_##_attrname##_display_name.attr, \
+ &attr_##_attrname##_type.attr, NULL \
+ }; \
+ static const struct attribute_group _attrname##_attr_group = { \
+ .name = _fsname, .attrs = _attrname##_attrs \
+ }
+
+/*
+ * ROG PPT attributes need a little different in setup as they
+ * require rog_tunables members.
+ */
+
+#define __ROG_TUNABLE_SHOW(_prop, _attrname, _val) \
+ static ssize_t _attrname##_##_prop##_show( \
+ struct kobject *kobj, struct kobj_attribute *attr, char *buf) \
+ { \
+ struct rog_tunables *tunables = get_current_tunables(); \
+ \
+ if (!tunables || !tunables->power_limits) \
+ return -ENODEV; \
+ \
+ return sysfs_emit(buf, "%d\n", tunables->power_limits->_val); \
+ } \
+ static struct kobj_attribute attr_##_attrname##_##_prop = \
+ __ASUS_ATTR_RO(_attrname, _prop)
+
+#define __ROG_TUNABLE_SHOW_DEFAULT(_attrname) \
+ static ssize_t _attrname##_default_value_show( \
+ struct kobject *kobj, struct kobj_attribute *attr, char *buf) \
+ { \
+ struct rog_tunables *tunables = get_current_tunables(); \
+ \
+ if (!tunables || !tunables->power_limits) \
+ return -ENODEV; \
+ \
+ return sysfs_emit( \
+ buf, "%d\n", \
+ tunables->power_limits->_attrname##_def ? \
+ tunables->power_limits->_attrname##_def : \
+ tunables->power_limits->_attrname##_max); \
+ } \
+ static struct kobj_attribute attr_##_attrname##_default_value = \
+ __ASUS_ATTR_RO(_attrname, default_value)
+
+#define __ROG_TUNABLE_RW(_attr, _wmi) \
+ static ssize_t _attr##_current_value_store( \
+ struct kobject *kobj, struct kobj_attribute *attr, \
+ const char *buf, size_t count) \
+ { \
+ struct rog_tunables *tunables = get_current_tunables(); \
+ \
+ if (!tunables || !tunables->power_limits) \
+ return -ENODEV; \
+ \
+ if (tunables->power_limits->_attr##_min == \
+ tunables->power_limits->_attr##_max) \
+ return -EINVAL; \
+ \
+ return armoury_attr_uint_store(kobj, attr, buf, count, \
+ tunables->power_limits->_attr##_min, \
+ tunables->power_limits->_attr##_max, \
+ &tunables->_attr, _wmi); \
+ } \
+ static ssize_t _attr##_current_value_show( \
+ struct kobject *kobj, struct kobj_attribute *attr, char *buf) \
+ { \
+ struct rog_tunables *tunables = get_current_tunables(); \
+ \
+ if (!tunables) \
+ return -ENODEV; \
+ \
+ return sysfs_emit(buf, "%u\n", tunables->_attr); \
+ } \
+ static struct kobj_attribute attr_##_attr##_current_value = \
+ __ASUS_ATTR_RW(_attr, current_value)
+
+#define ASUS_ATTR_GROUP_ROG_TUNABLE(_attrname, _fsname, _wmi, _dispname) \
+ __ROG_TUNABLE_RW(_attrname, _wmi); \
+ __ROG_TUNABLE_SHOW_DEFAULT(_attrname); \
+ __ROG_TUNABLE_SHOW(min_value, _attrname, _attrname##_min); \
+ __ROG_TUNABLE_SHOW(max_value, _attrname, _attrname##_max); \
+ __ATTR_SHOW_FMT(scalar_increment, _attrname, "%d\n", 1); \
+ __ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \
+ static struct kobj_attribute attr_##_attrname##_type = \
+ __ASUS_ATTR_RO_AS(type, int_type_show); \
+ static struct attribute *_attrname##_attrs[] = { \
+ &attr_##_attrname##_current_value.attr, \
+ &attr_##_attrname##_default_value.attr, \
+ &attr_##_attrname##_min_value.attr, \
+ &attr_##_attrname##_max_value.attr, \
+ &attr_##_attrname##_scalar_increment.attr, \
+ &attr_##_attrname##_display_name.attr, \
+ &attr_##_attrname##_type.attr, \
+ NULL \
+ }; \
+ static const struct attribute_group _attrname##_attr_group = { \
+ .name = _fsname, .attrs = _attrname##_attrs \
+ }
+
+/* Default is always the maximum value unless *_def is specified */
+struct power_limits {
+ u8 ppt_pl1_spl_min;
+ u8 ppt_pl1_spl_def;
+ u8 ppt_pl1_spl_max;
+ u8 ppt_pl2_sppt_min;
+ u8 ppt_pl2_sppt_def;
+ u8 ppt_pl2_sppt_max;
+ u8 ppt_pl3_fppt_min;
+ u8 ppt_pl3_fppt_def;
+ u8 ppt_pl3_fppt_max;
+ u8 ppt_apu_sppt_min;
+ u8 ppt_apu_sppt_def;
+ u8 ppt_apu_sppt_max;
+ u8 ppt_platform_sppt_min;
+ u8 ppt_platform_sppt_def;
+ u8 ppt_platform_sppt_max;
+ /* Nvidia GPU specific, default is always max */
+ u8 nv_dynamic_boost_def; // unused. exists for macro
+ u8 nv_dynamic_boost_min;
+ u8 nv_dynamic_boost_max;
+ u8 nv_temp_target_def; // unused. exists for macro
+ u8 nv_temp_target_min;
+ u8 nv_temp_target_max;
+ u8 nv_tgp_def; // unused. exists for macro
+ u8 nv_tgp_min;
+ u8 nv_tgp_max;
+};
+
+struct power_data {
+ const struct power_limits *ac_data;
+ const struct power_limits *dc_data;
+ bool requires_fan_curve;
+};
+
+/*
+ * For each available attribute there must be a min and a max.
+ * _def is not required and will be assumed to be default == max if missing.
+ */
+static const struct dmi_system_id power_limits[] = {
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "FA401W"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_max = 80,
+ .ppt_pl2_sppt_min = 35,
+ .ppt_pl2_sppt_max = 80,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_max = 80,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 25,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ .nv_tgp_min = 55,
+ .nv_tgp_max = 75,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 25,
+ .ppt_pl1_spl_max = 30,
+ .ppt_pl2_sppt_min = 31,
+ .ppt_pl2_sppt_max = 44,
+ .ppt_pl3_fppt_min = 45,
+ .ppt_pl3_fppt_max = 65,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "FA507N"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_max = 80,
+ .ppt_pl2_sppt_min = 35,
+ .ppt_pl2_sppt_max = 80,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_max = 80,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 25,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_def = 45,
+ .ppt_pl1_spl_max = 65,
+ .ppt_pl2_sppt_min = 35,
+ .ppt_pl2_sppt_def = 54,
+ .ppt_pl2_sppt_max = 65,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_max = 65,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "FA507UV"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_max = 80,
+ .ppt_pl2_sppt_min = 35,
+ .ppt_pl2_sppt_max = 80,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_max = 80,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 25,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ .nv_tgp_min = 55,
+ .nv_tgp_max = 115,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_def = 45,
+ .ppt_pl1_spl_max = 65,
+ .ppt_pl2_sppt_min = 35,
+ .ppt_pl2_sppt_def = 54,
+ .ppt_pl2_sppt_max = 65,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_max = 65,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "FA507R"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_max = 80,
+ .ppt_pl2_sppt_min = 25,
+ .ppt_pl2_sppt_max = 80,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_max = 80
+ },
+ .dc_data = NULL,
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "FA507X"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_max = 80,
+ .ppt_pl2_sppt_min = 35,
+ .ppt_pl2_sppt_max = 80,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_max = 80,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 20,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ .nv_tgp_min = 55,
+ .nv_tgp_max = 85,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_def = 45,
+ .ppt_pl1_spl_max = 65,
+ .ppt_pl2_sppt_min = 35,
+ .ppt_pl2_sppt_def = 54,
+ .ppt_pl2_sppt_max = 65,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_max = 65,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "FA507Z"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 28,
+ .ppt_pl1_spl_max = 65,
+ .ppt_pl2_sppt_min = 28,
+ .ppt_pl2_sppt_max = 105,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 15,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ .nv_tgp_min = 55,
+ .nv_tgp_max = 85,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 25,
+ .ppt_pl1_spl_max = 45,
+ .ppt_pl2_sppt_min = 35,
+ .ppt_pl2_sppt_max = 60,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "FA607P"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 30,
+ .ppt_pl1_spl_def = 100,
+ .ppt_pl1_spl_max = 135,
+ .ppt_pl2_sppt_min = 30,
+ .ppt_pl2_sppt_def = 115,
+ .ppt_pl2_sppt_max = 135,
+ .ppt_pl3_fppt_min = 30,
+ .ppt_pl3_fppt_max = 135,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 25,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ .nv_tgp_min = 55,
+ .nv_tgp_max = 115,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 25,
+ .ppt_pl1_spl_def = 45,
+ .ppt_pl1_spl_max = 80,
+ .ppt_pl2_sppt_min = 25,
+ .ppt_pl2_sppt_def = 60,
+ .ppt_pl2_sppt_max = 80,
+ .ppt_pl3_fppt_min = 25,
+ .ppt_pl3_fppt_max = 80,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "FA608WI"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_def = 90,
+ .ppt_pl1_spl_max = 90,
+ .ppt_pl2_sppt_min = 35,
+ .ppt_pl2_sppt_def = 90,
+ .ppt_pl2_sppt_max = 90,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_def = 90,
+ .ppt_pl3_fppt_max = 90,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 25,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ .nv_tgp_min = 55,
+ .nv_tgp_max = 115,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_def = 45,
+ .ppt_pl1_spl_max = 65,
+ .ppt_pl2_sppt_min = 35,
+ .ppt_pl2_sppt_def = 54,
+ .ppt_pl2_sppt_max = 65,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_def = 65,
+ .ppt_pl3_fppt_max = 65,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "FA617NS"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_apu_sppt_min = 15,
+ .ppt_apu_sppt_max = 80,
+ .ppt_platform_sppt_min = 30,
+ .ppt_platform_sppt_max = 120,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_apu_sppt_min = 25,
+ .ppt_apu_sppt_max = 35,
+ .ppt_platform_sppt_min = 45,
+ .ppt_platform_sppt_max = 100,
+ },
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "FA617NT"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_apu_sppt_min = 15,
+ .ppt_apu_sppt_max = 80,
+ .ppt_platform_sppt_min = 30,
+ .ppt_platform_sppt_max = 115,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_apu_sppt_min = 15,
+ .ppt_apu_sppt_max = 45,
+ .ppt_platform_sppt_min = 30,
+ .ppt_platform_sppt_max = 50,
+ },
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "FA617XS"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_apu_sppt_min = 15,
+ .ppt_apu_sppt_max = 80,
+ .ppt_platform_sppt_min = 30,
+ .ppt_platform_sppt_max = 120,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_apu_sppt_min = 25,
+ .ppt_apu_sppt_max = 35,
+ .ppt_platform_sppt_min = 45,
+ .ppt_platform_sppt_max = 100,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "FX507VI"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 28,
+ .ppt_pl1_spl_max = 135,
+ .ppt_pl2_sppt_min = 28,
+ .ppt_pl2_sppt_max = 135,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 25,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 25,
+ .ppt_pl1_spl_max = 45,
+ .ppt_pl2_sppt_min = 35,
+ .ppt_pl2_sppt_max = 60,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .requires_fan_curve = true,
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "FX507VV"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 28,
+ .ppt_pl1_spl_def = 115,
+ .ppt_pl1_spl_max = 135,
+ .ppt_pl2_sppt_min = 28,
+ .ppt_pl2_sppt_max = 135,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 25,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 25,
+ .ppt_pl1_spl_max = 45,
+ .ppt_pl2_sppt_min = 35,
+ .ppt_pl2_sppt_max = 60,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .requires_fan_curve = true,
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "FX507Z"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 28,
+ .ppt_pl1_spl_max = 90,
+ .ppt_pl2_sppt_min = 28,
+ .ppt_pl2_sppt_max = 135,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 15,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 25,
+ .ppt_pl1_spl_max = 45,
+ .ppt_pl2_sppt_min = 35,
+ .ppt_pl2_sppt_max = 60,
+ },
+ .requires_fan_curve = true,
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "GA401Q"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_max = 80,
+ .ppt_pl2_sppt_min = 15,
+ .ppt_pl2_sppt_max = 80,
+ },
+ .dc_data = NULL,
+ },
+ },
+ {
+ .matches = {
+ // This model is full AMD. No Nvidia dGPU.
+ DMI_MATCH(DMI_BOARD_NAME, "GA402R"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_apu_sppt_min = 15,
+ .ppt_apu_sppt_max = 80,
+ .ppt_platform_sppt_min = 30,
+ .ppt_platform_sppt_max = 115,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_apu_sppt_min = 25,
+ .ppt_apu_sppt_def = 30,
+ .ppt_apu_sppt_max = 45,
+ .ppt_platform_sppt_min = 40,
+ .ppt_platform_sppt_max = 60,
+ },
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "GA402X"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_def = 35,
+ .ppt_pl1_spl_max = 80,
+ .ppt_pl2_sppt_min = 25,
+ .ppt_pl2_sppt_def = 65,
+ .ppt_pl2_sppt_max = 80,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_max = 80,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_max = 35,
+ .ppt_pl2_sppt_min = 25,
+ .ppt_pl2_sppt_max = 35,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_max = 65,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .requires_fan_curve = true,
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "GA403U"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_max = 80,
+ .ppt_pl2_sppt_min = 25,
+ .ppt_pl2_sppt_max = 80,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_max = 80,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 25,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ .nv_tgp_min = 55,
+ .nv_tgp_max = 65,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_max = 35,
+ .ppt_pl2_sppt_min = 25,
+ .ppt_pl2_sppt_max = 35,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_max = 65,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .requires_fan_curve = true,
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "GA503QR"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_def = 35,
+ .ppt_pl1_spl_max = 80,
+ .ppt_pl2_sppt_min = 65,
+ .ppt_pl2_sppt_max = 80,
+ },
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "GA503R"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_def = 35,
+ .ppt_pl1_spl_max = 80,
+ .ppt_pl2_sppt_min = 35,
+ .ppt_pl2_sppt_def = 65,
+ .ppt_pl2_sppt_max = 80,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_max = 80,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 20,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_def = 25,
+ .ppt_pl1_spl_max = 65,
+ .ppt_pl2_sppt_min = 35,
+ .ppt_pl2_sppt_def = 54,
+ .ppt_pl2_sppt_max = 60,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_max = 65,
+ },
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "GA605W"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_max = 80,
+ .ppt_pl2_sppt_min = 35,
+ .ppt_pl2_sppt_max = 80,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_max = 80,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 20,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ .nv_tgp_min = 55,
+ .nv_tgp_max = 85,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 25,
+ .ppt_pl1_spl_max = 35,
+ .ppt_pl2_sppt_min = 31,
+ .ppt_pl2_sppt_max = 44,
+ .ppt_pl3_fppt_min = 45,
+ .ppt_pl3_fppt_max = 65,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .requires_fan_curve = true,
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "GU603Z"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 25,
+ .ppt_pl1_spl_max = 60,
+ .ppt_pl2_sppt_min = 25,
+ .ppt_pl2_sppt_max = 135,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 20,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 25,
+ .ppt_pl1_spl_max = 40,
+ .ppt_pl2_sppt_min = 25,
+ .ppt_pl2_sppt_max = 40,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ }
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "GU604V"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 65,
+ .ppt_pl1_spl_max = 120,
+ .ppt_pl2_sppt_min = 65,
+ .ppt_pl2_sppt_max = 150,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 25,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 25,
+ .ppt_pl1_spl_max = 40,
+ .ppt_pl2_sppt_min = 35,
+ .ppt_pl2_sppt_def = 40,
+ .ppt_pl2_sppt_max = 60,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "GU605CW"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 45,
+ .ppt_pl1_spl_max = 85,
+ .ppt_pl2_sppt_min = 56,
+ .ppt_pl2_sppt_max = 110,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 20,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ .nv_tgp_min = 80,
+ .nv_tgp_def = 90,
+ .nv_tgp_max = 110,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 25,
+ .ppt_pl1_spl_max = 85,
+ .ppt_pl2_sppt_min = 32,
+ .ppt_pl2_sppt_max = 110,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .requires_fan_curve = true,
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "GU605CX"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 45,
+ .ppt_pl1_spl_max = 85,
+ .ppt_pl2_sppt_min = 56,
+ .ppt_pl2_sppt_max = 110,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 20,
+ .nv_temp_target_min = 7,
+ .nv_temp_target_max = 87,
+ .nv_tgp_min = 95,
+ .nv_tgp_def = 100,
+ .nv_tgp_max = 110,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 25,
+ .ppt_pl1_spl_max = 85,
+ .ppt_pl2_sppt_min = 32,
+ .ppt_pl2_sppt_max = 110,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .requires_fan_curve = true,
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "GU605M"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 28,
+ .ppt_pl1_spl_max = 90,
+ .ppt_pl2_sppt_min = 28,
+ .ppt_pl2_sppt_max = 135,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 20,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 25,
+ .ppt_pl1_spl_max = 35,
+ .ppt_pl2_sppt_min = 38,
+ .ppt_pl2_sppt_max = 53,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .requires_fan_curve = true,
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "GV301Q"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_max = 45,
+ .ppt_pl2_sppt_min = 65,
+ .ppt_pl2_sppt_max = 80,
+ },
+ .dc_data = NULL,
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "GV301R"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_max = 45,
+ .ppt_pl2_sppt_min = 25,
+ .ppt_pl2_sppt_max = 54,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_max = 65,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_max = 35,
+ .ppt_pl2_sppt_min = 25,
+ .ppt_pl2_sppt_max = 35,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_max = 65,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "GV601R"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_def = 35,
+ .ppt_pl1_spl_max = 90,
+ .ppt_pl2_sppt_min = 35,
+ .ppt_pl2_sppt_def = 54,
+ .ppt_pl2_sppt_max = 100,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_def = 80,
+ .ppt_pl3_fppt_max = 125,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 25,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_def = 28,
+ .ppt_pl1_spl_max = 65,
+ .ppt_pl2_sppt_min = 35,
+ .ppt_pl2_sppt_def = 54,
+ .ppt_pl2_sppt_max = 60,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_def = 80,
+ .ppt_pl3_fppt_max = 65,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "GV601V"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 28,
+ .ppt_pl1_spl_def = 100,
+ .ppt_pl1_spl_max = 110,
+ .ppt_pl2_sppt_min = 28,
+ .ppt_pl2_sppt_max = 135,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 20,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 25,
+ .ppt_pl1_spl_max = 40,
+ .ppt_pl2_sppt_min = 35,
+ .ppt_pl2_sppt_def = 40,
+ .ppt_pl2_sppt_max = 60,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "GX650P"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_def = 110,
+ .ppt_pl1_spl_max = 130,
+ .ppt_pl2_sppt_min = 35,
+ .ppt_pl2_sppt_def = 125,
+ .ppt_pl2_sppt_max = 130,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_def = 125,
+ .ppt_pl3_fppt_max = 135,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 25,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_def = 25,
+ .ppt_pl1_spl_max = 65,
+ .ppt_pl2_sppt_min = 35,
+ .ppt_pl2_sppt_def = 35,
+ .ppt_pl2_sppt_max = 65,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_def = 42,
+ .ppt_pl3_fppt_max = 65,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "G513I"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ /* Yes this laptop is very limited */
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_max = 80,
+ .ppt_pl2_sppt_min = 15,
+ .ppt_pl2_sppt_max = 80,
+ },
+ .dc_data = NULL,
+ .requires_fan_curve = true,
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "G513QM"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ /* Yes this laptop is very limited */
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_max = 100,
+ .ppt_pl2_sppt_min = 15,
+ .ppt_pl2_sppt_max = 190,
+ },
+ .dc_data = NULL,
+ .requires_fan_curve = true,
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "G513R"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 35,
+ .ppt_pl1_spl_max = 90,
+ .ppt_pl2_sppt_min = 54,
+ .ppt_pl2_sppt_max = 100,
+ .ppt_pl3_fppt_min = 54,
+ .ppt_pl3_fppt_max = 125,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 25,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 28,
+ .ppt_pl1_spl_max = 50,
+ .ppt_pl2_sppt_min = 28,
+ .ppt_pl2_sppt_max = 50,
+ .ppt_pl3_fppt_min = 28,
+ .ppt_pl3_fppt_max = 65,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .requires_fan_curve = true,
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "G614J"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 28,
+ .ppt_pl1_spl_max = 140,
+ .ppt_pl2_sppt_min = 28,
+ .ppt_pl2_sppt_max = 175,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 25,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 25,
+ .ppt_pl1_spl_max = 55,
+ .ppt_pl2_sppt_min = 25,
+ .ppt_pl2_sppt_max = 70,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .requires_fan_curve = true,
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "G634J"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 28,
+ .ppt_pl1_spl_max = 140,
+ .ppt_pl2_sppt_min = 28,
+ .ppt_pl2_sppt_max = 175,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 25,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 25,
+ .ppt_pl1_spl_max = 55,
+ .ppt_pl2_sppt_min = 25,
+ .ppt_pl2_sppt_max = 70,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .requires_fan_curve = true,
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "G713PV"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 30,
+ .ppt_pl1_spl_def = 120,
+ .ppt_pl1_spl_max = 130,
+ .ppt_pl2_sppt_min = 65,
+ .ppt_pl2_sppt_def = 125,
+ .ppt_pl2_sppt_max = 130,
+ .ppt_pl3_fppt_min = 65,
+ .ppt_pl3_fppt_def = 125,
+ .ppt_pl3_fppt_max = 130,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 25,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 25,
+ .ppt_pl1_spl_max = 65,
+ .ppt_pl2_sppt_min = 25,
+ .ppt_pl2_sppt_max = 65,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_max = 75,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .requires_fan_curve = true,
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "G733C"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 28,
+ .ppt_pl1_spl_max = 170,
+ .ppt_pl2_sppt_min = 28,
+ .ppt_pl2_sppt_max = 175,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 25,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 28,
+ .ppt_pl1_spl_max = 35,
+ .ppt_pl2_sppt_min = 28,
+ .ppt_pl2_sppt_max = 35,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .requires_fan_curve = true,
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "G733P"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 30,
+ .ppt_pl1_spl_def = 100,
+ .ppt_pl1_spl_max = 130,
+ .ppt_pl2_sppt_min = 65,
+ .ppt_pl2_sppt_def = 125,
+ .ppt_pl2_sppt_max = 130,
+ .ppt_pl3_fppt_min = 65,
+ .ppt_pl3_fppt_def = 125,
+ .ppt_pl3_fppt_max = 130,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 25,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 25,
+ .ppt_pl1_spl_max = 65,
+ .ppt_pl2_sppt_min = 25,
+ .ppt_pl2_sppt_max = 65,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_max = 75,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .requires_fan_curve = true,
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "G814J"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 28,
+ .ppt_pl1_spl_max = 140,
+ .ppt_pl2_sppt_min = 28,
+ .ppt_pl2_sppt_max = 140,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 25,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 25,
+ .ppt_pl1_spl_max = 55,
+ .ppt_pl2_sppt_min = 25,
+ .ppt_pl2_sppt_max = 70,
+ },
+ .requires_fan_curve = true,
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "G834J"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 28,
+ .ppt_pl1_spl_max = 140,
+ .ppt_pl2_sppt_min = 28,
+ .ppt_pl2_sppt_max = 175,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 25,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 25,
+ .ppt_pl1_spl_max = 55,
+ .ppt_pl2_sppt_min = 25,
+ .ppt_pl2_sppt_max = 70,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .requires_fan_curve = true,
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "H7606W"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_max = 80,
+ .ppt_pl2_sppt_min = 35,
+ .ppt_pl2_sppt_max = 80,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_max = 80,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 20,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ .nv_tgp_min = 55,
+ .nv_tgp_max = 85,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 25,
+ .ppt_pl1_spl_max = 35,
+ .ppt_pl2_sppt_min = 31,
+ .ppt_pl2_sppt_max = 44,
+ .ppt_pl3_fppt_min = 45,
+ .ppt_pl3_fppt_max = 65,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "RC71"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 7,
+ .ppt_pl1_spl_max = 30,
+ .ppt_pl2_sppt_min = 15,
+ .ppt_pl2_sppt_max = 43,
+ .ppt_pl3_fppt_min = 15,
+ .ppt_pl3_fppt_max = 53,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 7,
+ .ppt_pl1_spl_def = 15,
+ .ppt_pl1_spl_max = 25,
+ .ppt_pl2_sppt_min = 15,
+ .ppt_pl2_sppt_def = 20,
+ .ppt_pl2_sppt_max = 30,
+ .ppt_pl3_fppt_min = 15,
+ .ppt_pl3_fppt_def = 25,
+ .ppt_pl3_fppt_max = 35,
+ },
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "RC72"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 7,
+ .ppt_pl1_spl_max = 30,
+ .ppt_pl2_sppt_min = 15,
+ .ppt_pl2_sppt_max = 43,
+ .ppt_pl3_fppt_min = 15,
+ .ppt_pl3_fppt_max = 53,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 7,
+ .ppt_pl1_spl_def = 17,
+ .ppt_pl1_spl_max = 25,
+ .ppt_pl2_sppt_min = 15,
+ .ppt_pl2_sppt_def = 24,
+ .ppt_pl2_sppt_max = 30,
+ .ppt_pl3_fppt_min = 15,
+ .ppt_pl3_fppt_def = 30,
+ .ppt_pl3_fppt_max = 35,
+ },
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "RC73XA"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 7,
+ .ppt_pl1_spl_max = 35,
+ .ppt_pl2_sppt_min = 14,
+ .ppt_pl2_sppt_max = 45,
+ .ppt_pl3_fppt_min = 19,
+ .ppt_pl3_fppt_max = 55,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 7,
+ .ppt_pl1_spl_def = 17,
+ .ppt_pl1_spl_max = 35,
+ .ppt_pl2_sppt_min = 13,
+ .ppt_pl2_sppt_def = 21,
+ .ppt_pl2_sppt_max = 45,
+ .ppt_pl3_fppt_min = 19,
+ .ppt_pl3_fppt_def = 26,
+ .ppt_pl3_fppt_max = 55,
+ },
+ },
+ },
+ {}
+};
+
+#endif /* _ASUS_ARMOURY_H_ */
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index e72a2b5d158e..4aec7ec69250 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -15,6 +15,7 @@
#include <linux/acpi.h>
#include <linux/backlight.h>
+#include <linux/bits.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/dmi.h>
@@ -30,6 +31,7 @@
#include <linux/pci.h>
#include <linux/pci_hotplug.h>
#include <linux/platform_data/x86/asus-wmi.h>
+#include <linux/platform_data/x86/asus-wmi-leds-ids.h>
#include <linux/platform_device.h>
#include <linux/platform_profile.h>
#include <linux/power_supply.h>
@@ -55,8 +57,6 @@ module_param(fnlock_default, bool, 0444);
#define to_asus_wmi_driver(pdrv) \
(container_of((pdrv), struct asus_wmi_driver, platform_driver))
-#define ASUS_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66"
-
#define NOTIFY_BRNUP_MIN 0x11
#define NOTIFY_BRNUP_MAX 0x1f
#define NOTIFY_BRNDOWN_MIN 0x20
@@ -105,8 +105,6 @@ module_param(fnlock_default, bool, 0444);
#define USB_INTEL_XUSB2PR 0xD0
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31
-#define ASUS_ACPI_UID_ASUSWMI "ASUSWMI"
-
#define WMI_EVENT_MASK 0xFFFF
#define FAN_CURVE_POINTS 8
@@ -340,6 +338,13 @@ struct asus_wmi {
/* Global to allow setting externally without requiring driver data */
static enum asus_ally_mcu_hack use_ally_mcu_hack = ASUS_WMI_ALLY_MCU_HACK_INIT;
+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
+static void asus_wmi_show_deprecated(void)
+{
+ pr_notice_once("Accessing attributes through /sys/bus/platform/asus_wmi is deprecated and will be removed in a future release. Please switch over to /sys/class/firmware_attributes.\n");
+}
+#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */
+
/* WMI ************************************************************************/
static int asus_wmi_evaluate_method3(u32 method_id,
@@ -390,7 +395,7 @@ int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, u32 *retval)
{
return asus_wmi_evaluate_method3(method_id, arg0, arg1, 0, retval);
}
-EXPORT_SYMBOL_GPL(asus_wmi_evaluate_method);
+EXPORT_SYMBOL_NS_GPL(asus_wmi_evaluate_method, "ASUS_WMI");
static int asus_wmi_evaluate_method5(u32 method_id,
u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4, u32 *retval)
@@ -554,12 +559,52 @@ static int asus_wmi_get_devstate(struct asus_wmi *asus, u32 dev_id, u32 *retval)
return 0;
}
-int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param,
- u32 *retval)
+/**
+ * asus_wmi_get_devstate_dsts() - Get the WMI function state.
+ * @dev_id: The WMI method ID to call.
+ * @retval: A pointer to where to store the value returned from WMI.
+ *
+ * Returns:
+ * * %-ENODEV - method ID is unsupported.
+ * * %0 - successful and retval is filled.
+ * * %other - error from WMI call.
+ */
+int asus_wmi_get_devstate_dsts(u32 dev_id, u32 *retval)
+{
+ int err;
+
+ err = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, dev_id, 0, retval);
+ if (err)
+ return err;
+
+ if ((*retval & ASUS_WMI_DSTS_PRESENCE_BIT) == 0x00)
+ return -ENODEV;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(asus_wmi_get_devstate_dsts, "ASUS_WMI");
+
+/**
+ * asus_wmi_set_devstate() - Set the WMI function state.
+ *
+ * Note: an asus_wmi_set_devstate() call must be paired with a
+ * asus_wmi_get_devstate_dsts() to check if the WMI function is supported.
+ *
+ * @dev_id: The WMI function to call.
+ * @ctrl_param: The argument to be used for this WMI function.
+ * @retval: A pointer to where to store the value returned from WMI.
+ *
+ * Returns:
+ * * %-ENODEV - method ID is unsupported.
+ * * %0 - successful and retval is filled.
+ * * %other - error from WMI call.
+ */
+int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, u32 *retval)
{
return asus_wmi_evaluate_method(ASUS_WMI_METHODID_DEVS, dev_id,
ctrl_param, retval);
}
+EXPORT_SYMBOL_NS_GPL(asus_wmi_set_devstate, "ASUS_WMI");
/* Helper for special devices with magic return codes */
static int asus_wmi_get_devstate_bits(struct asus_wmi *asus,
@@ -692,6 +737,7 @@ static void asus_wmi_tablet_mode_get_state(struct asus_wmi *asus)
}
/* Charging mode, 1=Barrel, 2=USB ******************************************/
+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
static ssize_t charge_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -702,12 +748,16 @@ static ssize_t charge_mode_show(struct device *dev,
if (result < 0)
return result;
+ asus_wmi_show_deprecated();
+
return sysfs_emit(buf, "%d\n", value & 0xff);
}
static DEVICE_ATTR_RO(charge_mode);
+#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */
/* dGPU ********************************************************************/
+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
static ssize_t dgpu_disable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -718,6 +768,8 @@ static ssize_t dgpu_disable_show(struct device *dev,
if (result < 0)
return result;
+ asus_wmi_show_deprecated();
+
return sysfs_emit(buf, "%d\n", result);
}
@@ -771,8 +823,10 @@ static ssize_t dgpu_disable_store(struct device *dev,
return count;
}
static DEVICE_ATTR_RW(dgpu_disable);
+#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */
/* eGPU ********************************************************************/
+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
static ssize_t egpu_enable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -783,6 +837,8 @@ static ssize_t egpu_enable_show(struct device *dev,
if (result < 0)
return result;
+ asus_wmi_show_deprecated();
+
return sysfs_emit(buf, "%d\n", result);
}
@@ -839,8 +895,10 @@ static ssize_t egpu_enable_store(struct device *dev,
return count;
}
static DEVICE_ATTR_RW(egpu_enable);
+#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */
/* Is eGPU connected? *********************************************************/
+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
static ssize_t egpu_connected_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -851,12 +909,16 @@ static ssize_t egpu_connected_show(struct device *dev,
if (result < 0)
return result;
+ asus_wmi_show_deprecated();
+
return sysfs_emit(buf, "%d\n", result);
}
static DEVICE_ATTR_RO(egpu_connected);
+#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */
/* gpu mux switch *************************************************************/
+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
static ssize_t gpu_mux_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -867,6 +929,8 @@ static ssize_t gpu_mux_mode_show(struct device *dev,
if (result < 0)
return result;
+ asus_wmi_show_deprecated();
+
return sysfs_emit(buf, "%d\n", result);
}
@@ -925,6 +989,7 @@ static ssize_t gpu_mux_mode_store(struct device *dev,
return count;
}
static DEVICE_ATTR_RW(gpu_mux_mode);
+#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */
/* TUF Laptop Keyboard RGB Modes **********************************************/
static ssize_t kbd_rgb_mode_store(struct device *dev,
@@ -1048,6 +1113,7 @@ static const struct attribute_group *kbd_rgb_mode_groups[] = {
};
/* Tunable: PPT: Intel=PL1, AMD=SPPT *****************************************/
+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
static ssize_t ppt_pl2_sppt_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
@@ -1086,6 +1152,8 @@ static ssize_t ppt_pl2_sppt_show(struct device *dev,
{
struct asus_wmi *asus = dev_get_drvdata(dev);
+ asus_wmi_show_deprecated();
+
return sysfs_emit(buf, "%u\n", asus->ppt_pl2_sppt);
}
static DEVICE_ATTR_RW(ppt_pl2_sppt);
@@ -1128,6 +1196,8 @@ static ssize_t ppt_pl1_spl_show(struct device *dev,
{
struct asus_wmi *asus = dev_get_drvdata(dev);
+ asus_wmi_show_deprecated();
+
return sysfs_emit(buf, "%u\n", asus->ppt_pl1_spl);
}
static DEVICE_ATTR_RW(ppt_pl1_spl);
@@ -1148,7 +1218,7 @@ static ssize_t ppt_fppt_store(struct device *dev,
if (value < PPT_TOTAL_MIN || value > PPT_TOTAL_MAX)
return -EINVAL;
- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_FPPT, value, &result);
+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_PL3_FPPT, value, &result);
if (err) {
pr_warn("Failed to set ppt_fppt: %d\n", err);
return err;
@@ -1171,6 +1241,8 @@ static ssize_t ppt_fppt_show(struct device *dev,
{
struct asus_wmi *asus = dev_get_drvdata(dev);
+ asus_wmi_show_deprecated();
+
return sysfs_emit(buf, "%u\n", asus->ppt_fppt);
}
static DEVICE_ATTR_RW(ppt_fppt);
@@ -1214,6 +1286,8 @@ static ssize_t ppt_apu_sppt_show(struct device *dev,
{
struct asus_wmi *asus = dev_get_drvdata(dev);
+ asus_wmi_show_deprecated();
+
return sysfs_emit(buf, "%u\n", asus->ppt_apu_sppt);
}
static DEVICE_ATTR_RW(ppt_apu_sppt);
@@ -1257,6 +1331,8 @@ static ssize_t ppt_platform_sppt_show(struct device *dev,
{
struct asus_wmi *asus = dev_get_drvdata(dev);
+ asus_wmi_show_deprecated();
+
return sysfs_emit(buf, "%u\n", asus->ppt_platform_sppt);
}
static DEVICE_ATTR_RW(ppt_platform_sppt);
@@ -1300,6 +1376,8 @@ static ssize_t nv_dynamic_boost_show(struct device *dev,
{
struct asus_wmi *asus = dev_get_drvdata(dev);
+ asus_wmi_show_deprecated();
+
return sysfs_emit(buf, "%u\n", asus->nv_dynamic_boost);
}
static DEVICE_ATTR_RW(nv_dynamic_boost);
@@ -1343,9 +1421,12 @@ static ssize_t nv_temp_target_show(struct device *dev,
{
struct asus_wmi *asus = dev_get_drvdata(dev);
+ asus_wmi_show_deprecated();
+
return sysfs_emit(buf, "%u\n", asus->nv_temp_target);
}
static DEVICE_ATTR_RW(nv_temp_target);
+#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */
/* Ally MCU Powersave ********************************************************/
@@ -1386,6 +1467,7 @@ void set_ally_mcu_powersave(bool enabled)
}
EXPORT_SYMBOL_NS_GPL(set_ally_mcu_powersave, "ASUS_WMI");
+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
static ssize_t mcu_powersave_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -1396,6 +1478,8 @@ static ssize_t mcu_powersave_show(struct device *dev,
if (result < 0)
return result;
+ asus_wmi_show_deprecated();
+
return sysfs_emit(buf, "%d\n", result);
}
@@ -1431,6 +1515,7 @@ static ssize_t mcu_powersave_store(struct device *dev,
return count;
}
static DEVICE_ATTR_RW(mcu_powersave);
+#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */
/* Battery ********************************************************************/
@@ -1619,14 +1704,14 @@ static void do_kbd_led_set(struct led_classdev *led_cdev, int value)
kbd_led_update(asus);
}
-static void kbd_led_set(struct led_classdev *led_cdev,
- enum led_brightness value)
+static int kbd_led_set(struct led_classdev *led_cdev, enum led_brightness value)
{
/* Prevent disabling keyboard backlight on module unregister */
if (led_cdev->flags & LED_UNREGISTERING)
- return;
+ return 0;
do_kbd_led_set(led_cdev, value);
+ return 0;
}
static void kbd_led_set_by_kbd(struct asus_wmi *asus, enum led_brightness value)
@@ -1802,7 +1887,7 @@ static int asus_wmi_led_init(struct asus_wmi *asus)
asus->kbd_led_wk = led_val;
asus->kbd_led.name = "asus::kbd_backlight";
asus->kbd_led.flags = LED_BRIGHT_HW_CHANGED;
- asus->kbd_led.brightness_set = kbd_led_set;
+ asus->kbd_led.brightness_set_blocking = kbd_led_set;
asus->kbd_led.brightness_get = kbd_led_get;
asus->kbd_led.max_brightness = 3;
@@ -2304,6 +2389,7 @@ exit:
}
/* Panel Overdrive ************************************************************/
+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
static ssize_t panel_od_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -2314,6 +2400,8 @@ static ssize_t panel_od_show(struct device *dev,
if (result < 0)
return result;
+ asus_wmi_show_deprecated();
+
return sysfs_emit(buf, "%d\n", result);
}
@@ -2350,9 +2438,10 @@ static ssize_t panel_od_store(struct device *dev,
return count;
}
static DEVICE_ATTR_RW(panel_od);
+#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */
/* Bootup sound ***************************************************************/
-
+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
static ssize_t boot_sound_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -2363,6 +2452,8 @@ static ssize_t boot_sound_show(struct device *dev,
if (result < 0)
return result;
+ asus_wmi_show_deprecated();
+
return sysfs_emit(buf, "%d\n", result);
}
@@ -2398,8 +2489,10 @@ static ssize_t boot_sound_store(struct device *dev,
return count;
}
static DEVICE_ATTR_RW(boot_sound);
+#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */
/* Mini-LED mode **************************************************************/
+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
static ssize_t mini_led_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -2430,6 +2523,8 @@ static ssize_t mini_led_mode_show(struct device *dev,
}
}
+ asus_wmi_show_deprecated();
+
return sysfs_emit(buf, "%d\n", value);
}
@@ -2500,10 +2595,13 @@ static ssize_t available_mini_led_mode_show(struct device *dev,
return sysfs_emit(buf, "0 1 2\n");
}
+ asus_wmi_show_deprecated();
+
return sysfs_emit(buf, "0\n");
}
static DEVICE_ATTR_RO(available_mini_led_mode);
+#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */
/* Quirks *********************************************************************/
@@ -3791,6 +3889,7 @@ static int throttle_thermal_policy_set_default(struct asus_wmi *asus)
return throttle_thermal_policy_write(asus);
}
+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
static ssize_t throttle_thermal_policy_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -3834,6 +3933,7 @@ static ssize_t throttle_thermal_policy_store(struct device *dev,
* Throttle thermal policy: 0 - default, 1 - overboost, 2 - silent
*/
static DEVICE_ATTR_RW(throttle_thermal_policy);
+#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */
/* Platform profile ***********************************************************/
static int asus_wmi_platform_profile_get(struct device *dev,
@@ -4435,27 +4535,29 @@ static struct attribute *platform_attributes[] = {
&dev_attr_camera.attr,
&dev_attr_cardr.attr,
&dev_attr_touchpad.attr,
- &dev_attr_charge_mode.attr,
- &dev_attr_egpu_enable.attr,
- &dev_attr_egpu_connected.attr,
- &dev_attr_dgpu_disable.attr,
- &dev_attr_gpu_mux_mode.attr,
&dev_attr_lid_resume.attr,
&dev_attr_als_enable.attr,
&dev_attr_fan_boost_mode.attr,
- &dev_attr_throttle_thermal_policy.attr,
- &dev_attr_ppt_pl2_sppt.attr,
- &dev_attr_ppt_pl1_spl.attr,
- &dev_attr_ppt_fppt.attr,
- &dev_attr_ppt_apu_sppt.attr,
- &dev_attr_ppt_platform_sppt.attr,
- &dev_attr_nv_dynamic_boost.attr,
- &dev_attr_nv_temp_target.attr,
- &dev_attr_mcu_powersave.attr,
- &dev_attr_boot_sound.attr,
- &dev_attr_panel_od.attr,
- &dev_attr_mini_led_mode.attr,
- &dev_attr_available_mini_led_mode.attr,
+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
+ &dev_attr_charge_mode.attr,
+ &dev_attr_egpu_enable.attr,
+ &dev_attr_egpu_connected.attr,
+ &dev_attr_dgpu_disable.attr,
+ &dev_attr_gpu_mux_mode.attr,
+ &dev_attr_ppt_pl2_sppt.attr,
+ &dev_attr_ppt_pl1_spl.attr,
+ &dev_attr_ppt_fppt.attr,
+ &dev_attr_ppt_apu_sppt.attr,
+ &dev_attr_ppt_platform_sppt.attr,
+ &dev_attr_nv_dynamic_boost.attr,
+ &dev_attr_nv_temp_target.attr,
+ &dev_attr_mcu_powersave.attr,
+ &dev_attr_boot_sound.attr,
+ &dev_attr_panel_od.attr,
+ &dev_attr_mini_led_mode.attr,
+ &dev_attr_available_mini_led_mode.attr,
+ &dev_attr_throttle_thermal_policy.attr,
+#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */
NULL
};
@@ -4477,7 +4579,11 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
devid = ASUS_WMI_DEVID_LID_RESUME;
else if (attr == &dev_attr_als_enable.attr)
devid = ASUS_WMI_DEVID_ALS_ENABLE;
- else if (attr == &dev_attr_charge_mode.attr)
+ else if (attr == &dev_attr_fan_boost_mode.attr)
+ ok = asus->fan_boost_mode_available;
+
+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
+ if (attr == &dev_attr_charge_mode.attr)
devid = ASUS_WMI_DEVID_CHARGE_MODE;
else if (attr == &dev_attr_egpu_enable.attr)
ok = asus->egpu_enable_available;
@@ -4496,7 +4602,7 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
else if (attr == &dev_attr_ppt_pl1_spl.attr)
devid = ASUS_WMI_DEVID_PPT_PL1_SPL;
else if (attr == &dev_attr_ppt_fppt.attr)
- devid = ASUS_WMI_DEVID_PPT_FPPT;
+ devid = ASUS_WMI_DEVID_PPT_PL3_FPPT;
else if (attr == &dev_attr_ppt_apu_sppt.attr)
devid = ASUS_WMI_DEVID_PPT_APU_SPPT;
else if (attr == &dev_attr_ppt_platform_sppt.attr)
@@ -4515,6 +4621,7 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
ok = asus->mini_led_dev_id != 0;
else if (attr == &dev_attr_available_mini_led_mode.attr)
ok = asus->mini_led_dev_id != 0;
+#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */
if (devid != -1) {
ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0);
@@ -4770,6 +4877,7 @@ static int asus_wmi_add(struct platform_device *pdev)
}
/* ensure defaults for tunables */
+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
asus->ppt_pl2_sppt = 5;
asus->ppt_pl1_spl = 5;
asus->ppt_apu_sppt = 5;
@@ -4792,17 +4900,18 @@ static int asus_wmi_add(struct platform_device *pdev)
asus->gpu_mux_dev = ASUS_WMI_DEVID_GPU_MUX;
else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_MUX_VIVO))
asus->gpu_mux_dev = ASUS_WMI_DEVID_GPU_MUX_VIVO;
-
- if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE))
- asus->kbd_rgb_dev = ASUS_WMI_DEVID_TUF_RGB_MODE;
- else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE2))
- asus->kbd_rgb_dev = ASUS_WMI_DEVID_TUF_RGB_MODE2;
+#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */
if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY))
asus->throttle_thermal_policy_dev = ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY;
else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO))
asus->throttle_thermal_policy_dev = ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO;
+ if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE))
+ asus->kbd_rgb_dev = ASUS_WMI_DEVID_TUF_RGB_MODE;
+ else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE2))
+ asus->kbd_rgb_dev = ASUS_WMI_DEVID_TUF_RGB_MODE2;
+
err = fan_boost_mode_check_present(asus);
if (err)
goto fail_fan_boost_mode;
diff --git a/drivers/platform/x86/ayaneo-ec.c b/drivers/platform/x86/ayaneo-ec.c
new file mode 100644
index 000000000000..41a24e091248
--- /dev/null
+++ b/drivers/platform/x86/ayaneo-ec.c
@@ -0,0 +1,593 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Platform driver for the Embedded Controller (EC) of Ayaneo devices. Handles
+ * hwmon (fan speed, fan control), battery charge limits, and magic module
+ * control (connected modules, controller disconnection).
+ *
+ * Copyright (C) 2025 Antheas Kapenekakis <lkml@antheas.dev>
+ */
+
+#include <linux/acpi.h>
+#include <linux/bits.h>
+#include <linux/dmi.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/power_supply.h>
+#include <linux/sysfs.h>
+#include <acpi/battery.h>
+
+#define AYANEO_PWM_ENABLE_REG 0x4A
+#define AYANEO_PWM_REG 0x4B
+#define AYANEO_PWM_MODE_AUTO 0x00
+#define AYANEO_PWM_MODE_MANUAL 0x01
+
+#define AYANEO_FAN_REG 0x76
+
+#define EC_CHARGE_CONTROL_BEHAVIOURS \
+ (BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO) | \
+ BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE))
+#define AYANEO_CHARGE_REG 0x1e
+#define AYANEO_CHARGE_VAL_AUTO 0xaa
+#define AYANEO_CHARGE_VAL_INHIBIT 0x55
+
+#define AYANEO_POWER_REG 0x2d
+#define AYANEO_POWER_OFF 0xfe
+#define AYANEO_POWER_ON 0xff
+#define AYANEO_MODULE_REG 0x2f
+#define AYANEO_MODULE_LEFT BIT(0)
+#define AYANEO_MODULE_RIGHT BIT(1)
+#define AYANEO_MODULE_MASK (AYANEO_MODULE_LEFT | AYANEO_MODULE_RIGHT)
+
+struct ayaneo_ec_quirk {
+ bool has_fan_control;
+ bool has_charge_control;
+ bool has_magic_modules;
+};
+
+struct ayaneo_ec_platform_data {
+ struct platform_device *pdev;
+ struct ayaneo_ec_quirk *quirks;
+ struct acpi_battery_hook battery_hook;
+
+ // Protects access to restore_pwm
+ struct mutex hwmon_lock;
+ bool restore_charge_limit;
+ bool restore_pwm;
+};
+
+static const struct ayaneo_ec_quirk quirk_fan = {
+ .has_fan_control = true,
+};
+
+static const struct ayaneo_ec_quirk quirk_charge_limit = {
+ .has_fan_control = true,
+ .has_charge_control = true,
+};
+
+static const struct ayaneo_ec_quirk quirk_ayaneo3 = {
+ .has_fan_control = true,
+ .has_charge_control = true,
+ .has_magic_modules = true,
+};
+
+static const struct dmi_system_id dmi_table[] = {
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
+ DMI_MATCH(DMI_BOARD_NAME, "AYANEO 2"),
+ },
+ .driver_data = (void *)&quirk_fan,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
+ DMI_MATCH(DMI_BOARD_NAME, "FLIP"),
+ },
+ .driver_data = (void *)&quirk_fan,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
+ DMI_MATCH(DMI_BOARD_NAME, "GEEK"),
+ },
+ .driver_data = (void *)&quirk_fan,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR"),
+ },
+ .driver_data = (void *)&quirk_charge_limit,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR 1S"),
+ },
+ .driver_data = (void *)&quirk_charge_limit,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "AB05-Mendocino"),
+ },
+ .driver_data = (void *)&quirk_charge_limit,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR Pro"),
+ },
+ .driver_data = (void *)&quirk_charge_limit,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "KUN"),
+ },
+ .driver_data = (void *)&quirk_charge_limit,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "AYANEO 3"),
+ },
+ .driver_data = (void *)&quirk_ayaneo3,
+ },
+ {},
+};
+
+/* Callbacks for hwmon interface */
+static umode_t ayaneo_ec_hwmon_is_visible(const void *drvdata,
+ enum hwmon_sensor_types type, u32 attr,
+ int channel)
+{
+ switch (type) {
+ case hwmon_fan:
+ return 0444;
+ case hwmon_pwm:
+ return 0644;
+ default:
+ return 0;
+ }
+}
+
+static int ayaneo_ec_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ u8 tmp;
+ int ret;
+
+ switch (type) {
+ case hwmon_fan:
+ switch (attr) {
+ case hwmon_fan_input:
+ ret = ec_read(AYANEO_FAN_REG, &tmp);
+ if (ret)
+ return ret;
+ *val = tmp << 8;
+ ret = ec_read(AYANEO_FAN_REG + 1, &tmp);
+ if (ret)
+ return ret;
+ *val |= tmp;
+ return 0;
+ default:
+ break;
+ }
+ break;
+ case hwmon_pwm:
+ switch (attr) {
+ case hwmon_pwm_input:
+ ret = ec_read(AYANEO_PWM_REG, &tmp);
+ if (ret)
+ return ret;
+ if (tmp > 100)
+ return -EIO;
+ *val = (255 * tmp) / 100;
+ return 0;
+ case hwmon_pwm_enable:
+ ret = ec_read(AYANEO_PWM_ENABLE_REG, &tmp);
+ if (ret)
+ return ret;
+ if (tmp == AYANEO_PWM_MODE_MANUAL)
+ *val = 1;
+ else if (tmp == AYANEO_PWM_MODE_AUTO)
+ *val = 2;
+ else
+ return -EIO;
+ return 0;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ return -EOPNOTSUPP;
+}
+
+static int ayaneo_ec_write(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long val)
+{
+ struct ayaneo_ec_platform_data *data = dev_get_drvdata(dev);
+ int ret;
+
+ guard(mutex)(&data->hwmon_lock);
+
+ switch (type) {
+ case hwmon_pwm:
+ switch (attr) {
+ case hwmon_pwm_enable:
+ data->restore_pwm = false;
+ switch (val) {
+ case 1:
+ return ec_write(AYANEO_PWM_ENABLE_REG,
+ AYANEO_PWM_MODE_MANUAL);
+ case 2:
+ return ec_write(AYANEO_PWM_ENABLE_REG,
+ AYANEO_PWM_MODE_AUTO);
+ default:
+ return -EINVAL;
+ }
+ case hwmon_pwm_input:
+ if (val < 0 || val > 255)
+ return -EINVAL;
+ if (data->restore_pwm) {
+ /*
+ * Defer restoring PWM control to after
+ * userspace resumes successfully
+ */
+ ret = ec_write(AYANEO_PWM_ENABLE_REG,
+ AYANEO_PWM_MODE_MANUAL);
+ if (ret)
+ return ret;
+ data->restore_pwm = false;
+ }
+ return ec_write(AYANEO_PWM_REG, (val * 100) / 255);
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ return -EOPNOTSUPP;
+}
+
+static const struct hwmon_ops ayaneo_ec_hwmon_ops = {
+ .is_visible = ayaneo_ec_hwmon_is_visible,
+ .read = ayaneo_ec_read,
+ .write = ayaneo_ec_write,
+};
+
+static const struct hwmon_channel_info *const ayaneo_ec_sensors[] = {
+ HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT),
+ HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT | HWMON_PWM_ENABLE),
+ NULL,
+};
+
+static const struct hwmon_chip_info ayaneo_ec_chip_info = {
+ .ops = &ayaneo_ec_hwmon_ops,
+ .info = ayaneo_ec_sensors,
+};
+
+static int ayaneo_psy_ext_get_prop(struct power_supply *psy,
+ const struct power_supply_ext *ext,
+ void *data,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ int ret;
+ u8 tmp;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
+ ret = ec_read(AYANEO_CHARGE_REG, &tmp);
+ if (ret)
+ return ret;
+
+ if (tmp == AYANEO_CHARGE_VAL_INHIBIT)
+ val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE;
+ else
+ val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ayaneo_psy_ext_set_prop(struct power_supply *psy,
+ const struct power_supply_ext *ext,
+ void *data,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ u8 raw_val;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
+ switch (val->intval) {
+ case POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO:
+ raw_val = AYANEO_CHARGE_VAL_AUTO;
+ break;
+ case POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE:
+ raw_val = AYANEO_CHARGE_VAL_INHIBIT;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return ec_write(AYANEO_CHARGE_REG, raw_val);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ayaneo_psy_prop_is_writeable(struct power_supply *psy,
+ const struct power_supply_ext *ext,
+ void *data,
+ enum power_supply_property psp)
+{
+ return true;
+}
+
+static const enum power_supply_property ayaneo_psy_ext_props[] = {
+ POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR,
+};
+
+static const struct power_supply_ext ayaneo_psy_ext = {
+ .name = "ayaneo-charge-control",
+ .properties = ayaneo_psy_ext_props,
+ .num_properties = ARRAY_SIZE(ayaneo_psy_ext_props),
+ .charge_behaviours = EC_CHARGE_CONTROL_BEHAVIOURS,
+ .get_property = ayaneo_psy_ext_get_prop,
+ .set_property = ayaneo_psy_ext_set_prop,
+ .property_is_writeable = ayaneo_psy_prop_is_writeable,
+};
+
+static int ayaneo_add_battery(struct power_supply *battery,
+ struct acpi_battery_hook *hook)
+{
+ struct ayaneo_ec_platform_data *data =
+ container_of(hook, struct ayaneo_ec_platform_data, battery_hook);
+
+ return power_supply_register_extension(battery, &ayaneo_psy_ext,
+ &data->pdev->dev, NULL);
+}
+
+static int ayaneo_remove_battery(struct power_supply *battery,
+ struct acpi_battery_hook *hook)
+{
+ power_supply_unregister_extension(battery, &ayaneo_psy_ext);
+ return 0;
+}
+
+static ssize_t controller_power_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ bool value;
+ int ret;
+
+ ret = kstrtobool(buf, &value);
+ if (ret)
+ return ret;
+
+ ret = ec_write(AYANEO_POWER_REG, value ? AYANEO_POWER_ON : AYANEO_POWER_OFF);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static ssize_t controller_power_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ u8 val;
+
+ ret = ec_read(AYANEO_POWER_REG, &val);
+ if (ret)
+ return ret;
+
+ return sysfs_emit(buf, "%d\n", val == AYANEO_POWER_ON);
+}
+
+static DEVICE_ATTR_RW(controller_power);
+
+static ssize_t controller_modules_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u8 unconnected_modules;
+ char *out;
+ int ret;
+
+ ret = ec_read(AYANEO_MODULE_REG, &unconnected_modules);
+ if (ret)
+ return ret;
+
+ switch (~unconnected_modules & AYANEO_MODULE_MASK) {
+ case AYANEO_MODULE_LEFT | AYANEO_MODULE_RIGHT:
+ out = "both";
+ break;
+ case AYANEO_MODULE_LEFT:
+ out = "left";
+ break;
+ case AYANEO_MODULE_RIGHT:
+ out = "right";
+ break;
+ default:
+ out = "none";
+ break;
+ }
+
+ return sysfs_emit(buf, "%s\n", out);
+}
+
+static DEVICE_ATTR_RO(controller_modules);
+
+static struct attribute *aya_mm_attrs[] = {
+ &dev_attr_controller_power.attr,
+ &dev_attr_controller_modules.attr,
+ NULL
+};
+
+static umode_t aya_mm_is_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
+
+ if (data->quirks->has_magic_modules)
+ return attr->mode;
+ return 0;
+}
+
+static const struct attribute_group aya_mm_attribute_group = {
+ .is_visible = aya_mm_is_visible,
+ .attrs = aya_mm_attrs,
+};
+
+static const struct attribute_group *ayaneo_ec_groups[] = {
+ &aya_mm_attribute_group,
+ NULL
+};
+
+static int ayaneo_ec_probe(struct platform_device *pdev)
+{
+ const struct dmi_system_id *dmi_entry;
+ struct ayaneo_ec_platform_data *data;
+ struct device *hwdev;
+ int ret;
+
+ dmi_entry = dmi_first_match(dmi_table);
+ if (!dmi_entry)
+ return -ENODEV;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->pdev = pdev;
+ data->quirks = dmi_entry->driver_data;
+ ret = devm_mutex_init(&pdev->dev, &data->hwmon_lock);
+ if (ret)
+ return ret;
+ platform_set_drvdata(pdev, data);
+
+ if (data->quirks->has_fan_control) {
+ hwdev = devm_hwmon_device_register_with_info(&pdev->dev,
+ "ayaneo_ec", data, &ayaneo_ec_chip_info, NULL);
+ if (IS_ERR(hwdev))
+ return PTR_ERR(hwdev);
+ }
+
+ if (data->quirks->has_charge_control) {
+ data->battery_hook.add_battery = ayaneo_add_battery;
+ data->battery_hook.remove_battery = ayaneo_remove_battery;
+ data->battery_hook.name = "Ayaneo Battery";
+ ret = devm_battery_hook_register(&pdev->dev, &data->battery_hook);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ayaneo_freeze(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
+ int ret;
+ u8 tmp;
+
+ if (data->quirks->has_charge_control) {
+ ret = ec_read(AYANEO_CHARGE_REG, &tmp);
+ if (ret)
+ return ret;
+
+ data->restore_charge_limit = tmp == AYANEO_CHARGE_VAL_INHIBIT;
+ }
+
+ if (data->quirks->has_fan_control) {
+ ret = ec_read(AYANEO_PWM_ENABLE_REG, &tmp);
+ if (ret)
+ return ret;
+
+ data->restore_pwm = tmp == AYANEO_PWM_MODE_MANUAL;
+
+ /*
+ * Release the fan when entering hibernation to avoid
+ * overheating if hibernation fails and hangs.
+ */
+ if (data->restore_pwm) {
+ ret = ec_write(AYANEO_PWM_ENABLE_REG, AYANEO_PWM_MODE_AUTO);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int ayaneo_restore(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
+ int ret;
+
+ if (data->quirks->has_charge_control && data->restore_charge_limit) {
+ ret = ec_write(AYANEO_CHARGE_REG, AYANEO_CHARGE_VAL_INHIBIT);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops ayaneo_pm_ops = {
+ .freeze = ayaneo_freeze,
+ .restore = ayaneo_restore,
+};
+
+static struct platform_driver ayaneo_platform_driver = {
+ .driver = {
+ .name = "ayaneo-ec",
+ .dev_groups = ayaneo_ec_groups,
+ .pm = pm_sleep_ptr(&ayaneo_pm_ops),
+ },
+ .probe = ayaneo_ec_probe,
+};
+
+static struct platform_device *ayaneo_platform_device;
+
+static int __init ayaneo_ec_init(void)
+{
+ ayaneo_platform_device =
+ platform_create_bundle(&ayaneo_platform_driver,
+ ayaneo_ec_probe, NULL, 0, NULL, 0);
+
+ return PTR_ERR_OR_ZERO(ayaneo_platform_device);
+}
+
+static void __exit ayaneo_ec_exit(void)
+{
+ platform_device_unregister(ayaneo_platform_device);
+ platform_driver_unregister(&ayaneo_platform_driver);
+}
+
+MODULE_DEVICE_TABLE(dmi, dmi_table);
+
+module_init(ayaneo_ec_init);
+module_exit(ayaneo_ec_exit);
+
+MODULE_AUTHOR("Antheas Kapenekakis <lkml@antheas.dev>");
+MODULE_DESCRIPTION("Ayaneo Embedded Controller (EC) platform features");
+MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/dell/alienware-wmi-wmax.c b/drivers/platform/x86/dell/alienware-wmi-wmax.c
index fadf7aac6779..1418bd326edf 100644
--- a/drivers/platform/x86/dell/alienware-wmi-wmax.c
+++ b/drivers/platform/x86/dell/alienware-wmi-wmax.c
@@ -235,11 +235,6 @@ enum AWCC_THERMAL_TABLES {
AWCC_THERMAL_TABLE_USTT = 0xA,
};
-enum AWCC_SPECIAL_THERMAL_CODES {
- AWCC_SPECIAL_PROFILE_CUSTOM = 0x00,
- AWCC_SPECIAL_PROFILE_GMODE = 0xAB,
-};
-
enum AWCC_TEMP_SENSOR_TYPES {
AWCC_TEMP_SENSOR_CPU = 0x01,
AWCC_TEMP_SENSOR_FRONT = 0x03,
@@ -266,17 +261,18 @@ enum AWCC_FAN_TYPES {
};
enum awcc_thermal_profile {
- AWCC_PROFILE_USTT_BALANCED,
- AWCC_PROFILE_USTT_BALANCED_PERFORMANCE,
- AWCC_PROFILE_USTT_COOL,
- AWCC_PROFILE_USTT_QUIET,
- AWCC_PROFILE_USTT_PERFORMANCE,
- AWCC_PROFILE_USTT_LOW_POWER,
- AWCC_PROFILE_LEGACY_QUIET,
- AWCC_PROFILE_LEGACY_BALANCED,
- AWCC_PROFILE_LEGACY_BALANCED_PERFORMANCE,
- AWCC_PROFILE_LEGACY_PERFORMANCE,
- AWCC_PROFILE_LAST,
+ AWCC_PROFILE_SPECIAL_CUSTOM = 0x00,
+ AWCC_PROFILE_LEGACY_QUIET = 0x96,
+ AWCC_PROFILE_LEGACY_BALANCED = 0x97,
+ AWCC_PROFILE_LEGACY_BALANCED_PERFORMANCE = 0x98,
+ AWCC_PROFILE_LEGACY_PERFORMANCE = 0x99,
+ AWCC_PROFILE_USTT_BALANCED = 0xA0,
+ AWCC_PROFILE_USTT_BALANCED_PERFORMANCE = 0xA1,
+ AWCC_PROFILE_USTT_COOL = 0xA2,
+ AWCC_PROFILE_USTT_QUIET = 0xA3,
+ AWCC_PROFILE_USTT_PERFORMANCE = 0xA4,
+ AWCC_PROFILE_USTT_LOW_POWER = 0xA5,
+ AWCC_PROFILE_SPECIAL_GMODE = 0xAB,
};
struct wmax_led_args {
@@ -332,19 +328,6 @@ struct awcc_priv {
u32 gpio_count;
};
-static const enum platform_profile_option awcc_mode_to_platform_profile[AWCC_PROFILE_LAST] = {
- [AWCC_PROFILE_USTT_BALANCED] = PLATFORM_PROFILE_BALANCED,
- [AWCC_PROFILE_USTT_BALANCED_PERFORMANCE] = PLATFORM_PROFILE_BALANCED_PERFORMANCE,
- [AWCC_PROFILE_USTT_COOL] = PLATFORM_PROFILE_COOL,
- [AWCC_PROFILE_USTT_QUIET] = PLATFORM_PROFILE_QUIET,
- [AWCC_PROFILE_USTT_PERFORMANCE] = PLATFORM_PROFILE_PERFORMANCE,
- [AWCC_PROFILE_USTT_LOW_POWER] = PLATFORM_PROFILE_LOW_POWER,
- [AWCC_PROFILE_LEGACY_QUIET] = PLATFORM_PROFILE_QUIET,
- [AWCC_PROFILE_LEGACY_BALANCED] = PLATFORM_PROFILE_BALANCED,
- [AWCC_PROFILE_LEGACY_BALANCED_PERFORMANCE] = PLATFORM_PROFILE_BALANCED_PERFORMANCE,
- [AWCC_PROFILE_LEGACY_PERFORMANCE] = PLATFORM_PROFILE_PERFORMANCE,
-};
-
static struct awcc_quirks *awcc;
/*
@@ -562,21 +545,41 @@ const struct attribute_group wmax_deepsleep_attribute_group = {
/*
* AWCC Helpers
*/
-static bool is_awcc_thermal_profile_id(u8 code)
+static int awcc_profile_to_pprof(enum awcc_thermal_profile profile,
+ enum platform_profile_option *pprof)
{
- u8 table = FIELD_GET(AWCC_THERMAL_TABLE_MASK, code);
- u8 mode = FIELD_GET(AWCC_THERMAL_MODE_MASK, code);
-
- if (mode >= AWCC_PROFILE_LAST)
- return false;
-
- if (table == AWCC_THERMAL_TABLE_LEGACY && mode >= AWCC_PROFILE_LEGACY_QUIET)
- return true;
-
- if (table == AWCC_THERMAL_TABLE_USTT && mode <= AWCC_PROFILE_USTT_LOW_POWER)
- return true;
+ switch (profile) {
+ case AWCC_PROFILE_SPECIAL_CUSTOM:
+ *pprof = PLATFORM_PROFILE_CUSTOM;
+ break;
+ case AWCC_PROFILE_LEGACY_QUIET:
+ case AWCC_PROFILE_USTT_QUIET:
+ *pprof = PLATFORM_PROFILE_QUIET;
+ break;
+ case AWCC_PROFILE_LEGACY_BALANCED:
+ case AWCC_PROFILE_USTT_BALANCED:
+ *pprof = PLATFORM_PROFILE_BALANCED;
+ break;
+ case AWCC_PROFILE_LEGACY_BALANCED_PERFORMANCE:
+ case AWCC_PROFILE_USTT_BALANCED_PERFORMANCE:
+ *pprof = PLATFORM_PROFILE_BALANCED_PERFORMANCE;
+ break;
+ case AWCC_PROFILE_LEGACY_PERFORMANCE:
+ case AWCC_PROFILE_USTT_PERFORMANCE:
+ case AWCC_PROFILE_SPECIAL_GMODE:
+ *pprof = PLATFORM_PROFILE_PERFORMANCE;
+ break;
+ case AWCC_PROFILE_USTT_COOL:
+ *pprof = PLATFORM_PROFILE_COOL;
+ break;
+ case AWCC_PROFILE_USTT_LOW_POWER:
+ *pprof = PLATFORM_PROFILE_LOW_POWER;
+ break;
+ default:
+ return -EINVAL;
+ }
- return false;
+ return 0;
}
static int awcc_wmi_command(struct wmi_device *wdev, u32 method_id,
@@ -1225,24 +1228,7 @@ static int awcc_platform_profile_get(struct device *dev,
if (ret)
return ret;
- switch (out_data) {
- case AWCC_SPECIAL_PROFILE_CUSTOM:
- *profile = PLATFORM_PROFILE_CUSTOM;
- return 0;
- case AWCC_SPECIAL_PROFILE_GMODE:
- *profile = PLATFORM_PROFILE_PERFORMANCE;
- return 0;
- default:
- break;
- }
-
- if (!is_awcc_thermal_profile_id(out_data))
- return -ENODATA;
-
- out_data = FIELD_GET(AWCC_THERMAL_MODE_MASK, out_data);
- *profile = awcc_mode_to_platform_profile[out_data];
-
- return 0;
+ return awcc_profile_to_pprof(out_data, profile);
}
static int awcc_platform_profile_set(struct device *dev,
@@ -1279,7 +1265,6 @@ static int awcc_platform_profile_probe(void *drvdata, unsigned long *choices)
{
enum platform_profile_option profile;
struct awcc_priv *priv = drvdata;
- enum awcc_thermal_profile mode;
u8 id, offset = 0;
int ret;
@@ -1301,15 +1286,20 @@ static int awcc_platform_profile_probe(void *drvdata, unsigned long *choices)
if (ret)
return ret;
- if (!is_awcc_thermal_profile_id(id)) {
+ /*
+ * G-Mode profile ID is not listed consistently across modeles
+ * that support it, therefore we handle it through quirks.
+ */
+ if (id == AWCC_PROFILE_SPECIAL_GMODE)
+ continue;
+
+ ret = awcc_profile_to_pprof(id, &profile);
+ if (ret) {
dev_dbg(&priv->wdev->dev, "Unmapped thermal profile ID 0x%02x\n", id);
continue;
}
- mode = FIELD_GET(AWCC_THERMAL_MODE_MASK, id);
- profile = awcc_mode_to_platform_profile[mode];
priv->supported_profiles[profile] = id;
-
__set_bit(profile, choices);
}
@@ -1318,14 +1308,14 @@ static int awcc_platform_profile_probe(void *drvdata, unsigned long *choices)
if (awcc->gmode) {
priv->supported_profiles[PLATFORM_PROFILE_PERFORMANCE] =
- AWCC_SPECIAL_PROFILE_GMODE;
+ AWCC_PROFILE_SPECIAL_GMODE;
__set_bit(PLATFORM_PROFILE_PERFORMANCE, choices);
}
/* Every model supports the "custom" profile */
priv->supported_profiles[PLATFORM_PROFILE_CUSTOM] =
- AWCC_SPECIAL_PROFILE_CUSTOM;
+ AWCC_PROFILE_SPECIAL_CUSTOM;
__set_bit(PLATFORM_PROFILE_CUSTOM, choices);
diff --git a/drivers/platform/x86/gpd-pocket-fan.c b/drivers/platform/x86/gpd-pocket-fan.c
index 7a20f68ae206..c9236738f896 100644
--- a/drivers/platform/x86/gpd-pocket-fan.c
+++ b/drivers/platform/x86/gpd-pocket-fan.c
@@ -112,14 +112,14 @@ set_speed:
gpd_pocket_fan_set_speed(fan, speed);
/* When mostly idle (low temp/speed), slow down the poll interval. */
- queue_delayed_work(system_wq, &fan->work,
+ queue_delayed_work(system_percpu_wq, &fan->work,
msecs_to_jiffies(4000 / (speed + 1)));
}
static void gpd_pocket_fan_force_update(struct gpd_pocket_fan_data *fan)
{
fan->last_speed = -1;
- mod_delayed_work(system_wq, &fan->work, 0);
+ mod_delayed_work(system_percpu_wq, &fan->work, 0);
}
static int gpd_pocket_fan_probe(struct platform_device *pdev)
diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c
index ad9d9f97960f..f4ea1ea05997 100644
--- a/drivers/platform/x86/hp/hp-wmi.c
+++ b/drivers/platform/x86/hp/hp-wmi.c
@@ -63,12 +63,16 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45E9-BE91-3D44E2C707E4");
* contains "PerformanceControl".
*/
static const char * const omen_thermal_profile_boards[] = {
- "84DA", "84DB", "84DC", "8574", "8575", "860A", "87B5", "8572", "8573",
- "8600", "8601", "8602", "8605", "8606", "8607", "8746", "8747", "8749",
- "874A", "8603", "8604", "8748", "886B", "886C", "878A", "878B", "878C",
- "88C8", "88CB", "8786", "8787", "8788", "88D1", "88D2", "88F4", "88FD",
- "88F5", "88F6", "88F7", "88FE", "88FF", "8900", "8901", "8902", "8912",
- "8917", "8918", "8949", "894A", "89EB", "8BAD", "8A42", "8A15"
+ "84DA", "84DB", "84DC",
+ "8572", "8573", "8574", "8575",
+ "8600", "8601", "8602", "8603", "8604", "8605", "8606", "8607", "860A",
+ "8746", "8747", "8748", "8749", "874A", "8786", "8787", "8788", "878A",
+ "878B", "878C", "87B5",
+ "886B", "886C", "88C8", "88CB", "88D1", "88D2", "88F4", "88F5", "88F6",
+ "88F7", "88FD", "88FE", "88FF",
+ "8900", "8901", "8902", "8912", "8917", "8918", "8949", "894A", "89EB",
+ "8A15", "8A42",
+ "8BAD",
};
/* DMI Board names of Omen laptops that are specifically set to be thermal
@@ -76,7 +80,8 @@ static const char * const omen_thermal_profile_boards[] = {
* the get system design information WMI call returns
*/
static const char * const omen_thermal_profile_force_v0_boards[] = {
- "8607", "8746", "8747", "8749", "874A", "8748"
+ "8607",
+ "8746", "8747", "8748", "8749", "874A",
};
/* DMI board names of Omen laptops that have a thermal profile timer which will
@@ -84,12 +89,13 @@ static const char * const omen_thermal_profile_force_v0_boards[] = {
* "balanced" when reaching zero.
*/
static const char * const omen_timed_thermal_profile_boards[] = {
- "8BAD", "8A42", "8A15"
+ "8A15", "8A42",
+ "8BAD",
};
/* DMI Board names of Victus 16-d1xxx laptops */
static const char * const victus_thermal_profile_boards[] = {
- "8A25"
+ "8A25",
};
/* DMI Board names of Victus 16-r and Victus 16-s laptops */
diff --git a/drivers/platform/x86/intel/hid.c b/drivers/platform/x86/intel/hid.c
index 9c07a7faf18f..560cc063198e 100644
--- a/drivers/platform/x86/intel/hid.c
+++ b/drivers/platform/x86/intel/hid.c
@@ -177,6 +177,18 @@ static const struct dmi_system_id dmi_vgbs_allow_list[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "HP Elite Dragonfly G2 Notebook PC"),
},
},
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Dell Pro Rugged 10 Tablet RA00260"),
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Dell Pro Rugged 12 Tablet RA02260"),
+ },
+ },
{ }
};
diff --git a/drivers/platform/x86/intel/pmc/arl.c b/drivers/platform/x86/intel/pmc/arl.c
index 17ad87b392ab..eb23bc68340a 100644
--- a/drivers/platform/x86/intel/pmc/arl.c
+++ b/drivers/platform/x86/intel/pmc/arl.c
@@ -281,6 +281,7 @@ static const struct pmc_reg_map arl_socs_reg_map = {
.etr3_offset = ETR3_OFFSET,
.pson_residency_offset = TGL_PSON_RESIDENCY_OFFSET,
.pson_residency_counter_step = TGL_PSON_RES_COUNTER_STEP,
+ .lpm_req_guid = SOCS_LPM_REQ_GUID,
};
static const struct pmc_bit_map arl_pchs_ltr_show_map[] = {
@@ -648,26 +649,23 @@ static const struct pmc_reg_map arl_pchs_reg_map = {
.lpm_num_maps = ADL_LPM_NUM_MAPS,
.lpm_reg_index = ARL_LPM_REG_INDEX,
.etr3_offset = ETR3_OFFSET,
+ .lpm_req_guid = PCHS_LPM_REQ_GUID,
};
static struct pmc_info arl_pmc_info_list[] = {
{
- .guid = IOEP_LPM_REQ_GUID,
.devid = PMC_DEVID_ARL_IOEP,
.map = &mtl_ioep_reg_map,
},
{
- .guid = SOCS_LPM_REQ_GUID,
.devid = PMC_DEVID_ARL_SOCS,
.map = &arl_socs_reg_map,
},
{
- .guid = PCHS_LPM_REQ_GUID,
.devid = PMC_DEVID_ARL_PCHS,
.map = &arl_pchs_reg_map,
},
{
- .guid = SOCM_LPM_REQ_GUID,
.devid = PMC_DEVID_ARL_SOCM,
.map = &mtl_socm_reg_map,
},
@@ -720,9 +718,10 @@ static int arl_h_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_
return generic_core_init(pmcdev, pmc_dev_info);
}
+static u32 ARL_PMT_DMU_GUIDS[] = {ARL_PMT_DMU_GUID, 0x0};
struct pmc_dev_info arl_pmc_dev = {
.pci_func = 0,
- .dmu_guid = ARL_PMT_DMU_GUID,
+ .dmu_guids = ARL_PMT_DMU_GUIDS,
.regmap_list = arl_pmc_info_list,
.map = &arl_socs_reg_map,
.sub_req_show = &pmc_core_substate_req_regs_fops,
@@ -732,9 +731,10 @@ struct pmc_dev_info arl_pmc_dev = {
.sub_req = pmc_core_pmt_get_lpm_req,
};
+static u32 ARL_H_PMT_DMU_GUIDS[] = {ARL_PMT_DMU_GUID, ARL_H_PMT_DMU_GUID, 0x0};
struct pmc_dev_info arl_h_pmc_dev = {
.pci_func = 2,
- .dmu_guid = ARL_PMT_DMU_GUID,
+ .dmu_guids = ARL_H_PMT_DMU_GUIDS,
.regmap_list = arl_pmc_info_list,
.map = &mtl_socm_reg_map,
.sub_req_show = &pmc_core_substate_req_regs_fops,
diff --git a/drivers/platform/x86/intel/pmc/core.c b/drivers/platform/x86/intel/pmc/core.c
index ac3d19ae8c56..7d7ae8a40b0e 100644
--- a/drivers/platform/x86/intel/pmc/core.c
+++ b/drivers/platform/x86/intel/pmc/core.c
@@ -20,6 +20,7 @@ enum header_type {
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/dmi.h>
+#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/pci.h>
@@ -311,20 +312,20 @@ static inline u8 pmc_core_reg_read_byte(struct pmc *pmc, int offset)
}
static void pmc_core_display_map(struct seq_file *s, int index, int idx, int ip,
- int pmc_index, u8 pf_reg, const struct pmc_bit_map **pf_map)
+ int pmc_idx, u8 pf_reg, const struct pmc_bit_map **pf_map)
{
seq_printf(s, "PMC%d:PCH IP: %-2d - %-32s\tState: %s\n",
- pmc_index, ip, pf_map[idx][index].name,
+ pmc_idx, ip, pf_map[idx][index].name,
pf_map[idx][index].bit_mask & pf_reg ? "Off" : "On");
}
static int pmc_core_ppfear_show(struct seq_file *s, void *unused)
{
struct pmc_dev *pmcdev = s->private;
- unsigned int i;
+ unsigned int pmc_idx;
- for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) {
- struct pmc *pmc = pmcdev->pmcs[i];
+ for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); ++pmc_idx) {
+ struct pmc *pmc = pmcdev->pmcs[pmc_idx];
const struct pmc_bit_map **maps;
u8 pf_regs[PPFEAR_MAX_NUM_ENTRIES];
unsigned int index, iter, idx, ip = 0;
@@ -342,7 +343,7 @@ static int pmc_core_ppfear_show(struct seq_file *s, void *unused)
for (idx = 0; maps[idx]; idx++) {
for (index = 0; maps[idx][index].name &&
index < pmc->map->ppfear_buckets * 8; ip++, index++)
- pmc_core_display_map(s, index, idx, ip, i,
+ pmc_core_display_map(s, index, idx, ip, pmc_idx,
pf_regs[index / 8], maps);
}
}
@@ -471,7 +472,7 @@ int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value, int ignore)
struct pmc *pmc;
const struct pmc_reg_map *map;
u32 reg;
- unsigned int pmc_index;
+ unsigned int pmc_idx;
int ltr_index;
ltr_index = value;
@@ -479,8 +480,8 @@ int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value, int ignore)
* is based on the contiguous indexes from ltr_show output.
* pmc index and ltr index needs to be calculated from it.
*/
- for (pmc_index = 0; pmc_index < ARRAY_SIZE(pmcdev->pmcs) && ltr_index >= 0; pmc_index++) {
- pmc = pmcdev->pmcs[pmc_index];
+ for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs) && ltr_index >= 0; pmc_idx++) {
+ pmc = pmcdev->pmcs[pmc_idx];
if (!pmc)
continue;
@@ -497,10 +498,10 @@ int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value, int ignore)
ltr_index = ltr_index - (map->ltr_ignore_max + 2) - 1;
}
- if (pmc_index >= ARRAY_SIZE(pmcdev->pmcs) || ltr_index < 0)
+ if (pmc_idx >= ARRAY_SIZE(pmcdev->pmcs) || ltr_index < 0)
return -EINVAL;
- pr_debug("ltr_ignore for pmc%d: ltr_index:%d\n", pmc_index, ltr_index);
+ pr_debug("ltr_ignore for pmc%d: ltr_index:%d\n", pmc_idx, ltr_index);
guard(mutex)(&pmcdev->lock);
@@ -635,14 +636,14 @@ static int pmc_core_ltr_show(struct seq_file *s, void *unused)
u64 decoded_snoop_ltr, decoded_non_snoop_ltr, val;
u32 ltr_raw_data, scale;
u16 snoop_ltr, nonsnoop_ltr;
- unsigned int i, index, ltr_index = 0;
+ unsigned int pmc_idx, index, ltr_index = 0;
- for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) {
+ for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); ++pmc_idx) {
struct pmc *pmc;
const struct pmc_bit_map *map;
u32 ltr_ign_reg;
- pmc = pmcdev->pmcs[i];
+ pmc = pmcdev->pmcs[pmc_idx];
if (!pmc)
continue;
@@ -676,7 +677,7 @@ static int pmc_core_ltr_show(struct seq_file *s, void *unused)
}
seq_printf(s, "%d\tPMC%d:%-32s\tLTR: RAW: 0x%-16x\tNon-Snoop(ns): %-16llu\tSnoop(ns): %-16llu\tLTR_IGNORE: %d\n",
- ltr_index, i, map[index].name, ltr_raw_data,
+ ltr_index, pmc_idx, map[index].name, ltr_raw_data,
decoded_non_snoop_ltr,
decoded_snoop_ltr, ltr_ign_data);
ltr_index++;
@@ -689,15 +690,15 @@ DEFINE_SHOW_ATTRIBUTE(pmc_core_ltr);
static int pmc_core_s0ix_blocker_show(struct seq_file *s, void *unused)
{
struct pmc_dev *pmcdev = s->private;
- unsigned int pmcidx;
+ unsigned int pmc_idx;
- for (pmcidx = 0; pmcidx < ARRAY_SIZE(pmcdev->pmcs); pmcidx++) {
+ for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); pmc_idx++) {
const struct pmc_bit_map **maps;
unsigned int arr_size, r_idx;
u32 offset, counter;
struct pmc *pmc;
- pmc = pmcdev->pmcs[pmcidx];
+ pmc = pmcdev->pmcs[pmc_idx];
if (!pmc)
continue;
maps = pmc->map->s0ix_blocker_maps;
@@ -711,7 +712,7 @@ static int pmc_core_s0ix_blocker_show(struct seq_file *s, void *unused)
if (!map->blk)
continue;
counter = pmc_core_reg_read(pmc, offset);
- seq_printf(s, "PMC%d:%-30s %-30d\n", pmcidx,
+ seq_printf(s, "PMC%d:%-30s %-30d\n", pmc_idx,
map->name, counter);
offset += map->blk * S0IX_BLK_SIZE;
}
@@ -723,13 +724,13 @@ DEFINE_SHOW_ATTRIBUTE(pmc_core_s0ix_blocker);
static void pmc_core_ltr_ignore_all(struct pmc_dev *pmcdev)
{
- unsigned int i;
+ unsigned int pmc_idx;
- for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); i++) {
+ for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); pmc_idx++) {
struct pmc *pmc;
u32 ltr_ign;
- pmc = pmcdev->pmcs[i];
+ pmc = pmcdev->pmcs[pmc_idx];
if (!pmc)
continue;
@@ -750,12 +751,12 @@ static void pmc_core_ltr_ignore_all(struct pmc_dev *pmcdev)
static void pmc_core_ltr_restore_all(struct pmc_dev *pmcdev)
{
- unsigned int i;
+ unsigned int pmc_idx;
- for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); i++) {
+ for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); pmc_idx++) {
struct pmc *pmc;
- pmc = pmcdev->pmcs[i];
+ pmc = pmcdev->pmcs[pmc_idx];
if (!pmc)
continue;
@@ -794,10 +795,10 @@ DEFINE_SHOW_ATTRIBUTE(pmc_core_substate_res);
static int pmc_core_substate_sts_regs_show(struct seq_file *s, void *unused)
{
struct pmc_dev *pmcdev = s->private;
- unsigned int i;
+ unsigned int pmc_idx;
- for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) {
- struct pmc *pmc = pmcdev->pmcs[i];
+ for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); ++pmc_idx) {
+ struct pmc *pmc = pmcdev->pmcs[pmc_idx];
const struct pmc_bit_map **maps;
u32 offset;
@@ -805,7 +806,7 @@ static int pmc_core_substate_sts_regs_show(struct seq_file *s, void *unused)
continue;
maps = pmc->map->lpm_sts;
offset = pmc->map->lpm_status_offset;
- pmc_core_lpm_display(pmc, NULL, s, offset, i, "STATUS", maps);
+ pmc_core_lpm_display(pmc, NULL, s, offset, pmc_idx, "STATUS", maps);
}
return 0;
@@ -815,10 +816,10 @@ DEFINE_SHOW_ATTRIBUTE(pmc_core_substate_sts_regs);
static int pmc_core_substate_l_sts_regs_show(struct seq_file *s, void *unused)
{
struct pmc_dev *pmcdev = s->private;
- unsigned int i;
+ unsigned int pmc_idx;
- for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) {
- struct pmc *pmc = pmcdev->pmcs[i];
+ for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); ++pmc_idx) {
+ struct pmc *pmc = pmcdev->pmcs[pmc_idx];
const struct pmc_bit_map **maps;
u32 offset;
@@ -826,7 +827,7 @@ static int pmc_core_substate_l_sts_regs_show(struct seq_file *s, void *unused)
continue;
maps = pmc->map->lpm_sts;
offset = pmc->map->lpm_live_status_offset;
- pmc_core_lpm_display(pmc, NULL, s, offset, i, "LIVE_STATUS", maps);
+ pmc_core_lpm_display(pmc, NULL, s, offset, pmc_idx, "LIVE_STATUS", maps);
}
return 0;
@@ -919,11 +920,11 @@ static int pmc_core_substate_req_regs_show(struct seq_file *s, void *unused)
u32 sts_offset;
u32 sts_offset_live;
u32 *lpm_req_regs;
- unsigned int mp, pmc_index;
+ unsigned int mp, pmc_idx;
int num_maps;
- for (pmc_index = 0; pmc_index < ARRAY_SIZE(pmcdev->pmcs); ++pmc_index) {
- struct pmc *pmc = pmcdev->pmcs[pmc_index];
+ for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); ++pmc_idx) {
+ struct pmc *pmc = pmcdev->pmcs[pmc_idx];
const struct pmc_bit_map **maps;
if (!pmc)
@@ -944,7 +945,7 @@ static int pmc_core_substate_req_regs_show(struct seq_file *s, void *unused)
continue;
/* Display the header */
- pmc_core_substate_req_header_show(s, pmc_index, HEADER_STATUS);
+ pmc_core_substate_req_header_show(s, pmc_idx, HEADER_STATUS);
/* Loop over maps */
for (mp = 0; mp < num_maps; mp++) {
@@ -982,7 +983,7 @@ static int pmc_core_substate_req_regs_show(struct seq_file *s, void *unused)
}
/* Display the element name in the first column */
- seq_printf(s, "pmc%d: %34s |", pmc_index, map[i].name);
+ seq_printf(s, "pmc%d: %34s |", pmc_idx, map[i].name);
/* Loop over the enabled states and display if required */
pmc_for_each_mode(mode, pmcdev) {
@@ -1281,7 +1282,20 @@ int get_primary_reg_base(struct pmc *pmc)
return 0;
}
-void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, u32 guid)
+static struct telem_endpoint *pmc_core_register_endpoint(struct pci_dev *pcidev, u32 *guids)
+{
+ struct telem_endpoint *ep;
+ unsigned int i;
+
+ for (i = 0; guids[i]; i++) {
+ ep = pmt_telem_find_and_register_endpoint(pcidev, guids[i], 0);
+ if (!IS_ERR(ep))
+ return ep;
+ }
+ return ERR_PTR(-ENODEV);
+}
+
+void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, u32 *guids)
{
struct telem_endpoint *ep;
struct pci_dev *pcidev;
@@ -1292,7 +1306,7 @@ void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, u32 guid)
return;
}
- ep = pmt_telem_find_and_register_endpoint(pcidev, guid, 0);
+ ep = pmc_core_register_endpoint(pcidev, guids);
pci_dev_put(pcidev);
if (IS_ERR(ep)) {
dev_err(&pmcdev->pdev->dev,
@@ -1302,8 +1316,6 @@ void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, u32 guid)
}
pmcdev->punit_ep = ep;
-
- pmcdev->has_die_c6 = true;
pmcdev->die_c6_offset = MTL_PMT_DMU_DIE_C6_OFFSET;
}
@@ -1423,22 +1435,13 @@ static void pmc_core_dbgfs_register(struct pmc_dev *pmcdev, struct pmc_dev_info
pmcdev->dbgfs_dir, primary_pmc, &pmc_core_pson_residency);
}
- if (pmcdev->has_die_c6) {
+ if (pmcdev->punit_ep) {
debugfs_create_file("die_c6_us_show", 0444,
pmcdev->dbgfs_dir, pmcdev,
&pmc_core_die_c6_us_fops);
}
}
-static u32 pmc_core_find_guid(struct pmc_info *list, const struct pmc_reg_map *map)
-{
- for (; list->map; ++list)
- if (list->map == map)
- return list->guid;
-
- return 0;
-}
-
/*
* This function retrieves low power mode requirement data from PMC Low
* Power Mode (LPM) table.
@@ -1553,26 +1556,24 @@ static int pmc_core_get_telem_info(struct pmc_dev *pmcdev, struct pmc_dev_info *
{
struct pci_dev *pcidev __free(pci_dev_put) = NULL;
struct telem_endpoint *ep;
- unsigned int i;
- u32 guid;
+ unsigned int pmc_idx;
int ret;
pcidev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(20, pmc_dev_info->pci_func));
if (!pcidev)
return -ENODEV;
- for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) {
+ for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); ++pmc_idx) {
struct pmc *pmc;
- pmc = pmcdev->pmcs[i];
+ pmc = pmcdev->pmcs[pmc_idx];
if (!pmc)
continue;
- guid = pmc_core_find_guid(pmcdev->regmap_list, pmc->map);
- if (!guid)
+ if (!pmc->map->lpm_req_guid)
return -ENXIO;
- ep = pmt_telem_find_and_register_endpoint(pcidev, guid, 0);
+ ep = pmt_telem_find_and_register_endpoint(pcidev, pmc->map->lpm_req_guid, 0);
if (IS_ERR(ep)) {
dev_dbg(&pmcdev->pdev->dev, "couldn't get telem endpoint %pe", ep);
return -EPROBE_DEFER;
@@ -1596,7 +1597,7 @@ static const struct pmc_reg_map *pmc_core_find_regmap(struct pmc_info *list, u16
return NULL;
}
-static int pmc_core_pmc_add(struct pmc_dev *pmcdev, unsigned int pmc_index)
+static int pmc_core_pmc_add(struct pmc_dev *pmcdev, unsigned int pmc_idx)
{
struct pmc_ssram_telemetry pmc_ssram_telemetry;
@@ -1604,7 +1605,7 @@ static int pmc_core_pmc_add(struct pmc_dev *pmcdev, unsigned int pmc_index)
struct pmc *pmc;
int ret;
- ret = pmc_ssram_telemetry_get_pmc_info(pmc_index, &pmc_ssram_telemetry);
+ ret = pmc_ssram_telemetry_get_pmc_info(pmc_idx, &pmc_ssram_telemetry);
if (ret)
return ret;
@@ -1612,7 +1613,7 @@ static int pmc_core_pmc_add(struct pmc_dev *pmcdev, unsigned int pmc_index)
if (!map)
return -ENODEV;
- pmc = pmcdev->pmcs[pmc_index];
+ pmc = pmcdev->pmcs[pmc_idx];
/* Memory for primary PMC has been allocated */
if (!pmc) {
pmc = devm_kzalloc(&pmcdev->pdev->dev, sizeof(*pmc), GFP_KERNEL);
@@ -1629,7 +1630,7 @@ static int pmc_core_pmc_add(struct pmc_dev *pmcdev, unsigned int pmc_index)
return -ENOMEM;
}
- pmcdev->pmcs[pmc_index] = pmc;
+ pmcdev->pmcs[pmc_idx] = pmc;
return 0;
}
@@ -1689,8 +1690,8 @@ int generic_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info)
}
pmc_core_get_low_power_modes(pmcdev);
- if (pmc_dev_info->dmu_guid)
- pmc_core_punit_pmt_init(pmcdev, pmc_dev_info->dmu_guid);
+ if (pmc_dev_info->dmu_guids)
+ pmc_core_punit_pmt_init(pmcdev, pmc_dev_info->dmu_guids);
if (ssram) {
ret = pmc_core_get_telem_info(pmcdev, pmc_dev_info);
@@ -1701,8 +1702,8 @@ int generic_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info)
return 0;
unmap_regbase:
- for (unsigned int i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) {
- struct pmc *pmc = pmcdev->pmcs[i];
+ for (unsigned int pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); ++pmc_idx) {
+ struct pmc *pmc = pmcdev->pmcs[pmc_idx];
if (pmc && pmc->regbase)
iounmap(pmc->regbase);
@@ -1795,10 +1796,10 @@ static void pmc_core_do_dmi_quirks(struct pmc *pmc)
static void pmc_core_clean_structure(struct platform_device *pdev)
{
struct pmc_dev *pmcdev = platform_get_drvdata(pdev);
- unsigned int i;
+ unsigned int pmc_idx;
- for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) {
- struct pmc *pmc = pmcdev->pmcs[i];
+ for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); ++pmc_idx) {
+ struct pmc *pmc = pmcdev->pmcs[pmc_idx];
if (pmc && pmc->regbase)
iounmap(pmc->regbase);
@@ -1958,7 +1959,7 @@ int pmc_core_resume_common(struct pmc_dev *pmcdev)
struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN];
const struct pmc_bit_map **maps = pmc->map->lpm_sts;
int offset = pmc->map->lpm_status_offset;
- unsigned int i;
+ unsigned int pmc_idx, i;
/* Check if the syspend used S0ix */
if (pm_suspend_via_firmware())
@@ -1996,13 +1997,13 @@ int pmc_core_resume_common(struct pmc_dev *pmcdev)
if (pmc->map->slps0_dbg_maps)
pmc_core_slps0_display(pmc, dev, NULL);
- for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) {
- struct pmc *pmc = pmcdev->pmcs[i];
+ for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); ++pmc_idx) {
+ struct pmc *pmc = pmcdev->pmcs[pmc_idx];
if (!pmc)
continue;
if (pmc->map->lpm_sts)
- pmc_core_lpm_display(pmc, dev, NULL, offset, i, "STATUS", maps);
+ pmc_core_lpm_display(pmc, dev, NULL, offset, pmc_idx, "STATUS", maps);
}
return 0;
diff --git a/drivers/platform/x86/intel/pmc/core.h b/drivers/platform/x86/intel/pmc/core.h
index f4dadb696a31..272fb4f57f34 100644
--- a/drivers/platform/x86/intel/pmc/core.h
+++ b/drivers/platform/x86/intel/pmc/core.h
@@ -282,7 +282,8 @@ enum ppfear_regs {
/* Die C6 from PUNIT telemetry */
#define MTL_PMT_DMU_DIE_C6_OFFSET 15
#define MTL_PMT_DMU_GUID 0x1A067102
-#define ARL_PMT_DMU_GUID 0x1A06A000
+#define ARL_PMT_DMU_GUID 0x1A06A102
+#define ARL_H_PMT_DMU_GUID 0x1A06A101
#define LNL_PMC_MMIO_REG_LEN 0x2708
#define LNL_PMC_LTR_OSSE 0x1B88
@@ -303,6 +304,8 @@ enum ppfear_regs {
/* Wildcat Lake */
#define WCL_PMC_LTR_RESERVED 0x1B64
#define WCL_PCD_PMC_MMIO_REG_LEN 0x3178
+#define WCL_NUM_S0IX_BLOCKER 94
+#define WCL_BLK_REQ_OFFSET 50
/* SSRAM PMC Device ID */
/* LNL */
@@ -355,6 +358,7 @@ struct pmc_bit_map {
* @s0ix_blocker_offset PWRMBASE offset to S0ix blocker counter
* @num_s0ix_blocker: Number of S0ix blockers
* @blocker_req_offset: Telemetry offset to S0ix blocker low power mode substate requirement table
+ * @lpm_req_guid: Telemetry GUID to read low power mode substate requirement table
*
* Each PCH has unique set of register offsets and bit indexes. This structure
* captures them to have a common implementation.
@@ -396,6 +400,8 @@ struct pmc_reg_map {
const u8 *lpm_reg_index;
const u32 pson_residency_offset;
const u32 pson_residency_counter_step;
+ /* GUID for telemetry regions */
+ const u32 lpm_req_guid;
};
/**
@@ -405,7 +411,6 @@ struct pmc_reg_map {
* specific attributes
*/
struct pmc_info {
- u32 guid;
u16 devid;
const struct pmc_reg_map *map;
};
@@ -465,7 +470,6 @@ struct pmc_dev {
u64 *pkgc_res_cnt;
u8 num_of_pkgc;
- bool has_die_c6;
u32 die_c6_offset;
struct telem_endpoint *punit_ep;
struct pmc_info *regmap_list;
@@ -481,7 +485,7 @@ enum pmc_index {
/**
* struct pmc_dev_info - Structure to keep PMC device info
* @pci_func: Function number of the primary PMC
- * @dmu_guid: Die Management Unit GUID
+ * @dmu_guids: List of Die Management Unit GUID
* @regmap_list: Pointer to a list of pmc_info structure that could be
* available for the platform. When set, this field implies
* SSRAM support.
@@ -495,7 +499,7 @@ enum pmc_index {
*/
struct pmc_dev_info {
u8 pci_func;
- u32 dmu_guid;
+ u32 *dmu_guids;
struct pmc_info *regmap_list;
const struct pmc_reg_map *map;
const struct file_operations *sub_req_show;
@@ -532,7 +536,7 @@ int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value, int ignore);
int pmc_core_resume_common(struct pmc_dev *pmcdev);
int get_primary_reg_base(struct pmc *pmc);
void pmc_core_get_low_power_modes(struct pmc_dev *pmcdev);
-void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, u32 guid);
+void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, u32 *guids);
void pmc_core_set_device_d3(unsigned int device);
int generic_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info);
diff --git a/drivers/platform/x86/intel/pmc/lnl.c b/drivers/platform/x86/intel/pmc/lnl.c
index 6fa027e7071f..1cd81ee54dcf 100644
--- a/drivers/platform/x86/intel/pmc/lnl.c
+++ b/drivers/platform/x86/intel/pmc/lnl.c
@@ -533,11 +533,11 @@ static const struct pmc_reg_map lnl_socm_reg_map = {
.s0ix_blocker_maps = lnl_blk_maps,
.s0ix_blocker_offset = LNL_S0IX_BLOCKER_OFFSET,
.lpm_reg_index = LNL_LPM_REG_INDEX,
+ .lpm_req_guid = SOCM_LPM_REQ_GUID,
};
static struct pmc_info lnl_pmc_info_list[] = {
{
- .guid = SOCM_LPM_REQ_GUID,
.devid = PMC_DEVID_LNL_SOCM,
.map = &lnl_socm_reg_map,
},
diff --git a/drivers/platform/x86/intel/pmc/mtl.c b/drivers/platform/x86/intel/pmc/mtl.c
index 0b87e10f864e..57508cbf9cd4 100644
--- a/drivers/platform/x86/intel/pmc/mtl.c
+++ b/drivers/platform/x86/intel/pmc/mtl.c
@@ -473,6 +473,7 @@ const struct pmc_reg_map mtl_socm_reg_map = {
.lpm_status_offset = MTL_LPM_STATUS_OFFSET,
.lpm_live_status_offset = MTL_LPM_LIVE_STATUS_OFFSET,
.lpm_reg_index = MTL_LPM_REG_INDEX,
+ .lpm_req_guid = SOCP_LPM_REQ_GUID,
};
static const struct pmc_bit_map mtl_ioep_pfear_map[] = {
@@ -797,6 +798,7 @@ const struct pmc_reg_map mtl_ioep_reg_map = {
.lpm_en_offset = MTL_LPM_EN_OFFSET,
.lpm_sts_latch_en_offset = MTL_LPM_STATUS_LATCH_EN_OFFSET,
.lpm_reg_index = MTL_LPM_REG_INDEX,
+ .lpm_req_guid = IOEP_LPM_REQ_GUID,
};
static const struct pmc_bit_map mtl_ioem_pfear_map[] = {
@@ -944,21 +946,19 @@ static const struct pmc_reg_map mtl_ioem_reg_map = {
.lpm_res_counter_step_x2 = TGL_PMC_LPM_RES_COUNTER_STEP_X2,
.lpm_residency_offset = MTL_LPM_RESIDENCY_OFFSET,
.lpm_reg_index = MTL_LPM_REG_INDEX,
+ .lpm_req_guid = IOEM_LPM_REQ_GUID,
};
static struct pmc_info mtl_pmc_info_list[] = {
{
- .guid = SOCP_LPM_REQ_GUID,
.devid = PMC_DEVID_MTL_SOCM,
.map = &mtl_socm_reg_map,
},
{
- .guid = IOEP_LPM_REQ_GUID,
.devid = PMC_DEVID_MTL_IOEP,
.map = &mtl_ioep_reg_map,
},
{
- .guid = IOEM_LPM_REQ_GUID,
.devid = PMC_DEVID_MTL_IOEM,
.map = &mtl_ioem_reg_map
},
@@ -992,9 +992,10 @@ static int mtl_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_in
return generic_core_init(pmcdev, pmc_dev_info);
}
+static u32 MTL_PMT_DMU_GUIDS[] = {MTL_PMT_DMU_GUID, 0x0};
struct pmc_dev_info mtl_pmc_dev = {
.pci_func = 2,
- .dmu_guid = MTL_PMT_DMU_GUID,
+ .dmu_guids = MTL_PMT_DMU_GUIDS,
.regmap_list = mtl_pmc_info_list,
.map = &mtl_socm_reg_map,
.sub_req_show = &pmc_core_substate_req_regs_fops,
diff --git a/drivers/platform/x86/intel/pmc/ptl.c b/drivers/platform/x86/intel/pmc/ptl.c
index 1b35b84e06fa..1f48e2bbc699 100644
--- a/drivers/platform/x86/intel/pmc/ptl.c
+++ b/drivers/platform/x86/intel/pmc/ptl.c
@@ -528,16 +528,15 @@ static const struct pmc_reg_map ptl_pcdp_reg_map = {
.s0ix_blocker_offset = LNL_S0IX_BLOCKER_OFFSET,
.num_s0ix_blocker = PTL_NUM_S0IX_BLOCKER,
.blocker_req_offset = PTL_BLK_REQ_OFFSET,
+ .lpm_req_guid = PCDP_LPM_REQ_GUID,
};
static struct pmc_info ptl_pmc_info_list[] = {
{
- .guid = PCDP_LPM_REQ_GUID,
.devid = PMC_DEVID_PTL_PCDH,
.map = &ptl_pcdp_reg_map,
},
{
- .guid = PCDP_LPM_REQ_GUID,
.devid = PMC_DEVID_PTL_PCDP,
.map = &ptl_pcdp_reg_map,
},
diff --git a/drivers/platform/x86/intel/pmc/wcl.c b/drivers/platform/x86/intel/pmc/wcl.c
index 85e90a639e65..a45707e6364f 100644
--- a/drivers/platform/x86/intel/pmc/wcl.c
+++ b/drivers/platform/x86/intel/pmc/wcl.c
@@ -11,6 +11,9 @@
#include "core.h"
+/* PMC SSRAM PMT Telemetry GUIDS */
+#define PCDN_LPM_REQ_GUID 0x33747648
+
static const struct pmc_bit_map wcl_pcdn_pfear_map[] = {
{"PMC_0", BIT(0)},
{"FUSE_OSSE", BIT(1)},
@@ -453,6 +456,17 @@ static const struct pmc_reg_map wcl_pcdn_reg_map = {
.lpm_live_status_offset = MTL_LPM_LIVE_STATUS_OFFSET,
.s0ix_blocker_maps = wcl_pcdn_blk_maps,
.s0ix_blocker_offset = LNL_S0IX_BLOCKER_OFFSET,
+ .num_s0ix_blocker = WCL_NUM_S0IX_BLOCKER,
+ .blocker_req_offset = WCL_BLK_REQ_OFFSET,
+ .lpm_req_guid = PCDN_LPM_REQ_GUID,
+};
+
+static struct pmc_info wcl_pmc_info_list[] = {
+ {
+ .devid = PMC_DEVID_WCL_PCDN,
+ .map = &wcl_pcdn_reg_map,
+ },
+ {}
};
#define WCL_NPU_PCI_DEV 0xfd3e
@@ -479,8 +493,12 @@ static int wcl_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_in
}
struct pmc_dev_info wcl_pmc_dev = {
+ .pci_func = 2,
+ .regmap_list = wcl_pmc_info_list,
.map = &wcl_pcdn_reg_map,
+ .sub_req_show = &pmc_core_substate_blk_req_fops,
.suspend = cnl_suspend,
.resume = wcl_resume,
.init = wcl_core_init,
+ .sub_req = pmc_core_pmt_get_blk_sub_req,
};
diff --git a/drivers/platform/x86/intel/vsec.c b/drivers/platform/x86/intel/vsec.c
index f66f0ce8559b..ecfc7703f201 100644
--- a/drivers/platform/x86/intel/vsec.c
+++ b/drivers/platform/x86/intel/vsec.c
@@ -765,6 +765,7 @@ static const struct intel_vsec_platform_info lnl_info = {
#define PCI_DEVICE_ID_INTEL_VSEC_TGL 0x9a0d
#define PCI_DEVICE_ID_INTEL_VSEC_LNL_M 0x647d
#define PCI_DEVICE_ID_INTEL_VSEC_PTL 0xb07d
+#define PCI_DEVICE_ID_INTEL_VSEC_WCL 0xfd7d
static const struct pci_device_id intel_vsec_pci_ids[] = {
{ PCI_DEVICE_DATA(INTEL, VSEC_ADL, &tgl_info) },
{ PCI_DEVICE_DATA(INTEL, VSEC_DG1, &dg1_info) },
@@ -776,6 +777,7 @@ static const struct pci_device_id intel_vsec_pci_ids[] = {
{ PCI_DEVICE_DATA(INTEL, VSEC_TGL, &tgl_info) },
{ PCI_DEVICE_DATA(INTEL, VSEC_LNL_M, &lnl_info) },
{ PCI_DEVICE_DATA(INTEL, VSEC_PTL, &mtl_info) },
+ { PCI_DEVICE_DATA(INTEL, VSEC_WCL, &mtl_info) },
{ }
};
MODULE_DEVICE_TABLE(pci, intel_vsec_pci_ids);
diff --git a/drivers/platform/x86/lenovo/ideapad-laptop.c b/drivers/platform/x86/lenovo/ideapad-laptop.c
index fcebfbaf0460..5171a077f62c 100644
--- a/drivers/platform/x86/lenovo/ideapad-laptop.c
+++ b/drivers/platform/x86/lenovo/ideapad-laptop.c
@@ -31,6 +31,7 @@
#include <linux/power_supply.h>
#include <linux/rfkill.h>
#include <linux/seq_file.h>
+#include <linux/string_choices.h>
#include <linux/sysfs.h>
#include <linux/types.h>
#include <linux/wmi.h>
@@ -62,13 +63,27 @@ enum {
CFG_OSD_CAM_BIT = 31,
};
+/*
+ * There are two charge modes supported by the GBMD/SBMC interface:
+ * - "Rapid Charge": increase power to speed up charging
+ * - "Conservation Mode": stop charging at 60-80% (depends on model)
+ *
+ * The interface doesn't prohibit enabling both modes at the same time.
+ * However, doing so is essentially meaningless, and the manufacturer utilities
+ * on Windows always make them mutually exclusive.
+ */
+
enum {
+ GBMD_RAPID_CHARGE_STATE_BIT = 2,
GBMD_CONSERVATION_STATE_BIT = 5,
+ GBMD_RAPID_CHARGE_SUPPORTED_BIT = 17,
};
enum {
SBMC_CONSERVATION_ON = 3,
SBMC_CONSERVATION_OFF = 5,
+ SBMC_RAPID_CHARGE_ON = 7,
+ SBMC_RAPID_CHARGE_OFF = 8,
};
enum {
@@ -158,6 +173,7 @@ struct ideapad_rfk_priv {
struct ideapad_private {
struct acpi_device *adev;
struct mutex vpc_mutex; /* protects the VPC calls */
+ struct mutex gbmd_sbmc_mutex; /* protects GBMD/SBMC calls */
struct rfkill *rfk[IDEAPAD_RFKILL_DEV_NUM];
struct ideapad_rfk_priv rfk_priv[IDEAPAD_RFKILL_DEV_NUM];
struct platform_device *platform_device;
@@ -166,9 +182,11 @@ struct ideapad_private {
struct ideapad_dytc_priv *dytc;
struct dentry *debug;
struct acpi_battery_hook battery_hook;
+ const struct power_supply_ext *battery_ext;
unsigned long cfg;
unsigned long r_touchpad_val;
struct {
+ bool rapid_charge : 1;
bool conservation_mode : 1;
bool dytc : 1;
bool fan_mode : 1;
@@ -455,37 +473,40 @@ static int debugfs_status_show(struct seq_file *s, void *data)
struct ideapad_private *priv = s->private;
unsigned long value;
- guard(mutex)(&priv->vpc_mutex);
-
- if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL_MAX, &value))
- seq_printf(s, "Backlight max: %lu\n", value);
- if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL, &value))
- seq_printf(s, "Backlight now: %lu\n", value);
- if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL_POWER, &value))
- seq_printf(s, "BL power value: %s (%lu)\n", value ? "on" : "off", value);
-
- seq_puts(s, "=====================\n");
-
- if (!read_ec_data(priv->adev->handle, VPCCMD_R_RF, &value))
- seq_printf(s, "Radio status: %s (%lu)\n", value ? "on" : "off", value);
- if (!read_ec_data(priv->adev->handle, VPCCMD_R_WIFI, &value))
- seq_printf(s, "Wifi status: %s (%lu)\n", value ? "on" : "off", value);
- if (!read_ec_data(priv->adev->handle, VPCCMD_R_BT, &value))
- seq_printf(s, "BT status: %s (%lu)\n", value ? "on" : "off", value);
- if (!read_ec_data(priv->adev->handle, VPCCMD_R_3G, &value))
- seq_printf(s, "3G status: %s (%lu)\n", value ? "on" : "off", value);
+ scoped_guard(mutex, &priv->vpc_mutex) {
+ if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL_MAX, &value))
+ seq_printf(s, "Backlight max: %lu\n", value);
+ if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL, &value))
+ seq_printf(s, "Backlight now: %lu\n", value);
+ if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL_POWER, &value))
+ seq_printf(s, "BL power value: %s (%lu)\n", str_on_off(value), value);
+
+ seq_puts(s, "=====================\n");
+
+ if (!read_ec_data(priv->adev->handle, VPCCMD_R_RF, &value))
+ seq_printf(s, "Radio status: %s (%lu)\n", str_on_off(value), value);
+ if (!read_ec_data(priv->adev->handle, VPCCMD_R_WIFI, &value))
+ seq_printf(s, "Wifi status: %s (%lu)\n", str_on_off(value), value);
+ if (!read_ec_data(priv->adev->handle, VPCCMD_R_BT, &value))
+ seq_printf(s, "BT status: %s (%lu)\n", str_on_off(value), value);
+ if (!read_ec_data(priv->adev->handle, VPCCMD_R_3G, &value))
+ seq_printf(s, "3G status: %s (%lu)\n", str_on_off(value), value);
+
+ seq_puts(s, "=====================\n");
+
+ if (!read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value))
+ seq_printf(s, "Touchpad status: %s (%lu)\n", str_on_off(value), value);
+ if (!read_ec_data(priv->adev->handle, VPCCMD_R_CAMERA, &value))
+ seq_printf(s, "Camera status: %s (%lu)\n", str_on_off(value), value);
+ }
seq_puts(s, "=====================\n");
- if (!read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value))
- seq_printf(s, "Touchpad status: %s (%lu)\n", value ? "on" : "off", value);
- if (!read_ec_data(priv->adev->handle, VPCCMD_R_CAMERA, &value))
- seq_printf(s, "Camera status: %s (%lu)\n", value ? "on" : "off", value);
-
- seq_puts(s, "=====================\n");
+ scoped_guard(mutex, &priv->gbmd_sbmc_mutex) {
+ if (!eval_gbmd(priv->adev->handle, &value))
+ seq_printf(s, "GBMD: %#010lx\n", value);
+ }
- if (!eval_gbmd(priv->adev->handle, &value))
- seq_printf(s, "GBMD: %#010lx\n", value);
if (!eval_hals(priv->adev->handle, &value))
seq_printf(s, "HALS: %#010lx\n", value);
@@ -622,10 +643,16 @@ static ssize_t conservation_mode_show(struct device *dev,
show_conservation_mode_deprecation_warning(dev);
- err = eval_gbmd(priv->adev->handle, &result);
- if (err)
- return err;
+ scoped_guard(mutex, &priv->gbmd_sbmc_mutex) {
+ err = eval_gbmd(priv->adev->handle, &result);
+ if (err)
+ return err;
+ }
+ /*
+ * For backward compatibility, ignore Rapid Charge while reporting the
+ * state of Conservation Mode.
+ */
return sysfs_emit(buf, "%d\n", !!test_bit(GBMD_CONSERVATION_STATE_BIT, &result));
}
@@ -643,6 +670,18 @@ static ssize_t conservation_mode_store(struct device *dev,
if (err)
return err;
+ guard(mutex)(&priv->gbmd_sbmc_mutex);
+
+ /*
+ * Prevent mutually exclusive modes from being set at the same time,
+ * but do not disable Rapid Charge while disabling Conservation Mode.
+ */
+ if (priv->features.rapid_charge && state) {
+ err = exec_sbmc(priv->adev->handle, SBMC_RAPID_CHARGE_OFF);
+ if (err)
+ return err;
+ }
+
err = exec_sbmc(priv->adev->handle, state ? SBMC_CONSERVATION_ON : SBMC_CONSERVATION_OFF);
if (err)
return err;
@@ -2007,15 +2046,39 @@ static int ideapad_psy_ext_set_prop(struct power_supply *psy,
const union power_supply_propval *val)
{
struct ideapad_private *priv = ext_data;
+ unsigned long op1, op2;
+ int err;
switch (val->intval) {
+ case POWER_SUPPLY_CHARGE_TYPE_FAST:
+ if (WARN_ON(!priv->features.rapid_charge))
+ return -EINVAL;
+
+ op1 = SBMC_CONSERVATION_OFF;
+ op2 = SBMC_RAPID_CHARGE_ON;
+ break;
case POWER_SUPPLY_CHARGE_TYPE_LONGLIFE:
- return exec_sbmc(priv->adev->handle, SBMC_CONSERVATION_ON);
+ op1 = SBMC_RAPID_CHARGE_OFF;
+ op2 = SBMC_CONSERVATION_ON;
+ break;
case POWER_SUPPLY_CHARGE_TYPE_STANDARD:
- return exec_sbmc(priv->adev->handle, SBMC_CONSERVATION_OFF);
+ op1 = SBMC_RAPID_CHARGE_OFF;
+ op2 = SBMC_CONSERVATION_OFF;
+ break;
default:
return -EINVAL;
}
+
+ guard(mutex)(&priv->gbmd_sbmc_mutex);
+
+ /* If !rapid_charge, op1 must be SBMC_RAPID_CHARGE_OFF. Skip it. */
+ if (priv->features.rapid_charge) {
+ err = exec_sbmc(priv->adev->handle, op1);
+ if (err)
+ return err;
+ }
+
+ return exec_sbmc(priv->adev->handle, op2);
}
static int ideapad_psy_ext_get_prop(struct power_supply *psy,
@@ -2025,14 +2088,29 @@ static int ideapad_psy_ext_get_prop(struct power_supply *psy,
union power_supply_propval *val)
{
struct ideapad_private *priv = ext_data;
+ bool is_rapid_charge, is_conservation;
unsigned long result;
int err;
- err = eval_gbmd(priv->adev->handle, &result);
- if (err)
- return err;
+ scoped_guard(mutex, &priv->gbmd_sbmc_mutex) {
+ err = eval_gbmd(priv->adev->handle, &result);
+ if (err)
+ return err;
+ }
+
+ is_rapid_charge = (priv->features.rapid_charge &&
+ test_bit(GBMD_RAPID_CHARGE_STATE_BIT, &result));
+ is_conservation = test_bit(GBMD_CONSERVATION_STATE_BIT, &result);
+
+ if (unlikely(is_rapid_charge && is_conservation)) {
+ dev_err(&priv->platform_device->dev,
+ "unexpected charge_types: both [Fast] and [Long_Life] are enabled\n");
+ return -EINVAL;
+ }
- if (test_bit(GBMD_CONSERVATION_STATE_BIT, &result))
+ if (is_rapid_charge)
+ val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
+ else if (is_conservation)
val->intval = POWER_SUPPLY_CHARGE_TYPE_LONGLIFE;
else
val->intval = POWER_SUPPLY_CHARGE_TYPE_STANDARD;
@@ -2052,29 +2130,42 @@ static const enum power_supply_property ideapad_power_supply_props[] = {
POWER_SUPPLY_PROP_CHARGE_TYPES,
};
-static const struct power_supply_ext ideapad_battery_ext = {
- .name = "ideapad_laptop",
- .properties = ideapad_power_supply_props,
- .num_properties = ARRAY_SIZE(ideapad_power_supply_props),
- .charge_types = (BIT(POWER_SUPPLY_CHARGE_TYPE_STANDARD) |
- BIT(POWER_SUPPLY_CHARGE_TYPE_LONGLIFE)),
- .get_property = ideapad_psy_ext_get_prop,
- .set_property = ideapad_psy_ext_set_prop,
- .property_is_writeable = ideapad_psy_prop_is_writeable,
-};
+#define DEFINE_IDEAPAD_POWER_SUPPLY_EXTENSION(_name, _charge_types) \
+ static const struct power_supply_ext _name = { \
+ .name = "ideapad_laptop", \
+ .properties = ideapad_power_supply_props, \
+ .num_properties = ARRAY_SIZE(ideapad_power_supply_props), \
+ .charge_types = _charge_types, \
+ .get_property = ideapad_psy_ext_get_prop, \
+ .set_property = ideapad_psy_ext_set_prop, \
+ .property_is_writeable = ideapad_psy_prop_is_writeable, \
+ }
+
+DEFINE_IDEAPAD_POWER_SUPPLY_EXTENSION(ideapad_battery_ext_v1,
+ (BIT(POWER_SUPPLY_CHARGE_TYPE_STANDARD) |
+ BIT(POWER_SUPPLY_CHARGE_TYPE_LONGLIFE))
+);
+
+DEFINE_IDEAPAD_POWER_SUPPLY_EXTENSION(ideapad_battery_ext_v2,
+ (BIT(POWER_SUPPLY_CHARGE_TYPE_STANDARD) |
+ BIT(POWER_SUPPLY_CHARGE_TYPE_FAST) |
+ BIT(POWER_SUPPLY_CHARGE_TYPE_LONGLIFE))
+);
static int ideapad_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook)
{
struct ideapad_private *priv = container_of(hook, struct ideapad_private, battery_hook);
- return power_supply_register_extension(battery, &ideapad_battery_ext,
+ return power_supply_register_extension(battery, priv->battery_ext,
&priv->platform_device->dev, priv);
}
static int ideapad_battery_remove(struct power_supply *battery,
struct acpi_battery_hook *hook)
{
- power_supply_unregister_extension(battery, &ideapad_battery_ext);
+ struct ideapad_private *priv = container_of(hook, struct ideapad_private, battery_hook);
+
+ power_supply_unregister_extension(battery, priv->battery_ext);
return 0;
}
@@ -2099,14 +2190,25 @@ static int ideapad_check_features(struct ideapad_private *priv)
priv->features.fan_mode = true;
if (acpi_has_method(handle, "GBMD") && acpi_has_method(handle, "SBMC")) {
- priv->features.conservation_mode = true;
- priv->battery_hook.add_battery = ideapad_battery_add;
- priv->battery_hook.remove_battery = ideapad_battery_remove;
- priv->battery_hook.name = "Ideapad Battery Extension";
-
- err = devm_battery_hook_register(&priv->platform_device->dev, &priv->battery_hook);
- if (err)
- return err;
+ /* Not acquiring gbmd_sbmc_mutex as race condition is impossible on init */
+ if (!eval_gbmd(handle, &val)) {
+ priv->features.conservation_mode = true;
+ priv->features.rapid_charge = test_bit(GBMD_RAPID_CHARGE_SUPPORTED_BIT,
+ &val);
+
+ priv->battery_ext = priv->features.rapid_charge
+ ? &ideapad_battery_ext_v2
+ : &ideapad_battery_ext_v1;
+
+ priv->battery_hook.add_battery = ideapad_battery_add;
+ priv->battery_hook.remove_battery = ideapad_battery_remove;
+ priv->battery_hook.name = "Ideapad Battery Extension";
+
+ err = devm_battery_hook_register(&priv->platform_device->dev,
+ &priv->battery_hook);
+ if (err)
+ return err;
+ }
}
if (acpi_has_method(handle, "DYTC"))
@@ -2292,6 +2394,10 @@ static int ideapad_acpi_add(struct platform_device *pdev)
if (err)
return err;
+ err = devm_mutex_init(&pdev->dev, &priv->gbmd_sbmc_mutex);
+ if (err)
+ return err;
+
err = ideapad_check_features(priv);
if (err)
return err;
diff --git a/drivers/platform/x86/lenovo/wmi-gamezone.c b/drivers/platform/x86/lenovo/wmi-gamezone.c
index 0eb7fe8222f4..381836d29a96 100644
--- a/drivers/platform/x86/lenovo/wmi-gamezone.c
+++ b/drivers/platform/x86/lenovo/wmi-gamezone.c
@@ -171,14 +171,10 @@ static int lwmi_gz_profile_get(struct device *dev,
*profile = PLATFORM_PROFILE_BALANCED;
break;
case LWMI_GZ_THERMAL_MODE_PERFORMANCE:
- if (priv->extreme_supported) {
- *profile = PLATFORM_PROFILE_BALANCED_PERFORMANCE;
- break;
- }
*profile = PLATFORM_PROFILE_PERFORMANCE;
break;
case LWMI_GZ_THERMAL_MODE_EXTREME:
- *profile = PLATFORM_PROFILE_PERFORMANCE;
+ *profile = PLATFORM_PROFILE_MAX_POWER;
break;
case LWMI_GZ_THERMAL_MODE_CUSTOM:
*profile = PLATFORM_PROFILE_CUSTOM;
@@ -218,16 +214,12 @@ static int lwmi_gz_profile_set(struct device *dev,
case PLATFORM_PROFILE_BALANCED:
mode = LWMI_GZ_THERMAL_MODE_BALANCED;
break;
- case PLATFORM_PROFILE_BALANCED_PERFORMANCE:
- mode = LWMI_GZ_THERMAL_MODE_PERFORMANCE;
- break;
case PLATFORM_PROFILE_PERFORMANCE:
- if (priv->extreme_supported) {
- mode = LWMI_GZ_THERMAL_MODE_EXTREME;
- break;
- }
mode = LWMI_GZ_THERMAL_MODE_PERFORMANCE;
break;
+ case PLATFORM_PROFILE_MAX_POWER:
+ mode = LWMI_GZ_THERMAL_MODE_EXTREME;
+ break;
case PLATFORM_PROFILE_CUSTOM:
mode = LWMI_GZ_THERMAL_MODE_CUSTOM;
break;
@@ -274,8 +266,23 @@ static const struct dmi_system_id fwbug_list[] = {
},
.driver_data = &quirk_no_extreme_bug,
},
+ {
+ .ident = "Legion Go 8ASP2",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "Legion Go 8ASP2"),
+ },
+ .driver_data = &quirk_no_extreme_bug,
+ },
+ {
+ .ident = "Legion Go 8AHP2",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "Legion Go 8AHP2"),
+ },
+ .driver_data = &quirk_no_extreme_bug,
+ },
{},
-
};
/**
@@ -338,7 +345,7 @@ static int lwmi_gz_platform_profile_probe(void *drvdata, unsigned long *choices)
priv->extreme_supported = lwmi_gz_extreme_supported(profile_support_ver);
if (priv->extreme_supported)
- set_bit(PLATFORM_PROFILE_BALANCED_PERFORMANCE, choices);
+ set_bit(PLATFORM_PROFILE_MAX_POWER, choices);
return 0;
}
diff --git a/drivers/platform/x86/lg-laptop.c b/drivers/platform/x86/lg-laptop.c
index 6af6cf477c5b..f92e89c75db9 100644
--- a/drivers/platform/x86/lg-laptop.c
+++ b/drivers/platform/x86/lg-laptop.c
@@ -19,6 +19,7 @@
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/string_choices.h>
#include <linux/types.h>
#include <acpi/battery.h>
@@ -42,6 +43,7 @@ MODULE_PARM_DESC(fw_debug, "Enable printing of firmware debug messages");
#define LG_ADDRESS_SPACE_ID 0x8F
#define LG_ADDRESS_SPACE_DEBUG_FLAG_ADR 0x00
+#define LG_ADDRESS_SPACE_HD_AUDIO_POWER_ADDR 0x01
#define LG_ADDRESS_SPACE_FAN_MODE_ADR 0x03
#define LG_ADDRESS_SPACE_DTTM_FLAG_ADR 0x20
@@ -668,6 +670,15 @@ static acpi_status lg_laptop_address_space_write(struct device *dev, acpi_physic
byte = value & 0xFF;
switch (address) {
+ case LG_ADDRESS_SPACE_HD_AUDIO_POWER_ADDR:
+ /*
+ * The HD audio power field is not affected by the DTTM flag,
+ * so we have to manually check fw_debug.
+ */
+ if (fw_debug)
+ dev_dbg(dev, "HD audio power %s\n", str_enabled_disabled(byte));
+
+ return AE_OK;
case LG_ADDRESS_SPACE_FAN_MODE_ADR:
/*
* The fan mode field is not affected by the DTTM flag, so we
diff --git a/drivers/platform/x86/oxpec.c b/drivers/platform/x86/oxpec.c
index 54377b282ff8..144a454103b9 100644
--- a/drivers/platform/x86/oxpec.c
+++ b/drivers/platform/x86/oxpec.c
@@ -1,8 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Platform driver for OneXPlayer and AOKZOE devices. For the time being,
- * it also exposes fan controls for AYANEO, and OrangePi Handhelds via
- * hwmon sysfs.
+ * Platform driver for OneXPlayer and AOKZOE devices.
*
* Fan control is provided via pwm interface in the range [0-255].
* Old AMD boards use [0-100] as range in the EC, the written value is
@@ -43,14 +41,6 @@ static bool unlock_global_acpi_lock(void)
enum oxp_board {
aok_zoe_a1 = 1,
- aya_neo_2,
- aya_neo_air,
- aya_neo_air_1s,
- aya_neo_air_plus_mendo,
- aya_neo_air_pro,
- aya_neo_flip,
- aya_neo_geek,
- aya_neo_kun,
orange_pi_neo,
oxp_2,
oxp_fly,
@@ -133,62 +123,6 @@ static const struct dmi_system_id dmi_table[] = {
},
{
.matches = {
- DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
- DMI_MATCH(DMI_BOARD_NAME, "AYANEO 2"),
- },
- .driver_data = (void *)aya_neo_2,
- },
- {
- .matches = {
- DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
- DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR"),
- },
- .driver_data = (void *)aya_neo_air,
- },
- {
- .matches = {
- DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
- DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR 1S"),
- },
- .driver_data = (void *)aya_neo_air_1s,
- },
- {
- .matches = {
- DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
- DMI_EXACT_MATCH(DMI_BOARD_NAME, "AB05-Mendocino"),
- },
- .driver_data = (void *)aya_neo_air_plus_mendo,
- },
- {
- .matches = {
- DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
- DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR Pro"),
- },
- .driver_data = (void *)aya_neo_air_pro,
- },
- {
- .matches = {
- DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
- DMI_MATCH(DMI_BOARD_NAME, "FLIP"),
- },
- .driver_data = (void *)aya_neo_flip,
- },
- {
- .matches = {
- DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
- DMI_MATCH(DMI_BOARD_NAME, "GEEK"),
- },
- .driver_data = (void *)aya_neo_geek,
- },
- {
- .matches = {
- DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
- DMI_EXACT_MATCH(DMI_BOARD_NAME, "KUN"),
- },
- .driver_data = (void *)aya_neo_kun,
- },
- {
- .matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "OrangePi"),
DMI_EXACT_MATCH(DMI_BOARD_NAME, "NEO-01"),
},
@@ -672,13 +606,6 @@ static int oxp_pwm_enable(void)
case orange_pi_neo:
return write_to_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, PWM_MODE_MANUAL);
case aok_zoe_a1:
- case aya_neo_2:
- case aya_neo_air:
- case aya_neo_air_plus_mendo:
- case aya_neo_air_pro:
- case aya_neo_flip:
- case aya_neo_geek:
- case aya_neo_kun:
case oxp_2:
case oxp_fly:
case oxp_mini_amd:
@@ -699,14 +626,6 @@ static int oxp_pwm_disable(void)
case orange_pi_neo:
return write_to_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, PWM_MODE_AUTO);
case aok_zoe_a1:
- case aya_neo_2:
- case aya_neo_air:
- case aya_neo_air_1s:
- case aya_neo_air_plus_mendo:
- case aya_neo_air_pro:
- case aya_neo_flip:
- case aya_neo_geek:
- case aya_neo_kun:
case oxp_2:
case oxp_fly:
case oxp_mini_amd:
@@ -727,14 +646,6 @@ static int oxp_pwm_read(long *val)
case orange_pi_neo:
return read_from_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, 1, val);
case aok_zoe_a1:
- case aya_neo_2:
- case aya_neo_air:
- case aya_neo_air_1s:
- case aya_neo_air_plus_mendo:
- case aya_neo_air_pro:
- case aya_neo_flip:
- case aya_neo_geek:
- case aya_neo_kun:
case oxp_2:
case oxp_fly:
case oxp_mini_amd:
@@ -774,14 +685,6 @@ static int oxp_pwm_fan_speed(long *val)
case oxp_g1_i:
return read_from_ec(OXP_2_SENSOR_FAN_REG, 2, val);
case aok_zoe_a1:
- case aya_neo_2:
- case aya_neo_air:
- case aya_neo_air_1s:
- case aya_neo_air_plus_mendo:
- case aya_neo_air_pro:
- case aya_neo_flip:
- case aya_neo_geek:
- case aya_neo_kun:
case oxp_fly:
case oxp_mini_amd:
case oxp_mini_amd_a07:
@@ -810,14 +713,6 @@ static int oxp_pwm_input_write(long val)
/* scale to range [0-184] */
val = (val * 184) / 255;
return write_to_ec(OXP_SENSOR_PWM_REG, val);
- case aya_neo_2:
- case aya_neo_air:
- case aya_neo_air_1s:
- case aya_neo_air_plus_mendo:
- case aya_neo_air_pro:
- case aya_neo_flip:
- case aya_neo_geek:
- case aya_neo_kun:
case oxp_mini_amd:
case oxp_mini_amd_a07:
/* scale to range [0-100] */
@@ -854,14 +749,6 @@ static int oxp_pwm_input_read(long *val)
/* scale from range [0-184] */
*val = (*val * 255) / 184;
break;
- case aya_neo_2:
- case aya_neo_air:
- case aya_neo_air_1s:
- case aya_neo_air_plus_mendo:
- case aya_neo_air_pro:
- case aya_neo_flip:
- case aya_neo_geek:
- case aya_neo_kun:
case oxp_mini_amd:
case oxp_mini_amd_a07:
ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val);
diff --git a/drivers/platform/x86/serial-multi-instantiate.c b/drivers/platform/x86/serial-multi-instantiate.c
index db030b0f176a..1a369334f9cb 100644
--- a/drivers/platform/x86/serial-multi-instantiate.c
+++ b/drivers/platform/x86/serial-multi-instantiate.c
@@ -22,6 +22,7 @@
#define IRQ_RESOURCE_GPIO 1
#define IRQ_RESOURCE_APIC 2
#define IRQ_RESOURCE_AUTO 3
+#define IRQ_RESOURCE_OPT BIT(2)
enum smi_bus_type {
SMI_I2C,
@@ -64,6 +65,10 @@ static int smi_get_irq(struct platform_device *pdev, struct acpi_device *adev,
dev_dbg(&pdev->dev, "Using platform irq\n");
break;
}
+ if (inst->flags & IRQ_RESOURCE_OPT) {
+ dev_dbg(&pdev->dev, "No irq\n");
+ return 0;
+ }
break;
case IRQ_RESOURCE_GPIO:
ret = acpi_dev_gpio_irq_get(adev, inst->irq_idx);
@@ -386,10 +391,10 @@ static const struct smi_node cs35l57_hda = {
static const struct smi_node tas2781_hda = {
.instances = {
- { "tas2781-hda", IRQ_RESOURCE_AUTO, 0 },
- { "tas2781-hda", IRQ_RESOURCE_AUTO, 0 },
- { "tas2781-hda", IRQ_RESOURCE_AUTO, 0 },
- { "tas2781-hda", IRQ_RESOURCE_AUTO, 0 },
+ { "tas2781-hda", IRQ_RESOURCE_AUTO | IRQ_RESOURCE_OPT, 0 },
+ { "tas2781-hda", IRQ_RESOURCE_AUTO | IRQ_RESOURCE_OPT, 0 },
+ { "tas2781-hda", IRQ_RESOURCE_AUTO | IRQ_RESOURCE_OPT, 0 },
+ { "tas2781-hda", IRQ_RESOURCE_AUTO | IRQ_RESOURCE_OPT, 0 },
{}
},
.bus_type = SMI_AUTO_DETECT,
diff --git a/drivers/platform/x86/uniwill/Kconfig b/drivers/platform/x86/uniwill/Kconfig
new file mode 100644
index 000000000000..d07cc8440188
--- /dev/null
+++ b/drivers/platform/x86/uniwill/Kconfig
@@ -0,0 +1,38 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Uniwill X86 Platform Specific Drivers
+#
+
+menuconfig X86_PLATFORM_DRIVERS_UNIWILL
+ bool "Uniwill X86 Platform Specific Device Drivers"
+ depends on X86_PLATFORM_DEVICES
+ help
+ Say Y here to see options for device drivers for various
+ Uniwill x86 platforms, including many OEM laptops originally
+ manufactured by Uniwill.
+ This option alone does not add any kernel code.
+
+ If you say N, all options in this submenu will be skipped and disabled.
+
+if X86_PLATFORM_DRIVERS_UNIWILL
+
+config UNIWILL_LAPTOP
+ tristate "Uniwill Laptop Extras"
+ default m
+ depends on ACPI
+ depends on ACPI_WMI
+ depends on ACPI_BATTERY
+ depends on HWMON
+ depends on INPUT
+ depends on LEDS_CLASS_MULTICOLOR
+ depends on DMI
+ select REGMAP
+ select INPUT_SPARSEKMAP
+ help
+ This driver adds support for various extra features found on Uniwill laptops,
+ like the lightbar, hwmon sensors and hotkeys. It also supports many OEM laptops
+ originally manufactured by Uniwill.
+
+ If you have such a laptop, say Y or M here.
+
+endif
diff --git a/drivers/platform/x86/uniwill/Makefile b/drivers/platform/x86/uniwill/Makefile
new file mode 100644
index 000000000000..05cd1747a240
--- /dev/null
+++ b/drivers/platform/x86/uniwill/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Makefile for linux/drivers/platform/x86/uniwill
+# Uniwill X86 Platform Specific Drivers
+#
+
+obj-$(CONFIG_UNIWILL_LAPTOP) += uniwill-laptop.o
+uniwill-laptop-y := uniwill-acpi.o uniwill-wmi.o
diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
new file mode 100644
index 000000000000..bd7e63dd5181
--- /dev/null
+++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
@@ -0,0 +1,1912 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Linux driver for Uniwill notebooks.
+ *
+ * Special thanks go to PÅ‘cze BarnabĂ¡s, Christoffer Sandberg and Werner Sembach
+ * for supporting the development of this driver either through prior work or
+ * by answering questions regarding the underlying ACPI and WMI interfaces.
+ *
+ * Copyright (C) 2025 Armin Wolf <W_Armin@gmx.de>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/acpi.h>
+#include <linux/array_size.h>
+#include <linux/bits.h>
+#include <linux/bitfield.h>
+#include <linux/cleanup.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/device/driver.h>
+#include <linux/dmi.h>
+#include <linux/errno.h>
+#include <linux/fixp-arith.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
+#include <linux/kernel.h>
+#include <linux/kstrtox.h>
+#include <linux/leds.h>
+#include <linux/led-class-multicolor.h>
+#include <linux/limits.h>
+#include <linux/list.h>
+#include <linux/minmax.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/notifier.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/printk.h>
+#include <linux/regmap.h>
+#include <linux/string.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+#include <linux/units.h>
+
+#include <acpi/battery.h>
+
+#include "uniwill-wmi.h"
+
+#define EC_ADDR_BAT_POWER_UNIT_1 0x0400
+
+#define EC_ADDR_BAT_POWER_UNIT_2 0x0401
+
+#define EC_ADDR_BAT_DESIGN_CAPACITY_1 0x0402
+
+#define EC_ADDR_BAT_DESIGN_CAPACITY_2 0x0403
+
+#define EC_ADDR_BAT_FULL_CAPACITY_1 0x0404
+
+#define EC_ADDR_BAT_FULL_CAPACITY_2 0x0405
+
+#define EC_ADDR_BAT_DESIGN_VOLTAGE_1 0x0408
+
+#define EC_ADDR_BAT_DESIGN_VOLTAGE_2 0x0409
+
+#define EC_ADDR_BAT_STATUS_1 0x0432
+#define BAT_DISCHARGING BIT(0)
+
+#define EC_ADDR_BAT_STATUS_2 0x0433
+
+#define EC_ADDR_BAT_CURRENT_1 0x0434
+
+#define EC_ADDR_BAT_CURRENT_2 0x0435
+
+#define EC_ADDR_BAT_REMAIN_CAPACITY_1 0x0436
+
+#define EC_ADDR_BAT_REMAIN_CAPACITY_2 0x0437
+
+#define EC_ADDR_BAT_VOLTAGE_1 0x0438
+
+#define EC_ADDR_BAT_VOLTAGE_2 0x0439
+
+#define EC_ADDR_CPU_TEMP 0x043E
+
+#define EC_ADDR_GPU_TEMP 0x044F
+
+#define EC_ADDR_MAIN_FAN_RPM_1 0x0464
+
+#define EC_ADDR_MAIN_FAN_RPM_2 0x0465
+
+#define EC_ADDR_SECOND_FAN_RPM_1 0x046C
+
+#define EC_ADDR_SECOND_FAN_RPM_2 0x046D
+
+#define EC_ADDR_DEVICE_STATUS 0x047B
+#define WIFI_STATUS_ON BIT(7)
+/* BIT(5) is also unset depending on the rfkill state (bluetooth?) */
+
+#define EC_ADDR_BAT_ALERT 0x0494
+
+#define EC_ADDR_BAT_CYCLE_COUNT_1 0x04A6
+
+#define EC_ADDR_BAT_CYCLE_COUNT_2 0x04A7
+
+#define EC_ADDR_PROJECT_ID 0x0740
+
+#define EC_ADDR_AP_OEM 0x0741
+#define ENABLE_MANUAL_CTRL BIT(0)
+#define ITE_KBD_EFFECT_REACTIVE BIT(3)
+#define FAN_ABNORMAL BIT(5)
+
+#define EC_ADDR_SUPPORT_5 0x0742
+#define FAN_TURBO_SUPPORTED BIT(4)
+#define FAN_SUPPORT BIT(5)
+
+#define EC_ADDR_CTGP_DB_CTRL 0x0743
+#define CTGP_DB_GENERAL_ENABLE BIT(0)
+#define CTGP_DB_DB_ENABLE BIT(1)
+#define CTGP_DB_CTGP_ENABLE BIT(2)
+
+#define EC_ADDR_CTGP_OFFSET 0x0744
+
+#define EC_ADDR_TPP_OFFSET 0x0745
+
+#define EC_ADDR_MAX_TGP 0x0746
+
+#define EC_ADDR_LIGHTBAR_AC_CTRL 0x0748
+#define LIGHTBAR_APP_EXISTS BIT(0)
+#define LIGHTBAR_POWER_SAVE BIT(1)
+#define LIGHTBAR_S0_OFF BIT(2)
+#define LIGHTBAR_S3_OFF BIT(3) // Breathing animation when suspended
+#define LIGHTBAR_WELCOME BIT(7) // Rainbow animation
+
+#define EC_ADDR_LIGHTBAR_AC_RED 0x0749
+
+#define EC_ADDR_LIGHTBAR_AC_GREEN 0x074A
+
+#define EC_ADDR_LIGHTBAR_AC_BLUE 0x074B
+
+#define EC_ADDR_BIOS_OEM 0x074E
+#define FN_LOCK_STATUS BIT(4)
+
+#define EC_ADDR_MANUAL_FAN_CTRL 0x0751
+#define FAN_LEVEL_MASK GENMASK(2, 0)
+#define FAN_MODE_TURBO BIT(4)
+#define FAN_MODE_HIGH BIT(5)
+#define FAN_MODE_BOOST BIT(6)
+#define FAN_MODE_USER BIT(7)
+
+#define EC_ADDR_PWM_1 0x075B
+
+#define EC_ADDR_PWM_2 0x075C
+
+/* Unreliable */
+#define EC_ADDR_SUPPORT_1 0x0765
+#define AIRPLANE_MODE BIT(0)
+#define GPS_SWITCH BIT(1)
+#define OVERCLOCK BIT(2)
+#define MACRO_KEY BIT(3)
+#define SHORTCUT_KEY BIT(4)
+#define SUPER_KEY_LOCK BIT(5)
+#define LIGHTBAR BIT(6)
+#define FAN_BOOST BIT(7)
+
+#define EC_ADDR_SUPPORT_2 0x0766
+#define SILENT_MODE BIT(0)
+#define USB_CHARGING BIT(1)
+#define RGB_KEYBOARD BIT(2)
+#define CHINA_MODE BIT(5)
+#define MY_BATTERY BIT(6)
+
+#define EC_ADDR_TRIGGER 0x0767
+#define TRIGGER_SUPER_KEY_LOCK BIT(0)
+#define TRIGGER_LIGHTBAR BIT(1)
+#define TRIGGER_FAN_BOOST BIT(2)
+#define TRIGGER_SILENT_MODE BIT(3)
+#define TRIGGER_USB_CHARGING BIT(4)
+#define RGB_APPLY_COLOR BIT(5)
+#define RGB_LOGO_EFFECT BIT(6)
+#define RGB_RAINBOW_EFFECT BIT(7)
+
+#define EC_ADDR_SWITCH_STATUS 0x0768
+#define SUPER_KEY_LOCK_STATUS BIT(0)
+#define LIGHTBAR_STATUS BIT(1)
+#define FAN_BOOST_STATUS BIT(2)
+#define MACRO_KEY_STATUS BIT(3)
+#define MY_BAT_POWER_BAT_STATUS BIT(4)
+
+#define EC_ADDR_RGB_RED 0x0769
+
+#define EC_ADDR_RGB_GREEN 0x076A
+
+#define EC_ADDR_RGB_BLUE 0x076B
+
+#define EC_ADDR_ROMID_START 0x0770
+#define ROMID_LENGTH 14
+
+#define EC_ADDR_ROMID_EXTRA_1 0x077E
+
+#define EC_ADDR_ROMID_EXTRA_2 0x077F
+
+#define EC_ADDR_BIOS_OEM_2 0x0782
+#define FAN_V2_NEW BIT(0)
+#define FAN_QKEY BIT(1)
+#define FAN_TABLE_OFFICE_MODE BIT(2)
+#define FAN_V3 BIT(3)
+#define DEFAULT_MODE BIT(4)
+
+#define EC_ADDR_PL1_SETTING 0x0783
+
+#define EC_ADDR_PL2_SETTING 0x0784
+
+#define EC_ADDR_PL4_SETTING 0x0785
+
+#define EC_ADDR_FAN_DEFAULT 0x0786
+#define FAN_CURVE_LENGTH 5
+
+#define EC_ADDR_KBD_STATUS 0x078C
+#define KBD_WHITE_ONLY BIT(0) // ~single color
+#define KBD_SINGLE_COLOR_OFF BIT(1)
+#define KBD_TURBO_LEVEL_MASK GENMASK(3, 2)
+#define KBD_APPLY BIT(4)
+#define KBD_BRIGHTNESS GENMASK(7, 5)
+
+#define EC_ADDR_FAN_CTRL 0x078E
+#define FAN3P5 BIT(1)
+#define CHARGING_PROFILE BIT(3)
+#define UNIVERSAL_FAN_CTRL BIT(6)
+
+#define EC_ADDR_BIOS_OEM_3 0x07A3
+#define FAN_REDUCED_DURY_CYCLE BIT(5)
+#define FAN_ALWAYS_ON BIT(6)
+
+#define EC_ADDR_BIOS_BYTE 0x07A4
+#define FN_LOCK_SWITCH BIT(3)
+
+#define EC_ADDR_OEM_3 0x07A5
+#define POWER_LED_MASK GENMASK(1, 0)
+#define POWER_LED_LEFT 0x00
+#define POWER_LED_BOTH 0x01
+#define POWER_LED_NONE 0x02
+#define FAN_QUIET BIT(2)
+#define OVERBOOST BIT(4)
+#define HIGH_POWER BIT(7)
+
+#define EC_ADDR_OEM_4 0x07A6
+#define OVERBOOST_DYN_TEMP_OFF BIT(1)
+#define TOUCHPAD_TOGGLE_OFF BIT(6)
+
+#define EC_ADDR_CHARGE_CTRL 0x07B9
+#define CHARGE_CTRL_MASK GENMASK(6, 0)
+#define CHARGE_CTRL_REACHED BIT(7)
+
+#define EC_ADDR_UNIVERSAL_FAN_CTRL 0x07C5
+#define SPLIT_TABLES BIT(7)
+
+#define EC_ADDR_AP_OEM_6 0x07C6
+#define ENABLE_UNIVERSAL_FAN_CTRL BIT(2)
+#define BATTERY_CHARGE_FULL_OVER_24H BIT(3)
+#define BATTERY_ERM_STATUS_REACHED BIT(4)
+
+#define EC_ADDR_CHARGE_PRIO 0x07CC
+#define CHARGING_PERFORMANCE BIT(7)
+
+/* Same bits as EC_ADDR_LIGHTBAR_AC_CTRL except LIGHTBAR_S3_OFF */
+#define EC_ADDR_LIGHTBAR_BAT_CTRL 0x07E2
+
+#define EC_ADDR_LIGHTBAR_BAT_RED 0x07E3
+
+#define EC_ADDR_LIGHTBAR_BAT_GREEN 0x07E4
+
+#define EC_ADDR_LIGHTBAR_BAT_BLUE 0x07E5
+
+#define EC_ADDR_CPU_TEMP_END_TABLE 0x0F00
+
+#define EC_ADDR_CPU_TEMP_START_TABLE 0x0F10
+
+#define EC_ADDR_CPU_FAN_SPEED_TABLE 0x0F20
+
+#define EC_ADDR_GPU_TEMP_END_TABLE 0x0F30
+
+#define EC_ADDR_GPU_TEMP_START_TABLE 0x0F40
+
+#define EC_ADDR_GPU_FAN_SPEED_TABLE 0x0F50
+
+/*
+ * Those two registers technically allow for manual fan control,
+ * but are unstable on some models and are likely not meant to
+ * be used by applications as they are only accessible when using
+ * the WMI interface.
+ */
+#define EC_ADDR_PWM_1_WRITEABLE 0x1804
+
+#define EC_ADDR_PWM_2_WRITEABLE 0x1809
+
+#define DRIVER_NAME "uniwill"
+
+/*
+ * The OEM software always sleeps up to 6 ms after reading/writing EC
+ * registers, so we emulate this behaviour for maximum compatibility.
+ */
+#define UNIWILL_EC_DELAY_US 6000
+
+#define PWM_MAX 200
+#define FAN_TABLE_LENGTH 16
+
+#define LED_CHANNELS 3
+#define LED_MAX_BRIGHTNESS 200
+
+#define UNIWILL_FEATURE_FN_LOCK_TOGGLE BIT(0)
+#define UNIWILL_FEATURE_SUPER_KEY_TOGGLE BIT(1)
+#define UNIWILL_FEATURE_TOUCHPAD_TOGGLE BIT(2)
+#define UNIWILL_FEATURE_LIGHTBAR BIT(3)
+#define UNIWILL_FEATURE_BATTERY BIT(4)
+#define UNIWILL_FEATURE_HWMON BIT(5)
+
+struct uniwill_data {
+ struct device *dev;
+ acpi_handle handle;
+ struct regmap *regmap;
+ struct acpi_battery_hook hook;
+ unsigned int last_charge_ctrl;
+ struct mutex battery_lock; /* Protects the list of currently registered batteries */
+ unsigned int last_switch_status;
+ struct mutex super_key_lock; /* Protects the toggling of the super key lock state */
+ struct list_head batteries;
+ struct mutex led_lock; /* Protects writes to the lightbar registers */
+ struct led_classdev_mc led_mc_cdev;
+ struct mc_subled led_mc_subled_info[LED_CHANNELS];
+ struct mutex input_lock; /* Protects input sequence during notify */
+ struct input_dev *input_device;
+ struct notifier_block nb;
+};
+
+struct uniwill_battery_entry {
+ struct list_head head;
+ struct power_supply *battery;
+};
+
+static bool force;
+module_param_unsafe(force, bool, 0);
+MODULE_PARM_DESC(force, "Force loading without checking for supported devices\n");
+
+/* Feature bitmask since the associated registers are not reliable */
+static unsigned int supported_features;
+
+static const char * const uniwill_temp_labels[] = {
+ "CPU",
+ "GPU",
+};
+
+static const char * const uniwill_fan_labels[] = {
+ "Main",
+ "Secondary",
+};
+
+static const struct key_entry uniwill_keymap[] = {
+ /* Reported via keyboard controller */
+ { KE_IGNORE, UNIWILL_OSD_CAPSLOCK, { KEY_CAPSLOCK }},
+ { KE_IGNORE, UNIWILL_OSD_NUMLOCK, { KEY_NUMLOCK }},
+
+ /* Reported when the user locks/unlocks the super key */
+ { KE_IGNORE, UNIWILL_OSD_SUPER_KEY_LOCK_ENABLE, { KEY_UNKNOWN }},
+ { KE_IGNORE, UNIWILL_OSD_SUPER_KEY_LOCK_DISABLE, { KEY_UNKNOWN }},
+ /* Optional, might not be reported by all devices */
+ { KE_IGNORE, UNIWILL_OSD_SUPER_KEY_LOCK_CHANGED, { KEY_UNKNOWN }},
+
+ /* Reported in manual mode when toggling the airplane mode status */
+ { KE_KEY, UNIWILL_OSD_RFKILL, { KEY_RFKILL }},
+ { KE_IGNORE, UNIWILL_OSD_RADIOON, { KEY_UNKNOWN }},
+ { KE_IGNORE, UNIWILL_OSD_RADIOOFF, { KEY_UNKNOWN }},
+
+ /* Reported when user wants to cycle the platform profile */
+ { KE_KEY, UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE, { KEY_F14 }},
+
+ /* Reported when the user wants to adjust the brightness of the keyboard */
+ { KE_KEY, UNIWILL_OSD_KBDILLUMDOWN, { KEY_KBDILLUMDOWN }},
+ { KE_KEY, UNIWILL_OSD_KBDILLUMUP, { KEY_KBDILLUMUP }},
+
+ /* Reported when the user wants to toggle the microphone mute status */
+ { KE_KEY, UNIWILL_OSD_MIC_MUTE, { KEY_MICMUTE }},
+
+ /* Reported when the user wants to toggle the mute status */
+ { KE_IGNORE, UNIWILL_OSD_MUTE, { KEY_MUTE }},
+
+ /* Reported when the user locks/unlocks the Fn key */
+ { KE_IGNORE, UNIWILL_OSD_FN_LOCK, { KEY_FN_ESC }},
+
+ /* Reported when the user wants to toggle the brightness of the keyboard */
+ { KE_KEY, UNIWILL_OSD_KBDILLUMTOGGLE, { KEY_KBDILLUMTOGGLE }},
+ { KE_KEY, UNIWILL_OSD_KB_LED_LEVEL0, { KEY_KBDILLUMTOGGLE }},
+ { KE_KEY, UNIWILL_OSD_KB_LED_LEVEL1, { KEY_KBDILLUMTOGGLE }},
+ { KE_KEY, UNIWILL_OSD_KB_LED_LEVEL2, { KEY_KBDILLUMTOGGLE }},
+ { KE_KEY, UNIWILL_OSD_KB_LED_LEVEL3, { KEY_KBDILLUMTOGGLE }},
+ { KE_KEY, UNIWILL_OSD_KB_LED_LEVEL4, { KEY_KBDILLUMTOGGLE }},
+
+ /* FIXME: find out the exact meaning of those events */
+ { KE_IGNORE, UNIWILL_OSD_BAT_CHARGE_FULL_24_H, { KEY_UNKNOWN }},
+ { KE_IGNORE, UNIWILL_OSD_BAT_ERM_UPDATE, { KEY_UNKNOWN }},
+
+ /* Reported when the user wants to toggle the benchmark mode status */
+ { KE_IGNORE, UNIWILL_OSD_BENCHMARK_MODE_TOGGLE, { KEY_UNKNOWN }},
+
+ /* Reported when the user wants to toggle the webcam */
+ { KE_IGNORE, UNIWILL_OSD_WEBCAM_TOGGLE, { KEY_UNKNOWN }},
+
+ { KE_END }
+};
+
+static int uniwill_ec_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+ union acpi_object params[2] = {
+ {
+ .integer = {
+ .type = ACPI_TYPE_INTEGER,
+ .value = reg,
+ },
+ },
+ {
+ .integer = {
+ .type = ACPI_TYPE_INTEGER,
+ .value = val,
+ },
+ },
+ };
+ struct uniwill_data *data = context;
+ struct acpi_object_list input = {
+ .count = ARRAY_SIZE(params),
+ .pointer = params,
+ };
+ acpi_status status;
+
+ status = acpi_evaluate_object(data->handle, "ECRW", &input, NULL);
+ if (ACPI_FAILURE(status))
+ return -EIO;
+
+ usleep_range(UNIWILL_EC_DELAY_US, UNIWILL_EC_DELAY_US * 2);
+
+ return 0;
+}
+
+static int uniwill_ec_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+ union acpi_object params[1] = {
+ {
+ .integer = {
+ .type = ACPI_TYPE_INTEGER,
+ .value = reg,
+ },
+ },
+ };
+ struct uniwill_data *data = context;
+ struct acpi_object_list input = {
+ .count = ARRAY_SIZE(params),
+ .pointer = params,
+ };
+ unsigned long long output;
+ acpi_status status;
+
+ status = acpi_evaluate_integer(data->handle, "ECRR", &input, &output);
+ if (ACPI_FAILURE(status))
+ return -EIO;
+
+ if (output > U8_MAX)
+ return -ENXIO;
+
+ usleep_range(UNIWILL_EC_DELAY_US, UNIWILL_EC_DELAY_US * 2);
+
+ *val = output;
+
+ return 0;
+}
+
+static const struct regmap_bus uniwill_ec_bus = {
+ .reg_write = uniwill_ec_reg_write,
+ .reg_read = uniwill_ec_reg_read,
+ .reg_format_endian_default = REGMAP_ENDIAN_LITTLE,
+ .val_format_endian_default = REGMAP_ENDIAN_LITTLE,
+};
+
+static bool uniwill_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case EC_ADDR_AP_OEM:
+ case EC_ADDR_LIGHTBAR_AC_CTRL:
+ case EC_ADDR_LIGHTBAR_AC_RED:
+ case EC_ADDR_LIGHTBAR_AC_GREEN:
+ case EC_ADDR_LIGHTBAR_AC_BLUE:
+ case EC_ADDR_BIOS_OEM:
+ case EC_ADDR_TRIGGER:
+ case EC_ADDR_OEM_4:
+ case EC_ADDR_CHARGE_CTRL:
+ case EC_ADDR_LIGHTBAR_BAT_CTRL:
+ case EC_ADDR_LIGHTBAR_BAT_RED:
+ case EC_ADDR_LIGHTBAR_BAT_GREEN:
+ case EC_ADDR_LIGHTBAR_BAT_BLUE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool uniwill_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case EC_ADDR_CPU_TEMP:
+ case EC_ADDR_GPU_TEMP:
+ case EC_ADDR_MAIN_FAN_RPM_1:
+ case EC_ADDR_MAIN_FAN_RPM_2:
+ case EC_ADDR_SECOND_FAN_RPM_1:
+ case EC_ADDR_SECOND_FAN_RPM_2:
+ case EC_ADDR_BAT_ALERT:
+ case EC_ADDR_PROJECT_ID:
+ case EC_ADDR_AP_OEM:
+ case EC_ADDR_LIGHTBAR_AC_CTRL:
+ case EC_ADDR_LIGHTBAR_AC_RED:
+ case EC_ADDR_LIGHTBAR_AC_GREEN:
+ case EC_ADDR_LIGHTBAR_AC_BLUE:
+ case EC_ADDR_BIOS_OEM:
+ case EC_ADDR_PWM_1:
+ case EC_ADDR_PWM_2:
+ case EC_ADDR_TRIGGER:
+ case EC_ADDR_SWITCH_STATUS:
+ case EC_ADDR_OEM_4:
+ case EC_ADDR_CHARGE_CTRL:
+ case EC_ADDR_LIGHTBAR_BAT_CTRL:
+ case EC_ADDR_LIGHTBAR_BAT_RED:
+ case EC_ADDR_LIGHTBAR_BAT_GREEN:
+ case EC_ADDR_LIGHTBAR_BAT_BLUE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool uniwill_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case EC_ADDR_CPU_TEMP:
+ case EC_ADDR_GPU_TEMP:
+ case EC_ADDR_MAIN_FAN_RPM_1:
+ case EC_ADDR_MAIN_FAN_RPM_2:
+ case EC_ADDR_SECOND_FAN_RPM_1:
+ case EC_ADDR_SECOND_FAN_RPM_2:
+ case EC_ADDR_BAT_ALERT:
+ case EC_ADDR_PWM_1:
+ case EC_ADDR_PWM_2:
+ case EC_ADDR_TRIGGER:
+ case EC_ADDR_SWITCH_STATUS:
+ case EC_ADDR_CHARGE_CTRL:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config uniwill_ec_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .writeable_reg = uniwill_writeable_reg,
+ .readable_reg = uniwill_readable_reg,
+ .volatile_reg = uniwill_volatile_reg,
+ .can_sleep = true,
+ .max_register = 0xFFF,
+ .cache_type = REGCACHE_MAPLE,
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static ssize_t fn_lock_toggle_enable_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct uniwill_data *data = dev_get_drvdata(dev);
+ unsigned int value;
+ bool enable;
+ int ret;
+
+ ret = kstrtobool(buf, &enable);
+ if (ret < 0)
+ return ret;
+
+ if (enable)
+ value = FN_LOCK_STATUS;
+ else
+ value = 0;
+
+ ret = regmap_update_bits(data->regmap, EC_ADDR_BIOS_OEM, FN_LOCK_STATUS, value);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static ssize_t fn_lock_toggle_enable_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct uniwill_data *data = dev_get_drvdata(dev);
+ unsigned int value;
+ int ret;
+
+ ret = regmap_read(data->regmap, EC_ADDR_BIOS_OEM, &value);
+ if (ret < 0)
+ return ret;
+
+ return sysfs_emit(buf, "%d\n", !!(value & FN_LOCK_STATUS));
+}
+
+static DEVICE_ATTR_RW(fn_lock_toggle_enable);
+
+static ssize_t super_key_toggle_enable_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct uniwill_data *data = dev_get_drvdata(dev);
+ unsigned int value;
+ bool enable;
+ int ret;
+
+ ret = kstrtobool(buf, &enable);
+ if (ret < 0)
+ return ret;
+
+ guard(mutex)(&data->super_key_lock);
+
+ ret = regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, &value);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * We can only toggle the super key lock, so we return early if the setting
+ * is already in the correct state.
+ */
+ if (enable == !(value & SUPER_KEY_LOCK_STATUS))
+ return count;
+
+ ret = regmap_write_bits(data->regmap, EC_ADDR_TRIGGER, TRIGGER_SUPER_KEY_LOCK,
+ TRIGGER_SUPER_KEY_LOCK);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static ssize_t super_key_toggle_enable_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct uniwill_data *data = dev_get_drvdata(dev);
+ unsigned int value;
+ int ret;
+
+ ret = regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, &value);
+ if (ret < 0)
+ return ret;
+
+ return sysfs_emit(buf, "%d\n", !(value & SUPER_KEY_LOCK_STATUS));
+}
+
+static DEVICE_ATTR_RW(super_key_toggle_enable);
+
+static ssize_t touchpad_toggle_enable_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct uniwill_data *data = dev_get_drvdata(dev);
+ unsigned int value;
+ bool enable;
+ int ret;
+
+ ret = kstrtobool(buf, &enable);
+ if (ret < 0)
+ return ret;
+
+ if (enable)
+ value = 0;
+ else
+ value = TOUCHPAD_TOGGLE_OFF;
+
+ ret = regmap_update_bits(data->regmap, EC_ADDR_OEM_4, TOUCHPAD_TOGGLE_OFF, value);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static ssize_t touchpad_toggle_enable_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct uniwill_data *data = dev_get_drvdata(dev);
+ unsigned int value;
+ int ret;
+
+ ret = regmap_read(data->regmap, EC_ADDR_OEM_4, &value);
+ if (ret < 0)
+ return ret;
+
+ return sysfs_emit(buf, "%d\n", !(value & TOUCHPAD_TOGGLE_OFF));
+}
+
+static DEVICE_ATTR_RW(touchpad_toggle_enable);
+
+static ssize_t rainbow_animation_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct uniwill_data *data = dev_get_drvdata(dev);
+ unsigned int value;
+ bool enable;
+ int ret;
+
+ ret = kstrtobool(buf, &enable);
+ if (ret < 0)
+ return ret;
+
+ if (enable)
+ value = LIGHTBAR_WELCOME;
+ else
+ value = 0;
+
+ guard(mutex)(&data->led_lock);
+
+ ret = regmap_update_bits(data->regmap, EC_ADDR_LIGHTBAR_AC_CTRL, LIGHTBAR_WELCOME, value);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_update_bits(data->regmap, EC_ADDR_LIGHTBAR_BAT_CTRL, LIGHTBAR_WELCOME, value);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static ssize_t rainbow_animation_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct uniwill_data *data = dev_get_drvdata(dev);
+ unsigned int value;
+ int ret;
+
+ ret = regmap_read(data->regmap, EC_ADDR_LIGHTBAR_AC_CTRL, &value);
+ if (ret < 0)
+ return ret;
+
+ return sysfs_emit(buf, "%d\n", !!(value & LIGHTBAR_WELCOME));
+}
+
+static DEVICE_ATTR_RW(rainbow_animation);
+
+static ssize_t breathing_in_suspend_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct uniwill_data *data = dev_get_drvdata(dev);
+ unsigned int value;
+ bool enable;
+ int ret;
+
+ ret = kstrtobool(buf, &enable);
+ if (ret < 0)
+ return ret;
+
+ if (enable)
+ value = 0;
+ else
+ value = LIGHTBAR_S3_OFF;
+
+ /* We only access a single register here, so we do not need to use data->led_lock */
+ ret = regmap_update_bits(data->regmap, EC_ADDR_LIGHTBAR_AC_CTRL, LIGHTBAR_S3_OFF, value);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static ssize_t breathing_in_suspend_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct uniwill_data *data = dev_get_drvdata(dev);
+ unsigned int value;
+ int ret;
+
+ ret = regmap_read(data->regmap, EC_ADDR_LIGHTBAR_AC_CTRL, &value);
+ if (ret < 0)
+ return ret;
+
+ return sysfs_emit(buf, "%d\n", !(value & LIGHTBAR_S3_OFF));
+}
+
+static DEVICE_ATTR_RW(breathing_in_suspend);
+
+static struct attribute *uniwill_attrs[] = {
+ /* Keyboard-related */
+ &dev_attr_fn_lock_toggle_enable.attr,
+ &dev_attr_super_key_toggle_enable.attr,
+ &dev_attr_touchpad_toggle_enable.attr,
+ /* Lightbar-related */
+ &dev_attr_rainbow_animation.attr,
+ &dev_attr_breathing_in_suspend.attr,
+ NULL
+};
+
+static umode_t uniwill_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n)
+{
+ if (attr == &dev_attr_fn_lock_toggle_enable.attr) {
+ if (supported_features & UNIWILL_FEATURE_FN_LOCK_TOGGLE)
+ return attr->mode;
+ }
+
+ if (attr == &dev_attr_super_key_toggle_enable.attr) {
+ if (supported_features & UNIWILL_FEATURE_SUPER_KEY_TOGGLE)
+ return attr->mode;
+ }
+
+ if (attr == &dev_attr_touchpad_toggle_enable.attr) {
+ if (supported_features & UNIWILL_FEATURE_TOUCHPAD_TOGGLE)
+ return attr->mode;
+ }
+
+ if (attr == &dev_attr_rainbow_animation.attr ||
+ attr == &dev_attr_breathing_in_suspend.attr) {
+ if (supported_features & UNIWILL_FEATURE_LIGHTBAR)
+ return attr->mode;
+ }
+
+ return 0;
+}
+
+static const struct attribute_group uniwill_group = {
+ .is_visible = uniwill_attr_is_visible,
+ .attrs = uniwill_attrs,
+};
+
+static const struct attribute_group *uniwill_groups[] = {
+ &uniwill_group,
+ NULL
+};
+
+static int uniwill_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel,
+ long *val)
+{
+ struct uniwill_data *data = dev_get_drvdata(dev);
+ unsigned int value;
+ __be16 rpm;
+ int ret;
+
+ switch (type) {
+ case hwmon_temp:
+ switch (channel) {
+ case 0:
+ ret = regmap_read(data->regmap, EC_ADDR_CPU_TEMP, &value);
+ break;
+ case 1:
+ ret = regmap_read(data->regmap, EC_ADDR_GPU_TEMP, &value);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ if (ret < 0)
+ return ret;
+
+ *val = value * MILLIDEGREE_PER_DEGREE;
+ return 0;
+ case hwmon_fan:
+ switch (channel) {
+ case 0:
+ ret = regmap_bulk_read(data->regmap, EC_ADDR_MAIN_FAN_RPM_1, &rpm,
+ sizeof(rpm));
+ break;
+ case 1:
+ ret = regmap_bulk_read(data->regmap, EC_ADDR_SECOND_FAN_RPM_1, &rpm,
+ sizeof(rpm));
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ if (ret < 0)
+ return ret;
+
+ *val = be16_to_cpu(rpm);
+ return 0;
+ case hwmon_pwm:
+ switch (channel) {
+ case 0:
+ ret = regmap_read(data->regmap, EC_ADDR_PWM_1, &value);
+ break;
+ case 1:
+ ret = regmap_read(data->regmap, EC_ADDR_PWM_2, &value);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ if (ret < 0)
+ return ret;
+
+ *val = fixp_linear_interpolate(0, 0, PWM_MAX, U8_MAX, value);
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int uniwill_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr,
+ int channel, const char **str)
+{
+ switch (type) {
+ case hwmon_temp:
+ *str = uniwill_temp_labels[channel];
+ return 0;
+ case hwmon_fan:
+ *str = uniwill_fan_labels[channel];
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static const struct hwmon_ops uniwill_ops = {
+ .visible = 0444,
+ .read = uniwill_read,
+ .read_string = uniwill_read_string,
+};
+
+static const struct hwmon_channel_info * const uniwill_info[] = {
+ HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
+ HWMON_CHANNEL_INFO(temp,
+ HWMON_T_INPUT | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_LABEL),
+ HWMON_CHANNEL_INFO(fan,
+ HWMON_F_INPUT | HWMON_F_LABEL,
+ HWMON_F_INPUT | HWMON_F_LABEL),
+ HWMON_CHANNEL_INFO(pwm,
+ HWMON_PWM_INPUT,
+ HWMON_PWM_INPUT),
+ NULL
+};
+
+static const struct hwmon_chip_info uniwill_chip_info = {
+ .ops = &uniwill_ops,
+ .info = uniwill_info,
+};
+
+static int uniwill_hwmon_init(struct uniwill_data *data)
+{
+ struct device *hdev;
+
+ if (!(supported_features & UNIWILL_FEATURE_HWMON))
+ return 0;
+
+ hdev = devm_hwmon_device_register_with_info(data->dev, "uniwill", data,
+ &uniwill_chip_info, NULL);
+
+ return PTR_ERR_OR_ZERO(hdev);
+}
+
+static const unsigned int uniwill_led_channel_to_bat_reg[LED_CHANNELS] = {
+ EC_ADDR_LIGHTBAR_BAT_RED,
+ EC_ADDR_LIGHTBAR_BAT_GREEN,
+ EC_ADDR_LIGHTBAR_BAT_BLUE,
+};
+
+static const unsigned int uniwill_led_channel_to_ac_reg[LED_CHANNELS] = {
+ EC_ADDR_LIGHTBAR_AC_RED,
+ EC_ADDR_LIGHTBAR_AC_GREEN,
+ EC_ADDR_LIGHTBAR_AC_BLUE,
+};
+
+static int uniwill_led_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness)
+{
+ struct led_classdev_mc *led_mc_cdev = lcdev_to_mccdev(led_cdev);
+ struct uniwill_data *data = container_of(led_mc_cdev, struct uniwill_data, led_mc_cdev);
+ unsigned int value;
+ int ret;
+
+ ret = led_mc_calc_color_components(led_mc_cdev, brightness);
+ if (ret < 0)
+ return ret;
+
+ guard(mutex)(&data->led_lock);
+
+ for (int i = 0; i < LED_CHANNELS; i++) {
+ /* Prevent the brightness values from overflowing */
+ value = min(LED_MAX_BRIGHTNESS, data->led_mc_subled_info[i].brightness);
+ ret = regmap_write(data->regmap, uniwill_led_channel_to_ac_reg[i], value);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_write(data->regmap, uniwill_led_channel_to_bat_reg[i], value);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (brightness)
+ value = 0;
+ else
+ value = LIGHTBAR_S0_OFF;
+
+ ret = regmap_update_bits(data->regmap, EC_ADDR_LIGHTBAR_AC_CTRL, LIGHTBAR_S0_OFF, value);
+ if (ret < 0)
+ return ret;
+
+ return regmap_update_bits(data->regmap, EC_ADDR_LIGHTBAR_BAT_CTRL, LIGHTBAR_S0_OFF, value);
+}
+
+#define LIGHTBAR_MASK (LIGHTBAR_APP_EXISTS | LIGHTBAR_S0_OFF | LIGHTBAR_S3_OFF | LIGHTBAR_WELCOME)
+
+static int uniwill_led_init(struct uniwill_data *data)
+{
+ struct led_init_data init_data = {
+ .devicename = DRIVER_NAME,
+ .default_label = "multicolor:" LED_FUNCTION_STATUS,
+ .devname_mandatory = true,
+ };
+ unsigned int color_indices[3] = {
+ LED_COLOR_ID_RED,
+ LED_COLOR_ID_GREEN,
+ LED_COLOR_ID_BLUE,
+ };
+ unsigned int value;
+ int ret;
+
+ if (!(supported_features & UNIWILL_FEATURE_LIGHTBAR))
+ return 0;
+
+ ret = devm_mutex_init(data->dev, &data->led_lock);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * The EC has separate lightbar settings for AC and battery mode,
+ * so we have to ensure that both settings are the same.
+ */
+ ret = regmap_read(data->regmap, EC_ADDR_LIGHTBAR_AC_CTRL, &value);
+ if (ret < 0)
+ return ret;
+
+ value |= LIGHTBAR_APP_EXISTS;
+ ret = regmap_write(data->regmap, EC_ADDR_LIGHTBAR_AC_CTRL, value);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * The breathing animation during suspend is not supported when
+ * running on battery power.
+ */
+ value |= LIGHTBAR_S3_OFF;
+ ret = regmap_update_bits(data->regmap, EC_ADDR_LIGHTBAR_BAT_CTRL, LIGHTBAR_MASK, value);
+ if (ret < 0)
+ return ret;
+
+ data->led_mc_cdev.led_cdev.color = LED_COLOR_ID_MULTI;
+ data->led_mc_cdev.led_cdev.max_brightness = LED_MAX_BRIGHTNESS;
+ data->led_mc_cdev.led_cdev.flags = LED_REJECT_NAME_CONFLICT;
+ data->led_mc_cdev.led_cdev.brightness_set_blocking = uniwill_led_brightness_set;
+
+ if (value & LIGHTBAR_S0_OFF)
+ data->led_mc_cdev.led_cdev.brightness = 0;
+ else
+ data->led_mc_cdev.led_cdev.brightness = LED_MAX_BRIGHTNESS;
+
+ for (int i = 0; i < LED_CHANNELS; i++) {
+ data->led_mc_subled_info[i].color_index = color_indices[i];
+
+ ret = regmap_read(data->regmap, uniwill_led_channel_to_ac_reg[i], &value);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Make sure that the initial intensity value is not greater than
+ * the maximum brightness.
+ */
+ value = min(LED_MAX_BRIGHTNESS, value);
+ ret = regmap_write(data->regmap, uniwill_led_channel_to_ac_reg[i], value);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_write(data->regmap, uniwill_led_channel_to_bat_reg[i], value);
+ if (ret < 0)
+ return ret;
+
+ data->led_mc_subled_info[i].intensity = value;
+ data->led_mc_subled_info[i].channel = i;
+ }
+
+ data->led_mc_cdev.subled_info = data->led_mc_subled_info;
+ data->led_mc_cdev.num_colors = LED_CHANNELS;
+
+ return devm_led_classdev_multicolor_register_ext(data->dev, &data->led_mc_cdev,
+ &init_data);
+}
+
+static int uniwill_get_property(struct power_supply *psy, const struct power_supply_ext *ext,
+ void *drvdata, enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct uniwill_data *data = drvdata;
+ union power_supply_propval prop;
+ unsigned int regval;
+ int ret;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_HEALTH:
+ ret = power_supply_get_property_direct(psy, POWER_SUPPLY_PROP_PRESENT, &prop);
+ if (ret < 0)
+ return ret;
+
+ if (!prop.intval) {
+ val->intval = POWER_SUPPLY_HEALTH_NO_BATTERY;
+ return 0;
+ }
+
+ ret = power_supply_get_property_direct(psy, POWER_SUPPLY_PROP_STATUS, &prop);
+ if (ret < 0)
+ return ret;
+
+ if (prop.intval == POWER_SUPPLY_STATUS_UNKNOWN) {
+ val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
+ return 0;
+ }
+
+ ret = regmap_read(data->regmap, EC_ADDR_BAT_ALERT, &regval);
+ if (ret < 0)
+ return ret;
+
+ if (regval) {
+ /* Charging issue */
+ val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
+ return 0;
+ }
+
+ val->intval = POWER_SUPPLY_HEALTH_GOOD;
+ return 0;
+ case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD:
+ ret = regmap_read(data->regmap, EC_ADDR_CHARGE_CTRL, &regval);
+ if (ret < 0)
+ return ret;
+
+ val->intval = clamp_val(FIELD_GET(CHARGE_CTRL_MASK, regval), 0, 100);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int uniwill_set_property(struct power_supply *psy, const struct power_supply_ext *ext,
+ void *drvdata, enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ struct uniwill_data *data = drvdata;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD:
+ if (val->intval < 1 || val->intval > 100)
+ return -EINVAL;
+
+ return regmap_update_bits(data->regmap, EC_ADDR_CHARGE_CTRL, CHARGE_CTRL_MASK,
+ val->intval);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int uniwill_property_is_writeable(struct power_supply *psy,
+ const struct power_supply_ext *ext, void *drvdata,
+ enum power_supply_property psp)
+{
+ if (psp == POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD)
+ return true;
+
+ return false;
+}
+
+static const enum power_supply_property uniwill_properties[] = {
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD,
+};
+
+static const struct power_supply_ext uniwill_extension = {
+ .name = DRIVER_NAME,
+ .properties = uniwill_properties,
+ .num_properties = ARRAY_SIZE(uniwill_properties),
+ .get_property = uniwill_get_property,
+ .set_property = uniwill_set_property,
+ .property_is_writeable = uniwill_property_is_writeable,
+};
+
+static int uniwill_add_battery(struct power_supply *battery, struct acpi_battery_hook *hook)
+{
+ struct uniwill_data *data = container_of(hook, struct uniwill_data, hook);
+ struct uniwill_battery_entry *entry;
+ int ret;
+
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+
+ ret = power_supply_register_extension(battery, &uniwill_extension, data->dev, data);
+ if (ret < 0) {
+ kfree(entry);
+ return ret;
+ }
+
+ guard(mutex)(&data->battery_lock);
+
+ entry->battery = battery;
+ list_add(&entry->head, &data->batteries);
+
+ return 0;
+}
+
+static int uniwill_remove_battery(struct power_supply *battery, struct acpi_battery_hook *hook)
+{
+ struct uniwill_data *data = container_of(hook, struct uniwill_data, hook);
+ struct uniwill_battery_entry *entry, *tmp;
+
+ scoped_guard(mutex, &data->battery_lock) {
+ list_for_each_entry_safe(entry, tmp, &data->batteries, head) {
+ if (entry->battery == battery) {
+ list_del(&entry->head);
+ kfree(entry);
+ break;
+ }
+ }
+ }
+
+ power_supply_unregister_extension(battery, &uniwill_extension);
+
+ return 0;
+}
+
+static int uniwill_battery_init(struct uniwill_data *data)
+{
+ int ret;
+
+ if (!(supported_features & UNIWILL_FEATURE_BATTERY))
+ return 0;
+
+ ret = devm_mutex_init(data->dev, &data->battery_lock);
+ if (ret < 0)
+ return ret;
+
+ INIT_LIST_HEAD(&data->batteries);
+ data->hook.name = "Uniwill Battery Extension";
+ data->hook.add_battery = uniwill_add_battery;
+ data->hook.remove_battery = uniwill_remove_battery;
+
+ return devm_battery_hook_register(data->dev, &data->hook);
+}
+
+static int uniwill_notifier_call(struct notifier_block *nb, unsigned long action, void *dummy)
+{
+ struct uniwill_data *data = container_of(nb, struct uniwill_data, nb);
+ struct uniwill_battery_entry *entry;
+
+ switch (action) {
+ case UNIWILL_OSD_BATTERY_ALERT:
+ mutex_lock(&data->battery_lock);
+ list_for_each_entry(entry, &data->batteries, head) {
+ power_supply_changed(entry->battery);
+ }
+ mutex_unlock(&data->battery_lock);
+
+ return NOTIFY_OK;
+ case UNIWILL_OSD_DC_ADAPTER_CHANGED:
+ /* noop for the time being, will change once charging priority
+ * gets implemented.
+ */
+
+ return NOTIFY_OK;
+ default:
+ mutex_lock(&data->input_lock);
+ sparse_keymap_report_event(data->input_device, action, 1, true);
+ mutex_unlock(&data->input_lock);
+
+ return NOTIFY_OK;
+ }
+}
+
+static int uniwill_input_init(struct uniwill_data *data)
+{
+ int ret;
+
+ ret = devm_mutex_init(data->dev, &data->input_lock);
+ if (ret < 0)
+ return ret;
+
+ data->input_device = devm_input_allocate_device(data->dev);
+ if (!data->input_device)
+ return -ENOMEM;
+
+ ret = sparse_keymap_setup(data->input_device, uniwill_keymap, NULL);
+ if (ret < 0)
+ return ret;
+
+ data->input_device->name = "Uniwill WMI hotkeys";
+ data->input_device->phys = "wmi/input0";
+ data->input_device->id.bustype = BUS_HOST;
+ ret = input_register_device(data->input_device);
+ if (ret < 0)
+ return ret;
+
+ data->nb.notifier_call = uniwill_notifier_call;
+
+ return devm_uniwill_wmi_register_notifier(data->dev, &data->nb);
+}
+
+static void uniwill_disable_manual_control(void *context)
+{
+ struct uniwill_data *data = context;
+
+ regmap_clear_bits(data->regmap, EC_ADDR_AP_OEM, ENABLE_MANUAL_CTRL);
+}
+
+static int uniwill_ec_init(struct uniwill_data *data)
+{
+ unsigned int value;
+ int ret;
+
+ ret = regmap_read(data->regmap, EC_ADDR_PROJECT_ID, &value);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(data->dev, "Project ID: %u\n", value);
+
+ ret = regmap_set_bits(data->regmap, EC_ADDR_AP_OEM, ENABLE_MANUAL_CTRL);
+ if (ret < 0)
+ return ret;
+
+ return devm_add_action_or_reset(data->dev, uniwill_disable_manual_control, data);
+}
+
+static int uniwill_probe(struct platform_device *pdev)
+{
+ struct uniwill_data *data;
+ struct regmap *regmap;
+ acpi_handle handle;
+ int ret;
+
+ handle = ACPI_HANDLE(&pdev->dev);
+ if (!handle)
+ return -ENODEV;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->dev = &pdev->dev;
+ data->handle = handle;
+ platform_set_drvdata(pdev, data);
+
+ regmap = devm_regmap_init(&pdev->dev, &uniwill_ec_bus, data, &uniwill_ec_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ data->regmap = regmap;
+ ret = devm_mutex_init(&pdev->dev, &data->super_key_lock);
+ if (ret < 0)
+ return ret;
+
+ ret = uniwill_ec_init(data);
+ if (ret < 0)
+ return ret;
+
+ ret = uniwill_battery_init(data);
+ if (ret < 0)
+ return ret;
+
+ ret = uniwill_led_init(data);
+ if (ret < 0)
+ return ret;
+
+ ret = uniwill_hwmon_init(data);
+ if (ret < 0)
+ return ret;
+
+ return uniwill_input_init(data);
+}
+
+static void uniwill_shutdown(struct platform_device *pdev)
+{
+ struct uniwill_data *data = platform_get_drvdata(pdev);
+
+ regmap_clear_bits(data->regmap, EC_ADDR_AP_OEM, ENABLE_MANUAL_CTRL);
+}
+
+static int uniwill_suspend_keyboard(struct uniwill_data *data)
+{
+ if (!(supported_features & UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
+ return 0;
+
+ /*
+ * The EC_ADDR_SWITCH_STATUS is marked as volatile, so we have to restore it
+ * ourselves.
+ */
+ return regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, &data->last_switch_status);
+}
+
+static int uniwill_suspend_battery(struct uniwill_data *data)
+{
+ if (!(supported_features & UNIWILL_FEATURE_BATTERY))
+ return 0;
+
+ /*
+ * Save the current charge limit in order to restore it during resume.
+ * We cannot use the regmap code for that since this register needs to
+ * be declared as volatile due to CHARGE_CTRL_REACHED.
+ */
+ return regmap_read(data->regmap, EC_ADDR_CHARGE_CTRL, &data->last_charge_ctrl);
+}
+
+static int uniwill_suspend(struct device *dev)
+{
+ struct uniwill_data *data = dev_get_drvdata(dev);
+ int ret;
+
+ ret = uniwill_suspend_keyboard(data);
+ if (ret < 0)
+ return ret;
+
+ ret = uniwill_suspend_battery(data);
+ if (ret < 0)
+ return ret;
+
+ regcache_cache_only(data->regmap, true);
+ regcache_mark_dirty(data->regmap);
+
+ return 0;
+}
+
+static int uniwill_resume_keyboard(struct uniwill_data *data)
+{
+ unsigned int value;
+ int ret;
+
+ if (!(supported_features & UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
+ return 0;
+
+ ret = regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, &value);
+ if (ret < 0)
+ return ret;
+
+ if ((data->last_switch_status & SUPER_KEY_LOCK_STATUS) == (value & SUPER_KEY_LOCK_STATUS))
+ return 0;
+
+ return regmap_write_bits(data->regmap, EC_ADDR_TRIGGER, TRIGGER_SUPER_KEY_LOCK,
+ TRIGGER_SUPER_KEY_LOCK);
+}
+
+static int uniwill_resume_battery(struct uniwill_data *data)
+{
+ if (!(supported_features & UNIWILL_FEATURE_BATTERY))
+ return 0;
+
+ return regmap_update_bits(data->regmap, EC_ADDR_CHARGE_CTRL, CHARGE_CTRL_MASK,
+ data->last_charge_ctrl);
+}
+
+static int uniwill_resume(struct device *dev)
+{
+ struct uniwill_data *data = dev_get_drvdata(dev);
+ int ret;
+
+ regcache_cache_only(data->regmap, false);
+
+ ret = regcache_sync(data->regmap);
+ if (ret < 0)
+ return ret;
+
+ ret = uniwill_resume_keyboard(data);
+ if (ret < 0)
+ return ret;
+
+ return uniwill_resume_battery(data);
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(uniwill_pm_ops, uniwill_suspend, uniwill_resume);
+
+/*
+ * We only use the DMI table for auoloading because the ACPI device itself
+ * does not guarantee that the underlying EC implementation is supported.
+ */
+static const struct acpi_device_id uniwill_id_table[] = {
+ { "INOU0000" },
+ { },
+};
+
+static struct platform_driver uniwill_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .dev_groups = uniwill_groups,
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ .acpi_match_table = uniwill_id_table,
+ .pm = pm_sleep_ptr(&uniwill_pm_ops),
+ },
+ .probe = uniwill_probe,
+ .shutdown = uniwill_shutdown,
+};
+
+static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
+ {
+ .ident = "XMG FUSION 15",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "SchenkerTechnologiesGmbH"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "LAPQC71A"),
+ },
+ },
+ {
+ .ident = "XMG FUSION 15",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "SchenkerTechnologiesGmbH"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "LAPQC71B"),
+ },
+ },
+ {
+ .ident = "Intel NUC x15",
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "LAPAC71H"),
+ },
+ .driver_data = (void *)(UNIWILL_FEATURE_FN_LOCK_TOGGLE |
+ UNIWILL_FEATURE_SUPER_KEY_TOGGLE |
+ UNIWILL_FEATURE_TOUCHPAD_TOGGLE |
+ UNIWILL_FEATURE_BATTERY |
+ UNIWILL_FEATURE_HWMON),
+ },
+ {
+ .ident = "Intel NUC x15",
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "LAPKC71F"),
+ },
+ .driver_data = (void *)(UNIWILL_FEATURE_FN_LOCK_TOGGLE |
+ UNIWILL_FEATURE_SUPER_KEY_TOGGLE |
+ UNIWILL_FEATURE_TOUCHPAD_TOGGLE |
+ UNIWILL_FEATURE_LIGHTBAR |
+ UNIWILL_FEATURE_BATTERY |
+ UNIWILL_FEATURE_HWMON),
+ },
+ {
+ .ident = "TUXEDO InfinityBook Pro 14 Gen6 Intel",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxTxX1"),
+ },
+ },
+ {
+ .ident = "TUXEDO InfinityBook Pro 14 Gen6 Intel",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxTQx1"),
+ },
+ },
+ {
+ .ident = "TUXEDO InfinityBook Pro 14/16 Gen7 Intel",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxARX1_PHxAQF1"),
+ },
+ },
+ {
+ .ident = "TUXEDO InfinityBook Pro 16 Gen7 Intel/Commodore Omnia-Book Pro Gen 7",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH6AG01_PH6AQ71_PH6AQI1"),
+ },
+ },
+ {
+ .ident = "TUXEDO InfinityBook Pro 14/16 Gen8 Intel/Commodore Omnia-Book Pro Gen 8",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH4PRX1_PH6PRX1"),
+ },
+ },
+ {
+ .ident = "TUXEDO InfinityBook Pro 14 Gen8 Intel/Commodore Omnia-Book Pro Gen 8",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH4PG31"),
+ },
+ },
+ {
+ .ident = "TUXEDO InfinityBook Pro 16 Gen8 Intel",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH6PG01_PH6PG71"),
+ },
+ },
+ {
+ .ident = "TUXEDO InfinityBook Pro 14/15 Gen9 AMD",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "GXxHRXx"),
+ },
+ },
+ {
+ .ident = "TUXEDO InfinityBook Pro 14/15 Gen9 Intel/Commodore Omnia-Book 15 Gen9",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "GXxMRXx"),
+ },
+ },
+ {
+ .ident = "TUXEDO InfinityBook Pro 14/15 Gen10 AMD",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "XxHP4NAx"),
+ },
+ },
+ {
+ .ident = "TUXEDO InfinityBook Pro 14/15 Gen10 AMD",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "XxKK4NAx_XxSP4NAx"),
+ },
+ },
+ {
+ .ident = "TUXEDO InfinityBook Pro 15 Gen10 Intel",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "XxAR4NAx"),
+ },
+ },
+ {
+ .ident = "TUXEDO InfinityBook Max 15 Gen10 AMD",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "X5KK45xS_X5SP45xS"),
+ },
+ },
+ {
+ .ident = "TUXEDO InfinityBook Max 16 Gen10 AMD",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6HP45xU"),
+ },
+ },
+ {
+ .ident = "TUXEDO InfinityBook Max 16 Gen10 AMD",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6KK45xU_X6SP45xU"),
+ },
+ },
+ {
+ .ident = "TUXEDO InfinityBook Max 15 Gen10 Intel",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "X5AR45xS"),
+ },
+ },
+ {
+ .ident = "TUXEDO InfinityBook Max 16 Gen10 Intel",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR55xU"),
+ },
+ },
+ {
+ .ident = "TUXEDO Polaris 15 Gen1 AMD",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501A1650TI"),
+ },
+ },
+ {
+ .ident = "TUXEDO Polaris 15 Gen1 AMD",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501A2060"),
+ },
+ },
+ {
+ .ident = "TUXEDO Polaris 17 Gen1 AMD",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701A1650TI"),
+ },
+ },
+ {
+ .ident = "TUXEDO Polaris 17 Gen1 AMD",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701A2060"),
+ },
+ },
+ {
+ .ident = "TUXEDO Polaris 15 Gen1 Intel",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501I1650TI"),
+ },
+ },
+ {
+ .ident = "TUXEDO Polaris 15 Gen1 Intel",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501I2060"),
+ },
+ },
+ {
+ .ident = "TUXEDO Polaris 17 Gen1 Intel",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701I1650TI"),
+ },
+ },
+ {
+ .ident = "TUXEDO Polaris 17 Gen1 Intel",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701I2060"),
+ },
+ },
+ {
+ .ident = "TUXEDO Trinity 15 Intel Gen1",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "TRINITY1501I"),
+ },
+ },
+ {
+ .ident = "TUXEDO Trinity 17 Intel Gen1",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "TRINITY1701I"),
+ },
+ },
+ {
+ .ident = "TUXEDO Polaris 15/17 Gen2 AMD",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxMGxx"),
+ },
+ },
+ {
+ .ident = "TUXEDO Polaris 15/17 Gen2 Intel",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxNGxx"),
+ },
+ },
+ {
+ .ident = "TUXEDO Stellaris/Polaris 15/17 Gen3 AMD",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxZGxx"),
+ },
+ },
+ {
+ .ident = "TUXEDO Stellaris/Polaris 15/17 Gen3 Intel",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxTGxx"),
+ },
+ },
+ {
+ .ident = "TUXEDO Stellaris/Polaris 15/17 Gen4 AMD",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxRGxx"),
+ },
+ },
+ {
+ .ident = "TUXEDO Stellaris 15 Gen4 Intel",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxAGxx"),
+ },
+ },
+ {
+ .ident = "TUXEDO Polaris 15/17 Gen5 AMD",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxXGxx"),
+ },
+ },
+ {
+ .ident = "TUXEDO Stellaris 16 Gen5 AMD",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6XGxX"),
+ },
+ },
+ {
+ .ident = "TUXEDO Stellaris 16/17 Gen5 Intel/Commodore ORION Gen 5",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxPXxx"),
+ },
+ },
+ {
+ .ident = "TUXEDO Stellaris Slim 15 Gen6 AMD",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxHGxx"),
+ },
+ },
+ {
+ .ident = "TUXEDO Stellaris Slim 15 Gen6 Intel/Commodore ORION Slim 15 Gen6",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM5IXxA"),
+ },
+ },
+ {
+ .ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 16 Gen6",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB1"),
+ },
+ },
+ {
+ .ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 16 Gen6",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB2"),
+ },
+ },
+ {
+ .ident = "TUXEDO Stellaris 17 Gen6 Intel/Commodore ORION 17 Gen6",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM7IXxN"),
+ },
+ },
+ {
+ .ident = "TUXEDO Stellaris 16 Gen7 AMD",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6FR5xxY"),
+ },
+ },
+ {
+ .ident = "TUXEDO Stellaris 16 Gen7 Intel",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY"),
+ },
+ },
+ {
+ .ident = "TUXEDO Stellaris 16 Gen7 Intel",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY_mLED"),
+ },
+ },
+ {
+ .ident = "TUXEDO Pulse 14 Gen1 AMD",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "PULSE1401"),
+ },
+ },
+ {
+ .ident = "TUXEDO Pulse 15 Gen1 AMD",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "PULSE1501"),
+ },
+ },
+ {
+ .ident = "TUXEDO Pulse 15 Gen2 AMD",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "PF5LUXG"),
+ },
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(dmi, uniwill_dmi_table);
+
+static int __init uniwill_init(void)
+{
+ const struct dmi_system_id *id;
+ int ret;
+
+ id = dmi_first_match(uniwill_dmi_table);
+ if (!id) {
+ if (!force)
+ return -ENODEV;
+
+ /* Assume that the device supports all features */
+ supported_features = UINT_MAX;
+ pr_warn("Loading on a potentially unsupported device\n");
+ } else {
+ supported_features = (uintptr_t)id->driver_data;
+ }
+
+ ret = platform_driver_register(&uniwill_driver);
+ if (ret < 0)
+ return ret;
+
+ ret = uniwill_wmi_register_driver();
+ if (ret < 0) {
+ platform_driver_unregister(&uniwill_driver);
+ return ret;
+ }
+
+ return 0;
+}
+module_init(uniwill_init);
+
+static void __exit uniwill_exit(void)
+{
+ uniwill_wmi_unregister_driver();
+ platform_driver_unregister(&uniwill_driver);
+}
+module_exit(uniwill_exit);
+
+MODULE_AUTHOR("Armin Wolf <W_Armin@gmx.de>");
+MODULE_DESCRIPTION("Uniwill notebook driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/uniwill/uniwill-wmi.c b/drivers/platform/x86/uniwill/uniwill-wmi.c
new file mode 100644
index 000000000000..31d9c39f14ab
--- /dev/null
+++ b/drivers/platform/x86/uniwill/uniwill-wmi.c
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Linux hotkey driver for Uniwill notebooks.
+ *
+ * Special thanks go to PÅ‘cze BarnabĂ¡s, Christoffer Sandberg and Werner Sembach
+ * for supporting the development of this driver either through prior work or
+ * by answering questions regarding the underlying WMI interface.
+ *
+ * Copyright (C) 2025 Armin Wolf <W_Armin@gmx.de>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/mod_devicetable.h>
+#include <linux/notifier.h>
+#include <linux/printk.h>
+#include <linux/types.h>
+#include <linux/wmi.h>
+
+#include "uniwill-wmi.h"
+
+#define DRIVER_NAME "uniwill-wmi"
+#define UNIWILL_EVENT_GUID "ABBC0F72-8EA1-11D1-00A0-C90629100000"
+
+static BLOCKING_NOTIFIER_HEAD(uniwill_wmi_chain_head);
+
+static void devm_uniwill_wmi_unregister_notifier(void *data)
+{
+ struct notifier_block *nb = data;
+
+ blocking_notifier_chain_unregister(&uniwill_wmi_chain_head, nb);
+}
+
+int devm_uniwill_wmi_register_notifier(struct device *dev, struct notifier_block *nb)
+{
+ int ret;
+
+ ret = blocking_notifier_chain_register(&uniwill_wmi_chain_head, nb);
+ if (ret < 0)
+ return ret;
+
+ return devm_add_action_or_reset(dev, devm_uniwill_wmi_unregister_notifier, nb);
+}
+
+static void uniwill_wmi_notify(struct wmi_device *wdev, union acpi_object *obj)
+{
+ u32 value;
+
+ if (obj->type != ACPI_TYPE_INTEGER)
+ return;
+
+ value = obj->integer.value;
+
+ dev_dbg(&wdev->dev, "Received WMI event %u\n", value);
+
+ blocking_notifier_call_chain(&uniwill_wmi_chain_head, value, NULL);
+}
+
+/*
+ * We cannot fully trust this GUID since Uniwill just copied the WMI GUID
+ * from the Windows driver example, and others probably did the same.
+ *
+ * Because of this we cannot use this WMI GUID for autoloading. Instead the
+ * associated driver will be registered manually after matching a DMI table.
+ */
+static const struct wmi_device_id uniwill_wmi_id_table[] = {
+ { UNIWILL_EVENT_GUID, NULL },
+ { }
+};
+
+static struct wmi_driver uniwill_wmi_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ },
+ .id_table = uniwill_wmi_id_table,
+ .notify = uniwill_wmi_notify,
+ .no_singleton = true,
+};
+
+int __init uniwill_wmi_register_driver(void)
+{
+ return wmi_driver_register(&uniwill_wmi_driver);
+}
+
+void __exit uniwill_wmi_unregister_driver(void)
+{
+ wmi_driver_unregister(&uniwill_wmi_driver);
+}
diff --git a/drivers/platform/x86/uniwill/uniwill-wmi.h b/drivers/platform/x86/uniwill/uniwill-wmi.h
new file mode 100644
index 000000000000..48783b2e9ffb
--- /dev/null
+++ b/drivers/platform/x86/uniwill/uniwill-wmi.h
@@ -0,0 +1,129 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Linux hotkey driver for Uniwill notebooks.
+ *
+ * Copyright (C) 2025 Armin Wolf <W_Armin@gmx.de>
+ */
+
+#ifndef UNIWILL_WMI_H
+#define UNIWILL_WMI_H
+
+#include <linux/init.h>
+
+#define UNIWILL_OSD_CAPSLOCK 0x01
+#define UNIWILL_OSD_NUMLOCK 0x02
+#define UNIWILL_OSD_SCROLLLOCK 0x03
+
+#define UNIWILL_OSD_TOUCHPAD_ON 0x04
+#define UNIWILL_OSD_TOUCHPAD_OFF 0x05
+
+#define UNIWILL_OSD_SILENT_MODE_ON 0x06
+#define UNIWILL_OSD_SILENT_MODE_OFF 0x07
+
+#define UNIWILL_OSD_WLAN_ON 0x08
+#define UNIWILL_OSD_WLAN_OFF 0x09
+
+#define UNIWILL_OSD_WIMAX_ON 0x0A
+#define UNIWILL_OSD_WIMAX_OFF 0x0B
+
+#define UNIWILL_OSD_BLUETOOTH_ON 0x0C
+#define UNIWILL_OSD_BLUETOOTH_OFF 0x0D
+
+#define UNIWILL_OSD_RF_ON 0x0E
+#define UNIWILL_OSD_RF_OFF 0x0F
+
+#define UNIWILL_OSD_3G_ON 0x10
+#define UNIWILL_OSD_3G_OFF 0x11
+
+#define UNIWILL_OSD_WEBCAM_ON 0x12
+#define UNIWILL_OSD_WEBCAM_OFF 0x13
+
+#define UNIWILL_OSD_BRIGHTNESSUP 0x14
+#define UNIWILL_OSD_BRIGHTNESSDOWN 0x15
+
+#define UNIWILL_OSD_RADIOON 0x1A
+#define UNIWILL_OSD_RADIOOFF 0x1B
+
+#define UNIWILL_OSD_POWERSAVE_ON 0x31
+#define UNIWILL_OSD_POWERSAVE_OFF 0x32
+
+#define UNIWILL_OSD_MENU 0x34
+
+#define UNIWILL_OSD_MUTE 0x35
+#define UNIWILL_OSD_VOLUMEDOWN 0x36
+#define UNIWILL_OSD_VOLUMEUP 0x37
+
+#define UNIWILL_OSD_MENU_2 0x38
+
+#define UNIWILL_OSD_LIGHTBAR_ON 0x39
+#define UNIWILL_OSD_LIGHTBAR_OFF 0x3A
+
+#define UNIWILL_OSD_KB_LED_LEVEL0 0x3B
+#define UNIWILL_OSD_KB_LED_LEVEL1 0x3C
+#define UNIWILL_OSD_KB_LED_LEVEL2 0x3D
+#define UNIWILL_OSD_KB_LED_LEVEL3 0x3E
+#define UNIWILL_OSD_KB_LED_LEVEL4 0x3F
+
+#define UNIWILL_OSD_SUPER_KEY_LOCK_ENABLE 0x40
+#define UNIWILL_OSD_SUPER_KEY_LOCK_DISABLE 0x41
+
+#define UNIWILL_OSD_MENU_JP 0x42
+
+#define UNIWILL_OSD_CAMERA_ON 0x90
+#define UNIWILL_OSD_CAMERA_OFF 0x91
+
+#define UNIWILL_OSD_RFKILL 0xA4
+
+#define UNIWILL_OSD_SUPER_KEY_LOCK_CHANGED 0xA5
+
+#define UNIWILL_OSD_LIGHTBAR_STATE_CHANGED 0xA6
+
+#define UNIWILL_OSD_FAN_BOOST_STATE_CHANGED 0xA7
+
+#define UNIWILL_OSD_LCD_SW 0xA9
+
+#define UNIWILL_OSD_FAN_OVERTEMP 0xAA
+
+#define UNIWILL_OSD_DC_ADAPTER_CHANGED 0xAB
+
+#define UNIWILL_OSD_BAT_HP_OFF 0xAC
+
+#define UNIWILL_OSD_FAN_DOWN_TEMP 0xAD
+
+#define UNIWILL_OSD_BATTERY_ALERT 0xAE
+
+#define UNIWILL_OSD_TIMAP_HAIERLB_SW 0xAF
+
+#define UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE 0xB0
+
+#define UNIWILL_OSD_KBDILLUMDOWN 0xB1
+#define UNIWILL_OSD_KBDILLUMUP 0xB2
+
+#define UNIWILL_OSD_BACKLIGHT_LEVEL_CHANGE 0xB3
+#define UNIWILL_OSD_BACKLIGHT_POWER_CHANGE 0xB4
+
+#define UNIWILL_OSD_MIC_MUTE 0xB7
+
+#define UNIWILL_OSD_FN_LOCK 0xB8
+#define UNIWILL_OSD_KBDILLUMTOGGLE 0xB9
+
+#define UNIWILL_OSD_BAT_CHARGE_FULL_24_H 0xBE
+
+#define UNIWILL_OSD_BAT_ERM_UPDATE 0xBF
+
+#define UNIWILL_OSD_BENCHMARK_MODE_TOGGLE 0xC0
+
+#define UNIWILL_OSD_WEBCAM_TOGGLE 0xCF
+
+#define UNIWILL_OSD_KBD_BACKLIGHT_CHANGED 0xF0
+
+struct device;
+struct notifier_block;
+
+int devm_uniwill_wmi_register_notifier(struct device *dev, struct notifier_block *nb);
+
+int __init uniwill_wmi_register_driver(void);
+
+void __exit uniwill_wmi_unregister_driver(void);
+
+#endif /* UNIWILL_WMI_H */
diff --git a/drivers/platform/x86/x86-android-tablets/lenovo.c b/drivers/platform/x86/x86-android-tablets/lenovo.c
index e3d3a8290949..8d825e0b4661 100644
--- a/drivers/platform/x86/x86-android-tablets/lenovo.c
+++ b/drivers/platform/x86/x86-android-tablets/lenovo.c
@@ -543,7 +543,7 @@ static int __init lenovo_yoga_tab2_830_1050_init_codec(void)
ret = device_add_software_node(codec_dev, &lenovo_yoga_tab2_830_1050_wm5102);
if (ret) {
- ret = dev_err_probe(codec_dev, ret, "adding software node\n");
+ dev_err_probe(codec_dev, ret, "adding software node\n");
goto err_put_pinctrl;
}
diff --git a/drivers/platform/x86/x86-android-tablets/vexia_atla10_ec.c b/drivers/platform/x86/x86-android-tablets/vexia_atla10_ec.c
index 2f8cd8d9e0ab..ebbedfe5f4e8 100644
--- a/drivers/platform/x86/x86-android-tablets/vexia_atla10_ec.c
+++ b/drivers/platform/x86/x86-android-tablets/vexia_atla10_ec.c
@@ -183,7 +183,7 @@ static void atla10_ec_external_power_changed(struct power_supply *psy)
struct atla10_ec_data *data = power_supply_get_drvdata(psy);
/* After charger plug in/out wait 0.5s for things to stabilize */
- mod_delayed_work(system_wq, &data->work, HZ / 2);
+ mod_delayed_work(system_percpu_wq, &data->work, HZ / 2);
}
static const enum power_supply_property atla10_ec_psy_props[] = {
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index bf2d101f67a1..6f3147518376 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -760,7 +760,9 @@ config PWM_TEGRA
config PWM_TH1520
tristate "TH1520 PWM support"
+ depends on ARCH_THEAD || COMPILE_TEST
depends on RUST
+ depends on HAS_IOMEM && COMMON_CLK
select RUST_PWM_ABSTRACTIONS
help
This option enables the driver for the PWM controller found on the
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index f4987f54e01b..4b6182cde859 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -2823,14 +2823,18 @@ static void regulator_ena_gpio_free(struct regulator_dev *rdev)
static int regulator_ena_gpio_ctrl(struct regulator_dev *rdev, bool enable)
{
struct regulator_enable_gpio *pin = rdev->ena_pin;
+ int ret;
if (!pin)
return -EINVAL;
if (enable) {
/* Enable GPIO at initial use */
- if (pin->enable_count == 0)
- gpiod_set_value_cansleep(pin->gpiod, 1);
+ if (pin->enable_count == 0) {
+ ret = gpiod_set_value_cansleep(pin->gpiod, 1);
+ if (ret)
+ return ret;
+ }
pin->enable_count++;
} else {
@@ -2841,7 +2845,10 @@ static int regulator_ena_gpio_ctrl(struct regulator_dev *rdev, bool enable)
/* Disable GPIO if not used */
if (pin->enable_count <= 1) {
- gpiod_set_value_cansleep(pin->gpiod, 0);
+ ret = gpiod_set_value_cansleep(pin->gpiod, 0);
+ if (ret)
+ return ret;
+
pin->enable_count = 0;
}
}
diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
index a2d16e9abfb5..254c0a8a4555 100644
--- a/drivers/regulator/fixed.c
+++ b/drivers/regulator/fixed.c
@@ -330,13 +330,10 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
drvdata->dev = devm_regulator_register(&pdev->dev, &drvdata->desc,
&cfg);
- if (IS_ERR(drvdata->dev)) {
- ret = dev_err_probe(&pdev->dev, PTR_ERR(drvdata->dev),
- "Failed to register regulator: %ld\n",
- PTR_ERR(drvdata->dev));
- gpiod_put(cfg.ena_gpiod);
- return ret;
- }
+ if (IS_ERR(drvdata->dev))
+ return dev_err_probe(&pdev->dev, PTR_ERR(drvdata->dev),
+ "Failed to register regulator: %ld\n",
+ PTR_ERR(drvdata->dev));
platform_set_drvdata(pdev, drvdata);
diff --git a/drivers/regulator/spacemit-p1.c b/drivers/regulator/spacemit-p1.c
index d437e6738ea1..2bf9137e12b1 100644
--- a/drivers/regulator/spacemit-p1.c
+++ b/drivers/regulator/spacemit-p1.c
@@ -87,10 +87,10 @@ static const struct linear_range p1_ldo_ranges[] = {
}
#define P1_BUCK_DESC(_n) \
- P1_REG_DESC(BUCK, buck, _n, "vcc", 0x47, BUCK_MASK, 254, p1_buck_ranges)
+ P1_REG_DESC(BUCK, buck, _n, "vin", 0x47, BUCK_MASK, 254, p1_buck_ranges)
#define P1_ALDO_DESC(_n) \
- P1_REG_DESC(ALDO, aldo, _n, "vcc", 0x5b, LDO_MASK, 117, p1_ldo_ranges)
+ P1_REG_DESC(ALDO, aldo, _n, "vin", 0x5b, LDO_MASK, 117, p1_ldo_ranges)
#define P1_DLDO_DESC(_n) \
P1_REG_DESC(DLDO, dldo, _n, "buck5", 0x67, LDO_MASK, 117, p1_ldo_ranges)
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 2933c41c77c8..50dc779f7f98 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -409,13 +409,22 @@ config RTC_DRV_MAX77686
config RTC_DRV_SPACEMIT_P1
tristate "SpacemiT P1 RTC"
depends on ARCH_SPACEMIT || COMPILE_TEST
- select MFD_SPACEMIT_P1
- default ARCH_SPACEMIT
+ depends on MFD_SPACEMIT_P1
+ default MFD_SPACEMIT_P1
help
Enable support for the RTC function in the SpacemiT P1 PMIC.
This driver can also be built as a module, which will be called
"spacemit-p1-rtc".
+config RTC_DRV_NVIDIA_VRS10
+ tristate "NVIDIA VRS10 RTC device"
+ help
+ If you say yes here you will get support for the battery backed RTC device
+ of NVIDIA VRS (Voltage Regulator Specification). The RTC is connected via
+ I2C interface and supports alarm functionality.
+ This driver can also be built as a module. If so, the module will be called
+ rtc-nvidia-vrs10.
+
config RTC_DRV_NCT3018Y
tristate "Nuvoton NCT3018Y"
depends on OF
@@ -1063,6 +1072,21 @@ config RTC_DRV_ALPHA
Direct support for the real-time clock found on every Alpha
system, specifically MC146818 compatibles. If in doubt, say Y.
+config RTC_DRV_ATCRTC100
+ tristate "Andes ATCRTC100"
+ depends on ARCH_ANDES || COMPILE_TEST
+ select REGMAP_MMIO
+ help
+ If you say yes here you will get support for the Andes ATCRTC100
+ RTC driver.
+
+ This driver provides support for the Andes ATCRTC100 real-time clock
+ device. It allows setting and retrieving the time and date, as well
+ as setting alarms.
+
+ To compile this driver as a module, choose M here: the module will
+ be called rtc-atcrtc100.
+
config RTC_DRV_DS1216
tristate "Dallas DS1216"
depends on SNI_RM
@@ -1749,7 +1773,7 @@ config RTC_DRV_MC13XXX
tristate "Freescale MC13xxx RTC"
help
This enables support for the RTCs found on Freescale's PMICs
- MC13783 and MC13892.
+ MC13783, MC13892 and MC34708.
config RTC_DRV_MPC5121
tristate "Freescale MPC5121 built-in RTC"
@@ -2074,6 +2098,17 @@ config RTC_DRV_WILCO_EC
This can also be built as a module. If so, the module will
be named "rtc_wilco_ec".
+config RTC_DRV_MACSMC
+ tristate "Apple Mac System Management Controller RTC"
+ depends on MFD_MACSMC
+ help
+ If you say yes here you get support for RTC functions
+ inside Apple SPMI PMUs accessed through the SoC's
+ System Management Controller
+
+ To compile this driver as a module, choose M here: the
+ module will be called rtc-macsmc.
+
config RTC_DRV_MSC313
tristate "MStar MSC313 RTC"
depends on ARCH_MSTARV7 || COMPILE_TEST
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 8221bda6e6dc..6cf7e066314e 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_RTC_DRV_ASM9260) += rtc-asm9260.o
obj-$(CONFIG_RTC_DRV_ASPEED) += rtc-aspeed.o
obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o
+obj-$(CONFIG_RTC_DRV_ATCRTC100) += rtc-atcrtc100.o
obj-$(CONFIG_RTC_DRV_AU1XXX) += rtc-au1xxx.o
obj-$(CONFIG_RTC_DRV_BBNSM) += rtc-nxp-bbnsm.o
obj-$(CONFIG_RTC_DRV_BD70528) += rtc-bd70528.o
@@ -93,6 +94,7 @@ obj-$(CONFIG_RTC_DRV_M48T35) += rtc-m48t35.o
obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o
obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o
obj-$(CONFIG_RTC_DRV_MA35D1) += rtc-ma35d1.o
+obj-$(CONFIG_RTC_DRV_MACSMC) += rtc-macsmc.o
obj-$(CONFIG_RTC_DRV_MAX31335) += rtc-max31335.o
obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o
obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o
@@ -121,6 +123,7 @@ obj-$(CONFIG_RTC_DRV_GAMECUBE) += rtc-gamecube.o
obj-$(CONFIG_RTC_DRV_NCT3018Y) += rtc-nct3018y.o
obj-$(CONFIG_RTC_DRV_NCT6694) += rtc-nct6694.o
obj-$(CONFIG_RTC_DRV_NTXEC) += rtc-ntxec.o
+obj-$(CONFIG_RTC_DRV_NVIDIA_VRS10)+= rtc-nvidia-vrs10.o
obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o
obj-$(CONFIG_RTC_DRV_OPAL) += rtc-opal.o
obj-$(CONFIG_RTC_DRV_OPTEE) += rtc-optee.o
diff --git a/drivers/rtc/rtc-amlogic-a4.c b/drivers/rtc/rtc-amlogic-a4.c
index 1928b29c1045..123fb372fc9f 100644
--- a/drivers/rtc/rtc-amlogic-a4.c
+++ b/drivers/rtc/rtc-amlogic-a4.c
@@ -361,39 +361,26 @@ static int aml_rtc_probe(struct platform_device *pdev)
"failed to get_enable rtc sys clk\n");
aml_rtc_init(rtc);
- device_init_wakeup(dev, true);
+ devm_device_init_wakeup(dev);
platform_set_drvdata(pdev, rtc);
rtc->rtc_dev = devm_rtc_allocate_device(dev);
- if (IS_ERR(rtc->rtc_dev)) {
- ret = PTR_ERR(rtc->rtc_dev);
- goto err_clk;
- }
+ if (IS_ERR(rtc->rtc_dev))
+ return PTR_ERR(rtc->rtc_dev);
ret = devm_request_irq(dev, rtc->irq, aml_rtc_handler,
IRQF_ONESHOT, "aml-rtc alarm", rtc);
if (ret) {
dev_err_probe(dev, ret, "IRQ%d request failed, ret = %d\n",
rtc->irq, ret);
- goto err_clk;
+ return ret;
}
rtc->rtc_dev->ops = &aml_rtc_ops;
rtc->rtc_dev->range_min = 0;
rtc->rtc_dev->range_max = U32_MAX;
- ret = devm_rtc_register_device(rtc->rtc_dev);
- if (ret) {
- dev_err_probe(&pdev->dev, ret, "Failed to register RTC device: %d\n", ret);
- goto err_clk;
- }
-
- return 0;
-err_clk:
- clk_disable_unprepare(rtc->sys_clk);
- device_init_wakeup(dev, false);
-
- return ret;
+ return devm_rtc_register_device(rtc->rtc_dev);
}
#ifdef CONFIG_PM_SLEEP
@@ -421,14 +408,6 @@ static int aml_rtc_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(aml_rtc_pm_ops,
aml_rtc_suspend, aml_rtc_resume);
-static void aml_rtc_remove(struct platform_device *pdev)
-{
- struct aml_rtc_data *rtc = dev_get_drvdata(&pdev->dev);
-
- clk_disable_unprepare(rtc->sys_clk);
- device_init_wakeup(&pdev->dev, false);
-}
-
static const struct aml_rtc_config a5_rtc_config = {
};
@@ -451,7 +430,6 @@ MODULE_DEVICE_TABLE(of, aml_rtc_device_id);
static struct platform_driver aml_rtc_driver = {
.probe = aml_rtc_probe,
- .remove = aml_rtc_remove,
.driver = {
.name = "aml-rtc",
.pm = &aml_rtc_pm_ops,
diff --git a/drivers/rtc/rtc-atcrtc100.c b/drivers/rtc/rtc-atcrtc100.c
new file mode 100644
index 000000000000..9808fc2c5a49
--- /dev/null
+++ b/drivers/rtc/rtc-atcrtc100.c
@@ -0,0 +1,381 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Driver for Andes ATCRTC100 real time clock.
+ *
+ * Copyright (C) 2025 Andes Technology Corporation
+ */
+
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_wakeirq.h>
+#include <linux/regmap.h>
+#include <linux/rtc.h>
+#include <linux/workqueue.h>
+
+/* Register Offsets */
+#define RTC_ID 0x00 /* ID and Revision Register */
+#define RTC_RSV 0x04 /* Reserved Register */
+#define RTC_CNT 0x10 /* Counter Register */
+#define RTC_ALM 0x14 /* Alarm Register */
+#define RTC_CR 0x18 /* Control Register */
+#define RTC_STA 0x1C /* Status Register */
+#define RTC_TRIM 0x20 /* Digital Trimming Register */
+
+/* RTC_ID Register */
+#define ID_MSK GENMASK(31, 8)
+#define ID_ATCRTC100 0x030110
+
+/* RTC_CNT and RTC_ALM Register Fields */
+#define SEC_MSK GENMASK(5, 0)
+#define MIN_MSK GENMASK(11, 6)
+#define HOUR_MSK GENMASK(16, 12)
+#define DAY_MSK GENMASK(31, 17)
+#define RTC_SEC_GET(x) FIELD_GET(SEC_MSK, x)
+#define RTC_MIN_GET(x) FIELD_GET(MIN_MSK, x)
+#define RTC_HOUR_GET(x) FIELD_GET(HOUR_MSK, x)
+#define RTC_DAY_GET(x) FIELD_GET(DAY_MSK, x)
+#define RTC_SEC_SET(x) FIELD_PREP(SEC_MSK, x)
+#define RTC_MIN_SET(x) FIELD_PREP(MIN_MSK, x)
+#define RTC_HOUR_SET(x) FIELD_PREP(HOUR_MSK, x)
+#define RTC_DAY_SET(x) FIELD_PREP(DAY_MSK, x)
+
+/* RTC_CR Register Bits */
+#define RTC_EN BIT(0) /* RTC Enable */
+#define ALARM_WAKEUP BIT(1) /* Alarm Wakeup Enable */
+#define ALARM_INT BIT(2) /* Alarm Interrupt Enable */
+#define DAY_INT BIT(3) /* Day Interrupt Enable */
+#define HOUR_INT BIT(4) /* Hour Interrupt Enable */
+#define MIN_INT BIT(5) /* Minute Interrupt Enable */
+#define SEC_INT BIT(6) /* Second Periodic Interrupt Enable */
+#define HSEC_INT BIT(7) /* Half-Second Periodic Interrupt Enable */
+
+/* RTC_STA Register Bits */
+#define WRITE_DONE BIT(16) /* Register write completion status */
+
+/* Time conversion macro */
+#define ATCRTC_TIME_TO_SEC(D, H, M, S) \
+ ((time64_t)(D) * 86400 + (H) * 3600 + (M) * 60 + (S))
+
+/* Timeout for waiting for the write_done bit */
+#define ATCRTC_TIMEOUT_US 1000000
+#define ATCRTC_TIMEOUT_USLEEP_MIN 20
+#define ATCRTC_TIMEOUT_USLEEP_MAX 30
+
+struct atcrtc_dev {
+ struct rtc_device *rtc_dev;
+ struct regmap *regmap;
+ struct work_struct rtc_work;
+ unsigned int alarm_irq;
+ bool alarm_en;
+};
+
+static const struct regmap_config atcrtc_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = RTC_TRIM,
+ .cache_type = REGCACHE_NONE,
+};
+
+/**
+ * atcrtc_check_write_done - Wait for RTC registers to be synchronized.
+ * @rtc: Pointer to the atcrtc_dev structure.
+ *
+ * The WriteDone bit in the status register indicates the synchronization
+ * progress of RTC register updates. This bit is cleared to zero whenever
+ * any RTC control register (Counter, Alarm, Control, etc.) is written.
+ * It returns to one only after all previous updates have been fully
+ * synchronized to the RTC clock domain. This function polls the WriteDone
+ * bit with a timeout to ensure the device is ready for the next operation.
+ *
+ * Return: 0 on success, or -EBUSY on timeout.
+ */
+static int atcrtc_check_write_done(struct atcrtc_dev *rtc)
+{
+ unsigned int val;
+
+ /*
+ * Using read_poll_timeout is more efficient than a manual loop
+ * with usleep_range.
+ */
+ return regmap_read_poll_timeout(rtc->regmap, RTC_STA, val,
+ val & WRITE_DONE,
+ ATCRTC_TIMEOUT_USLEEP_MIN,
+ ATCRTC_TIMEOUT_US);
+}
+
+static irqreturn_t atcrtc_alarm_isr(int irq, void *dev)
+{
+ struct atcrtc_dev *rtc = dev;
+ unsigned int status;
+
+ regmap_read(rtc->regmap, RTC_STA, &status);
+ if (status & ALARM_INT) {
+ regmap_write(rtc->regmap, RTC_STA, ALARM_INT);
+ rtc->alarm_en = false;
+ schedule_work(&rtc->rtc_work);
+ rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF);
+ return IRQ_HANDLED;
+ }
+ return IRQ_NONE;
+}
+
+static int atcrtc_alarm_irq_enable(struct device *dev, unsigned int enable)
+{
+ struct atcrtc_dev *rtc = dev_get_drvdata(dev);
+ unsigned int mask;
+ int ret;
+
+ ret = atcrtc_check_write_done(rtc);
+ if (ret)
+ return ret;
+
+ mask = ALARM_WAKEUP | ALARM_INT;
+ regmap_update_bits(rtc->regmap, RTC_CR, mask, enable ? mask : 0);
+
+ return 0;
+}
+
+static void atcrtc_alarm_clear(struct work_struct *work)
+{
+ struct atcrtc_dev *rtc =
+ container_of(work, struct atcrtc_dev, rtc_work);
+ int ret;
+
+ rtc_lock(rtc->rtc_dev);
+
+ if (!rtc->alarm_en) {
+ ret = atcrtc_check_write_done(rtc);
+ if (ret)
+ dev_info(&rtc->rtc_dev->dev,
+ "failed to sync before clearing alarm: %d\n",
+ ret);
+ else
+ regmap_update_bits(rtc->regmap, RTC_CR,
+ ALARM_WAKEUP | ALARM_INT, 0);
+ }
+ rtc_unlock(rtc->rtc_dev);
+}
+
+static int atcrtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct atcrtc_dev *rtc = dev_get_drvdata(dev);
+ time64_t time;
+ unsigned int rtc_cnt;
+
+ if (!regmap_test_bits(rtc->regmap, RTC_CR, RTC_EN))
+ return -EIO;
+
+ regmap_read(rtc->regmap, RTC_CNT, &rtc_cnt);
+ time = ATCRTC_TIME_TO_SEC(RTC_DAY_GET(rtc_cnt),
+ RTC_HOUR_GET(rtc_cnt),
+ RTC_MIN_GET(rtc_cnt),
+ RTC_SEC_GET(rtc_cnt));
+ rtc_time64_to_tm(time, tm);
+
+ return 0;
+}
+
+static int atcrtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct atcrtc_dev *rtc = dev_get_drvdata(dev);
+ time64_t time;
+ unsigned int counter;
+ unsigned int day;
+ int ret;
+
+ time = rtc_tm_to_time64(tm);
+ day = div_s64(time, 86400);
+ counter = RTC_DAY_SET(day) |
+ RTC_HOUR_SET(tm->tm_hour) |
+ RTC_MIN_SET(tm->tm_min) |
+ RTC_SEC_SET(tm->tm_sec);
+ ret = atcrtc_check_write_done(rtc);
+ if (ret)
+ return ret;
+ regmap_write(rtc->regmap, RTC_CNT, counter);
+
+ ret = atcrtc_check_write_done(rtc);
+ if (ret)
+ return ret;
+ regmap_update_bits(rtc->regmap, RTC_CR, RTC_EN, RTC_EN);
+
+ return 0;
+}
+
+static int atcrtc_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
+{
+ struct atcrtc_dev *rtc = dev_get_drvdata(dev);
+ struct rtc_time *tm = &wkalrm->time;
+ unsigned int rtc_alarm;
+
+ wkalrm->enabled = regmap_test_bits(rtc->regmap, RTC_CR, ALARM_INT);
+ regmap_read(rtc->regmap, RTC_ALM, &rtc_alarm);
+ tm->tm_hour = RTC_HOUR_GET(rtc_alarm);
+ tm->tm_min = RTC_MIN_GET(rtc_alarm);
+ tm->tm_sec = RTC_SEC_GET(rtc_alarm);
+
+ /* The RTC alarm does not support day/month/year fields */
+ tm->tm_mday = -1;
+ tm->tm_mon = -1;
+ tm->tm_year = -1;
+
+ return 0;
+}
+
+static int atcrtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
+{
+ struct atcrtc_dev *rtc = dev_get_drvdata(dev);
+ struct rtc_time *tm = &wkalrm->time;
+ unsigned int rtc_alarm;
+ int ret;
+
+ /* Disable alarm first before setting a new one */
+ ret = atcrtc_alarm_irq_enable(dev, 0);
+ if (ret)
+ return ret;
+
+ rtc->alarm_en = false;
+
+ rtc_alarm = RTC_SEC_SET(tm->tm_sec) |
+ RTC_MIN_SET(tm->tm_min) |
+ RTC_HOUR_SET(tm->tm_hour);
+
+ ret = atcrtc_check_write_done(rtc);
+ if (ret)
+ return ret;
+
+ regmap_write(rtc->regmap, RTC_ALM, rtc_alarm);
+
+ rtc->alarm_en = wkalrm->enabled;
+ ret = atcrtc_alarm_irq_enable(dev, wkalrm->enabled);
+
+ return ret;
+}
+
+static const struct rtc_class_ops rtc_ops = {
+ .read_time = atcrtc_read_time,
+ .set_time = atcrtc_set_time,
+ .read_alarm = atcrtc_read_alarm,
+ .set_alarm = atcrtc_set_alarm,
+ .alarm_irq_enable = atcrtc_alarm_irq_enable,
+};
+
+static int atcrtc_probe(struct platform_device *pdev)
+{
+ struct atcrtc_dev *atcrtc_dev;
+ void __iomem *reg_base;
+ unsigned int rtc_id;
+ int ret;
+
+ atcrtc_dev = devm_kzalloc(&pdev->dev, sizeof(*atcrtc_dev), GFP_KERNEL);
+ if (!atcrtc_dev)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, atcrtc_dev);
+
+ reg_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(reg_base))
+ return dev_err_probe(&pdev->dev, PTR_ERR(reg_base),
+ "Failed to map I/O space\n");
+
+ atcrtc_dev->regmap = devm_regmap_init_mmio(&pdev->dev,
+ reg_base,
+ &atcrtc_regmap_config);
+ if (IS_ERR(atcrtc_dev->regmap))
+ return dev_err_probe(&pdev->dev, PTR_ERR(atcrtc_dev->regmap),
+ "Failed to initialize regmap\n");
+
+ regmap_read(atcrtc_dev->regmap, RTC_ID, &rtc_id);
+ if (FIELD_GET(ID_MSK, rtc_id) != ID_ATCRTC100)
+ return dev_err_probe(&pdev->dev, -ENODEV,
+ "Failed to initialize RTC: unsupported hardware ID 0x%x\n",
+ rtc_id);
+
+ ret = platform_get_irq(pdev, 1);
+ if (ret < 0)
+ return dev_err_probe(&pdev->dev, ret,
+ "Failed to get IRQ for alarm\n");
+ atcrtc_dev->alarm_irq = ret;
+
+ ret = devm_request_irq(&pdev->dev,
+ atcrtc_dev->alarm_irq,
+ atcrtc_alarm_isr,
+ 0,
+ "atcrtc_alarm",
+ atcrtc_dev);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "Failed to request IRQ %d for alarm\n",
+ atcrtc_dev->alarm_irq);
+
+ atcrtc_dev->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
+ if (IS_ERR(atcrtc_dev->rtc_dev))
+ return dev_err_probe(&pdev->dev, PTR_ERR(atcrtc_dev->rtc_dev),
+ "Failed to allocate RTC device\n");
+
+ set_bit(RTC_FEATURE_ALARM, atcrtc_dev->rtc_dev->features);
+ ret = device_init_wakeup(&pdev->dev, true);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "Failed to initialize wake capability\n");
+
+ ret = dev_pm_set_wake_irq(&pdev->dev, atcrtc_dev->alarm_irq);
+ if (ret) {
+ device_init_wakeup(&pdev->dev, false);
+ return dev_err_probe(&pdev->dev, ret,
+ "Failed to set wake IRQ\n");
+ }
+
+ atcrtc_dev->rtc_dev->ops = &rtc_ops;
+
+ INIT_WORK(&atcrtc_dev->rtc_work, atcrtc_alarm_clear);
+ return devm_rtc_register_device(atcrtc_dev->rtc_dev);
+}
+
+static int atcrtc_resume(struct device *dev)
+{
+ struct atcrtc_dev *rtc = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ disable_irq_wake(rtc->alarm_irq);
+
+ return 0;
+}
+
+static int atcrtc_suspend(struct device *dev)
+{
+ struct atcrtc_dev *rtc = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ enable_irq_wake(rtc->alarm_irq);
+
+ return 0;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(atcrtc_pm_ops, atcrtc_suspend, atcrtc_resume);
+
+static const struct of_device_id atcrtc_dt_match[] = {
+ { .compatible = "andestech,atcrtc100" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, atcrtc_dt_match);
+
+static struct platform_driver atcrtc_platform_driver = {
+ .driver = {
+ .name = "atcrtc100",
+ .of_match_table = atcrtc_dt_match,
+ .pm = pm_sleep_ptr(&atcrtc_pm_ops),
+ },
+ .probe = atcrtc_probe,
+};
+
+module_platform_driver(atcrtc_platform_driver);
+
+MODULE_AUTHOR("CL Wang <cl634@andestech.com>");
+MODULE_DESCRIPTION("Andes ATCRTC100 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-ds1685.c b/drivers/rtc/rtc-ds1685.c
index 97423f1d0361..5fc8e36b1abf 100644
--- a/drivers/rtc/rtc-ds1685.c
+++ b/drivers/rtc/rtc-ds1685.c
@@ -1268,9 +1268,6 @@ ds1685_rtc_probe(struct platform_device *pdev)
rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_2000;
rtc_dev->range_max = RTC_TIMESTAMP_END_2099;
- /* Maximum periodic rate is 8192Hz (0.122070ms). */
- rtc_dev->max_user_freq = RTC_MAX_USER_FREQ;
-
/* See if the platform doesn't support UIE. */
if (pdata->uie_unsupported)
clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc_dev->features);
diff --git a/drivers/rtc/rtc-gamecube.c b/drivers/rtc/rtc-gamecube.c
index c828bc8e05b9..045d5d45ab4b 100644
--- a/drivers/rtc/rtc-gamecube.c
+++ b/drivers/rtc/rtc-gamecube.c
@@ -242,6 +242,10 @@ static int gamecube_rtc_read_offset_from_sram(struct priv *d)
}
hw_srnprot = ioremap(res.start, resource_size(&res));
+ if (!hw_srnprot) {
+ pr_err("failed to ioremap hw_srnprot\n");
+ return -ENOMEM;
+ }
old = ioread32be(hw_srnprot);
/* TODO: figure out why we use this magic constant. I obtained it by
diff --git a/drivers/rtc/rtc-isl12026.c b/drivers/rtc/rtc-isl12026.c
index 2aabb9151d4c..45a2c9f676c5 100644
--- a/drivers/rtc/rtc-isl12026.c
+++ b/drivers/rtc/rtc-isl12026.c
@@ -484,6 +484,12 @@ static const struct of_device_id isl12026_dt_match[] = {
};
MODULE_DEVICE_TABLE(of, isl12026_dt_match);
+static const struct i2c_device_id isl12026_id[] = {
+ { "isl12026" },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, isl12026_id);
+
static struct i2c_driver isl12026_driver = {
.driver = {
.name = "rtc-isl12026",
@@ -491,6 +497,7 @@ static struct i2c_driver isl12026_driver = {
},
.probe = isl12026_probe,
.remove = isl12026_remove,
+ .id_table = isl12026_id,
};
module_i2c_driver(isl12026_driver);
diff --git a/drivers/rtc/rtc-macsmc.c b/drivers/rtc/rtc-macsmc.c
new file mode 100644
index 000000000000..8fe883066956
--- /dev/null
+++ b/drivers/rtc/rtc-macsmc.c
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+/*
+ * Apple SMC RTC driver
+ * Copyright The Asahi Linux Contributors
+ */
+
+#include <linux/bitops.h>
+#include <linux/mfd/macsmc.h>
+#include <linux/module.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/slab.h>
+
+/* 48-bit RTC */
+#define RTC_BYTES 6
+#define RTC_BITS (8 * RTC_BYTES)
+
+/* 32768 Hz clock */
+#define RTC_SEC_SHIFT 15
+
+struct macsmc_rtc {
+ struct device *dev;
+ struct apple_smc *smc;
+ struct rtc_device *rtc_dev;
+ struct nvmem_cell *rtc_offset;
+};
+
+static int macsmc_rtc_get_time(struct device *dev, struct rtc_time *tm)
+{
+ struct macsmc_rtc *rtc = dev_get_drvdata(dev);
+ u64 ctr = 0, off = 0;
+ time64_t now;
+ void *p_off;
+ size_t len;
+ int ret;
+
+ ret = apple_smc_read(rtc->smc, SMC_KEY(CLKM), &ctr, RTC_BYTES);
+ if (ret < 0)
+ return ret;
+ if (ret != RTC_BYTES)
+ return -EIO;
+
+ p_off = nvmem_cell_read(rtc->rtc_offset, &len);
+ if (IS_ERR(p_off))
+ return PTR_ERR(p_off);
+ if (len < RTC_BYTES) {
+ kfree(p_off);
+ return -EIO;
+ }
+
+ memcpy(&off, p_off, RTC_BYTES);
+ kfree(p_off);
+
+ /* Sign extend from 48 to 64 bits, then arithmetic shift right 15 bits to get seconds */
+ now = sign_extend64(ctr + off, RTC_BITS - 1) >> RTC_SEC_SHIFT;
+ rtc_time64_to_tm(now, tm);
+
+ return ret;
+}
+
+static int macsmc_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct macsmc_rtc *rtc = dev_get_drvdata(dev);
+ u64 ctr = 0, off = 0;
+ int ret;
+
+ ret = apple_smc_read(rtc->smc, SMC_KEY(CLKM), &ctr, RTC_BYTES);
+ if (ret < 0)
+ return ret;
+ if (ret != RTC_BYTES)
+ return -EIO;
+
+ /* This sets the offset such that the set second begins now */
+ off = (rtc_tm_to_time64(tm) << RTC_SEC_SHIFT) - ctr;
+ return nvmem_cell_write(rtc->rtc_offset, &off, RTC_BYTES);
+}
+
+static const struct rtc_class_ops macsmc_rtc_ops = {
+ .read_time = macsmc_rtc_get_time,
+ .set_time = macsmc_rtc_set_time,
+};
+
+static int macsmc_rtc_probe(struct platform_device *pdev)
+{
+ struct apple_smc *smc = dev_get_drvdata(pdev->dev.parent);
+ struct macsmc_rtc *rtc;
+
+ /*
+ * MFD will probe this device even without a node in the device tree,
+ * thus bail out early if the SMC on the current machines does not
+ * support RTC and has no node in the device tree.
+ */
+ if (!pdev->dev.of_node)
+ return -ENODEV;
+
+ rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
+ if (!rtc)
+ return -ENOMEM;
+
+ rtc->dev = &pdev->dev;
+ rtc->smc = smc;
+
+ rtc->rtc_offset = devm_nvmem_cell_get(&pdev->dev, "rtc_offset");
+ if (IS_ERR(rtc->rtc_offset))
+ return dev_err_probe(&pdev->dev, PTR_ERR(rtc->rtc_offset),
+ "Failed to get rtc_offset NVMEM cell\n");
+
+ rtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
+ if (IS_ERR(rtc->rtc_dev))
+ return PTR_ERR(rtc->rtc_dev);
+
+ rtc->rtc_dev->ops = &macsmc_rtc_ops;
+ rtc->rtc_dev->range_min = S64_MIN >> (RTC_SEC_SHIFT + (64 - RTC_BITS));
+ rtc->rtc_dev->range_max = S64_MAX >> (RTC_SEC_SHIFT + (64 - RTC_BITS));
+
+ platform_set_drvdata(pdev, rtc);
+
+ return devm_rtc_register_device(rtc->rtc_dev);
+}
+
+static const struct of_device_id macsmc_rtc_of_table[] = {
+ { .compatible = "apple,smc-rtc", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, macsmc_rtc_of_table);
+
+static struct platform_driver macsmc_rtc_driver = {
+ .driver = {
+ .name = "macsmc-rtc",
+ .of_match_table = macsmc_rtc_of_table,
+ },
+ .probe = macsmc_rtc_probe,
+};
+module_platform_driver(macsmc_rtc_driver);
+
+MODULE_LICENSE("Dual MIT/GPL");
+MODULE_DESCRIPTION("Apple SMC RTC driver");
+MODULE_AUTHOR("Hector Martin <marcan@marcan.st>");
diff --git a/drivers/rtc/rtc-max31335.c b/drivers/rtc/rtc-max31335.c
index dfb5bad3a369..23b7bf16b4cd 100644
--- a/drivers/rtc/rtc-max31335.c
+++ b/drivers/rtc/rtc-max31335.c
@@ -391,10 +391,8 @@ static int max31335_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
if (ret)
return ret;
- ret = regmap_update_bits(max31335->regmap, max31335->chip->int_status_reg,
- MAX31335_STATUS1_A1F, 0);
-
- return 0;
+ return regmap_update_bits(max31335->regmap, max31335->chip->int_status_reg,
+ MAX31335_STATUS1_A1F, 0);
}
static int max31335_alarm_irq_enable(struct device *dev, unsigned int enabled)
diff --git a/drivers/rtc/rtc-nvidia-vrs10.c b/drivers/rtc/rtc-nvidia-vrs10.c
new file mode 100644
index 000000000000..b15796698558
--- /dev/null
+++ b/drivers/rtc/rtc-nvidia-vrs10.c
@@ -0,0 +1,542 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * NVIDIA Voltage Regulator Specification RTC
+ *
+ * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
+ * All rights reserved.
+ */
+
+#include <linux/bits.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/rtc.h>
+
+#define NVVRS_REG_VENDOR_ID 0x00
+#define NVVRS_REG_MODEL_REV 0x01
+
+/* Interrupts registers */
+#define NVVRS_REG_INT_SRC1 0x10
+#define NVVRS_REG_INT_SRC2 0x11
+#define NVVRS_REG_INT_VENDOR 0x12
+
+/* Control Registers */
+#define NVVRS_REG_CTL_1 0x28
+#define NVVRS_REG_CTL_2 0x29
+
+/* RTC Registers */
+#define NVVRS_REG_RTC_T3 0x70
+#define NVVRS_REG_RTC_T2 0x71
+#define NVVRS_REG_RTC_T1 0x72
+#define NVVRS_REG_RTC_T0 0x73
+#define NVVRS_REG_RTC_A3 0x74
+#define NVVRS_REG_RTC_A2 0x75
+#define NVVRS_REG_RTC_A1 0x76
+#define NVVRS_REG_RTC_A0 0x77
+
+/* Interrupt Mask */
+#define NVVRS_INT_SRC1_RSTIRQ_MASK BIT(0)
+#define NVVRS_INT_SRC1_OSC_MASK BIT(1)
+#define NVVRS_INT_SRC1_EN_MASK BIT(2)
+#define NVVRS_INT_SRC1_RTC_MASK BIT(3)
+#define NVVRS_INT_SRC1_PEC_MASK BIT(4)
+#define NVVRS_INT_SRC1_WDT_MASK BIT(5)
+#define NVVRS_INT_SRC1_EM_PD_MASK BIT(6)
+#define NVVRS_INT_SRC1_INTERNAL_MASK BIT(7)
+#define NVVRS_INT_SRC2_PBSP_MASK BIT(0)
+#define NVVRS_INT_SRC2_ECC_DED_MASK BIT(1)
+#define NVVRS_INT_SRC2_TSD_MASK BIT(2)
+#define NVVRS_INT_SRC2_LDO_MASK BIT(3)
+#define NVVRS_INT_SRC2_BIST_MASK BIT(4)
+#define NVVRS_INT_SRC2_RT_CRC_MASK BIT(5)
+#define NVVRS_INT_SRC2_VENDOR_MASK BIT(7)
+#define NVVRS_INT_VENDOR0_MASK BIT(0)
+#define NVVRS_INT_VENDOR1_MASK BIT(1)
+#define NVVRS_INT_VENDOR2_MASK BIT(2)
+#define NVVRS_INT_VENDOR3_MASK BIT(3)
+#define NVVRS_INT_VENDOR4_MASK BIT(4)
+#define NVVRS_INT_VENDOR5_MASK BIT(5)
+#define NVVRS_INT_VENDOR6_MASK BIT(6)
+#define NVVRS_INT_VENDOR7_MASK BIT(7)
+
+/* Controller Register Mask */
+#define NVVRS_REG_CTL_1_FORCE_SHDN (BIT(0) | BIT(1))
+#define NVVRS_REG_CTL_1_FORCE_ACT BIT(2)
+#define NVVRS_REG_CTL_1_FORCE_INT BIT(3)
+#define NVVRS_REG_CTL_2_EN_PEC BIT(0)
+#define NVVRS_REG_CTL_2_REQ_PEC BIT(1)
+#define NVVRS_REG_CTL_2_RTC_PU BIT(2)
+#define NVVRS_REG_CTL_2_RTC_WAKE BIT(3)
+#define NVVRS_REG_CTL_2_RST_DLY 0xF0
+
+#define ALARM_RESET_VAL 0xffffffff
+#define NVVRS_MIN_MODEL_REV 0x40
+
+enum nvvrs_irq_regs {
+ NVVRS_IRQ_REG_INT_SRC1 = 0,
+ NVVRS_IRQ_REG_INT_SRC2 = 1,
+ NVVRS_IRQ_REG_INT_VENDOR = 2,
+ NVVRS_IRQ_REG_COUNT = 3,
+};
+
+struct nvvrs_rtc_info {
+ struct device *dev;
+ struct i2c_client *client;
+ struct rtc_device *rtc;
+ unsigned int irq;
+};
+
+static int nvvrs_update_bits(struct nvvrs_rtc_info *info, u8 reg,
+ u8 mask, u8 value)
+{
+ int ret;
+ u8 val;
+
+ ret = i2c_smbus_read_byte_data(info->client, reg);
+ if (ret < 0)
+ return ret;
+
+ val = (u8)ret;
+ val &= ~mask;
+ val |= (value & mask);
+
+ return i2c_smbus_write_byte_data(info->client, reg, val);
+}
+
+static int nvvrs_rtc_write_alarm(struct i2c_client *client, u8 *time)
+{
+ int ret;
+
+ ret = i2c_smbus_write_byte_data(client, NVVRS_REG_RTC_A3, time[3]);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, NVVRS_REG_RTC_A2, time[2]);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, NVVRS_REG_RTC_A1, time[1]);
+ if (ret < 0)
+ return ret;
+
+ return i2c_smbus_write_byte_data(client, NVVRS_REG_RTC_A0, time[0]);
+}
+
+static int nvvrs_rtc_enable_alarm(struct nvvrs_rtc_info *info)
+{
+ int ret;
+
+ /* Set RTC_WAKE bit for autonomous wake from sleep */
+ ret = nvvrs_update_bits(info, NVVRS_REG_CTL_2, NVVRS_REG_CTL_2_RTC_WAKE,
+ NVVRS_REG_CTL_2_RTC_WAKE);
+ if (ret < 0)
+ return ret;
+
+ /* Set RTC_PU bit for autonomous wake from shutdown */
+ ret = nvvrs_update_bits(info, NVVRS_REG_CTL_2, NVVRS_REG_CTL_2_RTC_PU,
+ NVVRS_REG_CTL_2_RTC_PU);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int nvvrs_rtc_disable_alarm(struct nvvrs_rtc_info *info)
+{
+ struct i2c_client *client = info->client;
+ u8 val[4];
+ int ret;
+
+ /* Clear RTC_WAKE bit */
+ ret = nvvrs_update_bits(info, NVVRS_REG_CTL_2, NVVRS_REG_CTL_2_RTC_WAKE,
+ 0);
+ if (ret < 0)
+ return ret;
+
+ /* Clear RTC_PU bit */
+ ret = nvvrs_update_bits(info, NVVRS_REG_CTL_2, NVVRS_REG_CTL_2_RTC_PU,
+ 0);
+ if (ret < 0)
+ return ret;
+
+ /* Write ALARM_RESET_VAL in RTC Alarm register to disable alarm */
+ val[0] = 0xff;
+ val[1] = 0xff;
+ val[2] = 0xff;
+ val[3] = 0xff;
+
+ ret = nvvrs_rtc_write_alarm(client, val);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int nvvrs_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct nvvrs_rtc_info *info = dev_get_drvdata(dev);
+ time64_t secs = 0;
+ int ret;
+ u8 val;
+
+ /*
+ * Multi-byte transfers are not supported with PEC enabled
+ * Read MSB first to avoid coherency issues
+ */
+ ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_T3);
+ if (ret < 0)
+ return ret;
+
+ val = (u8)ret;
+ secs |= (time64_t)val << 24;
+
+ ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_T2);
+ if (ret < 0)
+ return ret;
+
+ val = (u8)ret;
+ secs |= (time64_t)val << 16;
+
+ ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_T1);
+ if (ret < 0)
+ return ret;
+
+ val = (u8)ret;
+ secs |= (time64_t)val << 8;
+
+ ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_T0);
+ if (ret < 0)
+ return ret;
+
+ val = (u8)ret;
+ secs |= val;
+
+ rtc_time64_to_tm(secs, tm);
+
+ return 0;
+}
+
+static int nvvrs_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct nvvrs_rtc_info *info = dev_get_drvdata(dev);
+ time64_t secs;
+ u8 time[4];
+ int ret;
+
+ secs = rtc_tm_to_time64(tm);
+ time[0] = secs & 0xff;
+ time[1] = (secs >> 8) & 0xff;
+ time[2] = (secs >> 16) & 0xff;
+ time[3] = (secs >> 24) & 0xff;
+
+ ret = i2c_smbus_write_byte_data(info->client, NVVRS_REG_RTC_T3, time[3]);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(info->client, NVVRS_REG_RTC_T2, time[2]);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(info->client, NVVRS_REG_RTC_T1, time[1]);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(info->client, NVVRS_REG_RTC_T0, time[0]);
+
+ return ret;
+}
+
+static int nvvrs_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct nvvrs_rtc_info *info = dev_get_drvdata(dev);
+ time64_t alarm_val = 0;
+ int ret;
+ u8 val;
+
+ /* Multi-byte transfers are not supported with PEC enabled */
+ ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_A3);
+ if (ret < 0)
+ return ret;
+
+ val = (u8)ret;
+ alarm_val |= (time64_t)val << 24;
+
+ ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_A2);
+ if (ret < 0)
+ return ret;
+
+ val = (u8)ret;
+ alarm_val |= (time64_t)val << 16;
+
+ ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_A1);
+ if (ret < 0)
+ return ret;
+
+ val = (u8)ret;
+ alarm_val |= (time64_t)val << 8;
+
+ ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_A0);
+ if (ret < 0)
+ return ret;
+
+ val = (u8)ret;
+ alarm_val |= val;
+
+ if (alarm_val == ALARM_RESET_VAL)
+ alrm->enabled = 0;
+ else
+ alrm->enabled = 1;
+
+ rtc_time64_to_tm(alarm_val, &alrm->time);
+
+ return 0;
+}
+
+static int nvvrs_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct nvvrs_rtc_info *info = dev_get_drvdata(dev);
+ time64_t secs;
+ u8 time[4];
+ int ret;
+
+ if (!alrm->enabled) {
+ ret = nvvrs_rtc_disable_alarm(info);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = nvvrs_rtc_enable_alarm(info);
+ if (ret < 0)
+ return ret;
+
+ secs = rtc_tm_to_time64(&alrm->time);
+ time[0] = secs & 0xff;
+ time[1] = (secs >> 8) & 0xff;
+ time[2] = (secs >> 16) & 0xff;
+ time[3] = (secs >> 24) & 0xff;
+
+ ret = nvvrs_rtc_write_alarm(info->client, time);
+
+ return ret;
+}
+
+static int nvvrs_pseq_irq_clear(struct nvvrs_rtc_info *info)
+{
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < NVVRS_IRQ_REG_COUNT; i++) {
+ ret = i2c_smbus_read_byte_data(info->client,
+ NVVRS_REG_INT_SRC1 + i);
+ if (ret < 0) {
+ dev_err(info->dev, "Failed to read INT_SRC%d : %d\n",
+ i + 1, ret);
+ return ret;
+ }
+
+ ret = i2c_smbus_write_byte_data(info->client,
+ NVVRS_REG_INT_SRC1 + i,
+ (u8)ret);
+ if (ret < 0) {
+ dev_err(info->dev, "Failed to clear INT_SRC%d : %d\n",
+ i + 1, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static irqreturn_t nvvrs_rtc_irq_handler(int irq, void *data)
+{
+ struct nvvrs_rtc_info *info = data;
+ int ret;
+
+ /* Check for RTC alarm interrupt */
+ ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_INT_SRC1);
+ if (ret < 0)
+ return IRQ_NONE;
+
+ if (ret & NVVRS_INT_SRC1_RTC_MASK) {
+ rtc_lock(info->rtc);
+ rtc_update_irq(info->rtc, 1, RTC_IRQF | RTC_AF);
+ rtc_unlock(info->rtc);
+ }
+
+ /* Clear all interrupts */
+ if (nvvrs_pseq_irq_clear(info) < 0)
+ return IRQ_NONE;
+
+ return IRQ_HANDLED;
+}
+
+static int nvvrs_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ /*
+ * This hardware does not support enabling/disabling the alarm IRQ
+ * independently. The alarm is disabled by clearing the alarm time
+ * via set_alarm().
+ */
+ return 0;
+}
+
+static const struct rtc_class_ops nvvrs_rtc_ops = {
+ .read_time = nvvrs_rtc_read_time,
+ .set_time = nvvrs_rtc_set_time,
+ .read_alarm = nvvrs_rtc_read_alarm,
+ .set_alarm = nvvrs_rtc_set_alarm,
+ .alarm_irq_enable = nvvrs_rtc_alarm_irq_enable,
+};
+
+static int nvvrs_pseq_vendor_info(struct nvvrs_rtc_info *info)
+{
+ struct i2c_client *client = info->client;
+ u8 vendor_id, model_rev;
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(client, NVVRS_REG_VENDOR_ID);
+ if (ret < 0)
+ return dev_err_probe(&client->dev, ret,
+ "Failed to read Vendor ID\n");
+
+ vendor_id = (u8)ret;
+
+ ret = i2c_smbus_read_byte_data(client, NVVRS_REG_MODEL_REV);
+ if (ret < 0)
+ return dev_err_probe(&client->dev, ret,
+ "Failed to read Model Revision\n");
+
+ model_rev = (u8)ret;
+
+ if (model_rev < NVVRS_MIN_MODEL_REV) {
+ return dev_err_probe(&client->dev, -ENODEV,
+ "Chip revision 0x%02x is not supported!\n",
+ model_rev);
+ }
+
+ dev_dbg(&client->dev, "NVVRS Vendor ID: 0x%02x, Model Rev: 0x%02x\n",
+ vendor_id, model_rev);
+
+ return 0;
+}
+
+static int nvvrs_rtc_probe(struct i2c_client *client)
+{
+ struct nvvrs_rtc_info *info;
+ int ret;
+
+ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ if (client->irq <= 0)
+ return dev_err_probe(&client->dev, -EINVAL, "No IRQ specified\n");
+
+ info->irq = client->irq;
+ info->dev = &client->dev;
+ client->flags |= I2C_CLIENT_PEC;
+ i2c_set_clientdata(client, info);
+ info->client = client;
+
+ /* Check vendor info */
+ if (nvvrs_pseq_vendor_info(info) < 0)
+ return dev_err_probe(&client->dev, -EINVAL,
+ "Failed to get vendor info\n");
+
+ /* Clear any pending IRQs before requesting IRQ handler */
+ if (nvvrs_pseq_irq_clear(info) < 0)
+ return dev_err_probe(&client->dev, -EINVAL,
+ "Failed to clear interrupts\n");
+
+ /* Allocate RTC device */
+ info->rtc = devm_rtc_allocate_device(info->dev);
+ if (IS_ERR(info->rtc))
+ return PTR_ERR(info->rtc);
+
+ info->rtc->ops = &nvvrs_rtc_ops;
+ info->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
+ info->rtc->range_max = RTC_TIMESTAMP_END_2099;
+
+ /* Request RTC IRQ */
+ ret = devm_request_threaded_irq(info->dev, info->irq, NULL,
+ nvvrs_rtc_irq_handler, IRQF_ONESHOT,
+ "nvvrs-rtc", info);
+ if (ret < 0) {
+ dev_err_probe(info->dev, ret, "Failed to request RTC IRQ\n");
+ return ret;
+ }
+
+ /* RTC as a wakeup source */
+ devm_device_init_wakeup(info->dev);
+
+ return devm_rtc_register_device(info->rtc);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int nvvrs_rtc_suspend(struct device *dev)
+{
+ struct nvvrs_rtc_info *info = dev_get_drvdata(dev);
+ int ret;
+
+ if (device_may_wakeup(dev)) {
+ /* Set RTC_WAKE bit for auto wake system from suspend state */
+ ret = nvvrs_update_bits(info, NVVRS_REG_CTL_2,
+ NVVRS_REG_CTL_2_RTC_WAKE,
+ NVVRS_REG_CTL_2_RTC_WAKE);
+ if (ret < 0) {
+ dev_err(info->dev, "Failed to set RTC_WAKE bit (%d)\n",
+ ret);
+ return ret;
+ }
+
+ return enable_irq_wake(info->irq);
+ }
+
+ return 0;
+}
+
+static int nvvrs_rtc_resume(struct device *dev)
+{
+ struct nvvrs_rtc_info *info = dev_get_drvdata(dev);
+ int ret;
+
+ if (device_may_wakeup(dev)) {
+ /* Clear FORCE_ACT bit */
+ ret = nvvrs_update_bits(info, NVVRS_REG_CTL_1,
+ NVVRS_REG_CTL_1_FORCE_ACT, 0);
+ if (ret < 0) {
+ dev_err(info->dev, "Failed to clear FORCE_ACT bit (%d)\n",
+ ret);
+ return ret;
+ }
+
+ return disable_irq_wake(info->irq);
+ }
+
+ return 0;
+}
+
+#endif
+static SIMPLE_DEV_PM_OPS(nvvrs_rtc_pm_ops, nvvrs_rtc_suspend, nvvrs_rtc_resume);
+
+static const struct of_device_id nvvrs_rtc_of_match[] = {
+ { .compatible = "nvidia,vrs-10" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, nvvrs_rtc_of_match);
+
+static struct i2c_driver nvvrs_rtc_driver = {
+ .driver = {
+ .name = "rtc-nvidia-vrs10",
+ .pm = &nvvrs_rtc_pm_ops,
+ .of_match_table = nvvrs_rtc_of_match,
+ },
+ .probe = nvvrs_rtc_probe,
+};
+
+module_i2c_driver(nvvrs_rtc_driver);
+
+MODULE_AUTHOR("Shubhi Garg <shgarg@nvidia.com>");
+MODULE_DESCRIPTION("NVIDIA Voltage Regulator Specification RTC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-pic32.c b/drivers/rtc/rtc-pic32.c
index 2812da2c50c5..52c11532bc3a 100644
--- a/drivers/rtc/rtc-pic32.c
+++ b/drivers/rtc/rtc-pic32.c
@@ -340,8 +340,6 @@ static int pic32_rtc_probe(struct platform_device *pdev)
if (ret)
goto err_nortc;
- pdata->rtc->max_user_freq = 128;
-
pic32_rtc_setfreq(&pdev->dev, 1);
ret = devm_request_irq(&pdev->dev, pdata->alarm_irq,
pic32_rtc_alarmirq, 0,
diff --git a/drivers/rtc/rtc-renesas-rtca3.c b/drivers/rtc/rtc-renesas-rtca3.c
index ab816bdf0d77..cbabaa4dc96a 100644
--- a/drivers/rtc/rtc-renesas-rtca3.c
+++ b/drivers/rtc/rtc-renesas-rtca3.c
@@ -726,7 +726,7 @@ static int rtca3_probe(struct platform_device *pdev)
if (ret)
return ret;
- priv->rstc = devm_reset_control_get_shared(dev, NULL);
+ priv->rstc = devm_reset_control_array_get_shared(dev);
if (IS_ERR(priv->rstc))
return PTR_ERR(priv->rstc);
@@ -772,7 +772,6 @@ static int rtca3_probe(struct platform_device *pdev)
return PTR_ERR(priv->rtc_dev);
priv->rtc_dev->ops = &rtca3_ops;
- priv->rtc_dev->max_user_freq = 256;
priv->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_2000;
priv->rtc_dev->range_max = RTC_TIMESTAMP_END_2099;
diff --git a/drivers/rtc/rtc-rv3028.c b/drivers/rtc/rtc-rv3028.c
index c2a531f0e125..d96f6bb68850 100644
--- a/drivers/rtc/rtc-rv3028.c
+++ b/drivers/rtc/rtc-rv3028.c
@@ -1023,8 +1023,6 @@ static int rv3028_probe(struct i2c_client *client)
eeprom_cfg.priv = rv3028;
devm_rtc_nvmem_register(rv3028->rtc, &eeprom_cfg);
- rv3028->rtc->max_user_freq = 1;
-
#ifdef CONFIG_COMMON_CLK
rv3028_clkout_register_clk(rv3028, client);
#endif
diff --git a/drivers/rtc/rtc-rv3032.c b/drivers/rtc/rtc-rv3032.c
index b8376bd1d905..6c09da7738e1 100644
--- a/drivers/rtc/rtc-rv3032.c
+++ b/drivers/rtc/rtc-rv3032.c
@@ -968,8 +968,6 @@ static int rv3032_probe(struct i2c_client *client)
eeprom_cfg.priv = rv3032;
devm_rtc_nvmem_register(rv3032->rtc, &eeprom_cfg);
- rv3032->rtc->max_user_freq = 1;
-
#ifdef CONFIG_COMMON_CLK
rv3032_clkout_register_clk(rv3032, client);
#endif
diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c
index 1327251e527c..4e9e04cbec89 100644
--- a/drivers/rtc/rtc-rv8803.c
+++ b/drivers/rtc/rtc-rv8803.c
@@ -738,8 +738,6 @@ static int rv8803_probe(struct i2c_client *client)
devm_rtc_nvmem_register(rv8803->rtc, &nvmem_cfg);
- rv8803->rtc->max_user_freq = 1;
-
return 0;
}
diff --git a/drivers/rtc/rtc-rx6110.c b/drivers/rtc/rtc-rx6110.c
index 7c423d672adb..07bf35ac8d79 100644
--- a/drivers/rtc/rtc-rx6110.c
+++ b/drivers/rtc/rtc-rx6110.c
@@ -324,8 +324,6 @@ static int rx6110_probe(struct rx6110_data *rx6110, struct device *dev)
if (err)
return err;
- rx6110->rtc->max_user_freq = 1;
-
return 0;
}
diff --git a/drivers/rtc/rtc-rx8010.c b/drivers/rtc/rtc-rx8010.c
index 2b6198d1cf81..171240e50f48 100644
--- a/drivers/rtc/rtc-rx8010.c
+++ b/drivers/rtc/rtc-rx8010.c
@@ -412,7 +412,6 @@ static int rx8010_probe(struct i2c_client *client)
}
rx8010->rtc->ops = &rx8010_rtc_ops;
- rx8010->rtc->max_user_freq = 1;
rx8010->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
rx8010->rtc->range_max = RTC_TIMESTAMP_END_2099;
diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c
index 7e9f7cb90c28..ced6e7adfe8d 100644
--- a/drivers/rtc/rtc-rx8025.c
+++ b/drivers/rtc/rtc-rx8025.c
@@ -565,8 +565,6 @@ static int rx8025_probe(struct i2c_client *client)
clear_bit(RTC_FEATURE_ALARM, rx8025->rtc->features);
}
- rx8025->rtc->max_user_freq = 1;
-
set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rx8025->rtc->features);
clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rx8025->rtc->features);
diff --git a/drivers/rtc/rtc-s35390a.c b/drivers/rtc/rtc-s35390a.c
index 3408d2ab2741..07bd983b5692 100644
--- a/drivers/rtc/rtc-s35390a.c
+++ b/drivers/rtc/rtc-s35390a.c
@@ -66,7 +66,7 @@ struct s35390a {
int twentyfourhour;
};
-static int s35390a_set_reg(struct s35390a *s35390a, int reg, char *buf, int len)
+static int s35390a_set_reg(struct s35390a *s35390a, int reg, u8 *buf, int len)
{
struct i2c_client *client = s35390a->client[reg];
struct i2c_msg msg[] = {
@@ -83,7 +83,7 @@ static int s35390a_set_reg(struct s35390a *s35390a, int reg, char *buf, int len)
return 0;
}
-static int s35390a_get_reg(struct s35390a *s35390a, int reg, char *buf, int len)
+static int s35390a_get_reg(struct s35390a *s35390a, int reg, u8 *buf, int len)
{
struct i2c_client *client = s35390a->client[reg];
struct i2c_msg msg[] = {
@@ -168,7 +168,7 @@ static int s35390a_read_status(struct s35390a *s35390a, char *status1)
static int s35390a_disable_test_mode(struct s35390a *s35390a)
{
- char buf[1];
+ u8 buf[1];
if (s35390a_get_reg(s35390a, S35390A_CMD_STATUS2, buf, sizeof(buf)) < 0)
return -EIO;
@@ -210,7 +210,7 @@ static int s35390a_rtc_set_time(struct device *dev, struct rtc_time *tm)
struct i2c_client *client = to_i2c_client(dev);
struct s35390a *s35390a = i2c_get_clientdata(client);
int i;
- char buf[7], status;
+ u8 buf[7], status;
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d mday=%d, "
"mon=%d, year=%d, wday=%d\n", __func__, tm->tm_sec,
@@ -239,7 +239,7 @@ static int s35390a_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct i2c_client *client = to_i2c_client(dev);
struct s35390a *s35390a = i2c_get_clientdata(client);
- char buf[7], status;
+ u8 buf[7], status;
int i, err;
if (s35390a_read_status(s35390a, &status) == 1)
@@ -273,7 +273,7 @@ static int s35390a_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
{
struct i2c_client *client = to_i2c_client(dev);
struct s35390a *s35390a = i2c_get_clientdata(client);
- char buf[3], sts = 0;
+ u8 buf[3], sts = 0;
int err, i;
dev_dbg(&client->dev, "%s: alm is secs=%d, mins=%d, hours=%d mday=%d, "\
@@ -326,7 +326,7 @@ static int s35390a_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
{
struct i2c_client *client = to_i2c_client(dev);
struct s35390a *s35390a = i2c_get_clientdata(client);
- char buf[3], sts;
+ u8 buf[3], sts;
int i, err;
err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts));
@@ -383,7 +383,7 @@ static int s35390a_rtc_ioctl(struct device *dev, unsigned int cmd,
{
struct i2c_client *client = to_i2c_client(dev);
struct s35390a *s35390a = i2c_get_clientdata(client);
- char sts;
+ u8 sts;
int err;
switch (cmd) {
@@ -422,7 +422,7 @@ static int s35390a_probe(struct i2c_client *client)
unsigned int i;
struct s35390a *s35390a;
struct rtc_device *rtc;
- char buf, status1;
+ u8 buf, status1;
struct device *dev = &client->dev;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c
index 1ad93648d69c..26b2f4184ecc 100644
--- a/drivers/rtc/rtc-sa1100.c
+++ b/drivers/rtc/rtc-sa1100.c
@@ -40,8 +40,6 @@
#define RTC_DEF_DIVIDER (32768 - 1)
#define RTC_DEF_TRIM 0
-#define RTC_FREQ 1024
-
static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id)
{
@@ -202,7 +200,6 @@ int sa1100_rtc_init(struct platform_device *pdev, struct sa1100_rtc *info)
}
info->rtc->ops = &sa1100_rtc_ops;
- info->rtc->max_user_freq = RTC_FREQ;
info->rtc->range_max = U32_MAX;
ret = devm_rtc_register_device(info->rtc);
diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c
index 619800a00479..0510dc64c3e2 100644
--- a/drivers/rtc/rtc-sh.c
+++ b/drivers/rtc/rtc-sh.c
@@ -423,7 +423,6 @@ static int __init sh_rtc_probe(struct platform_device *pdev)
writeb(tmp, rtc->regbase + RCR1);
rtc->rtc_dev->ops = &sh_rtc_ops;
- rtc->rtc_dev->max_user_freq = 256;
if (rtc->capabilities & RTC_CAP_4_DIGIT_YEAR) {
rtc->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_1900;
diff --git a/drivers/rtc/rtc-tegra.c b/drivers/rtc/rtc-tegra.c
index 46788db89953..528e32b7d101 100644
--- a/drivers/rtc/rtc-tegra.c
+++ b/drivers/rtc/rtc-tegra.c
@@ -274,6 +274,12 @@ static const struct of_device_id tegra_rtc_dt_match[] = {
};
MODULE_DEVICE_TABLE(of, tegra_rtc_dt_match);
+static const struct acpi_device_id tegra_rtc_acpi_match[] = {
+ { "NVDA0280" },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, tegra_rtc_acpi_match);
+
static int tegra_rtc_probe(struct platform_device *pdev)
{
struct tegra_rtc_info *info;
@@ -300,13 +306,11 @@ static int tegra_rtc_probe(struct platform_device *pdev)
info->rtc->ops = &tegra_rtc_ops;
info->rtc->range_max = U32_MAX;
- info->clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(info->clk))
- return PTR_ERR(info->clk);
-
- ret = clk_prepare_enable(info->clk);
- if (ret < 0)
- return ret;
+ if (dev_of_node(&pdev->dev)) {
+ info->clk = devm_clk_get_enabled(&pdev->dev, NULL);
+ if (IS_ERR(info->clk))
+ return PTR_ERR(info->clk);
+ }
/* set context info */
info->pdev = pdev;
@@ -324,32 +328,18 @@ static int tegra_rtc_probe(struct platform_device *pdev)
ret = devm_request_irq(&pdev->dev, info->irq, tegra_rtc_irq_handler,
IRQF_TRIGGER_HIGH, dev_name(&pdev->dev),
&pdev->dev);
- if (ret) {
- dev_err(&pdev->dev, "failed to request interrupt: %d\n", ret);
- goto disable_clk;
- }
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "failed to request interrupt\n");
ret = devm_rtc_register_device(info->rtc);
if (ret)
- goto disable_clk;
+ return ret;
dev_notice(&pdev->dev, "Tegra internal Real Time Clock\n");
return 0;
-
-disable_clk:
- clk_disable_unprepare(info->clk);
- return ret;
-}
-
-static void tegra_rtc_remove(struct platform_device *pdev)
-{
- struct tegra_rtc_info *info = platform_get_drvdata(pdev);
-
- clk_disable_unprepare(info->clk);
}
-#ifdef CONFIG_PM_SLEEP
static int tegra_rtc_suspend(struct device *dev)
{
struct tegra_rtc_info *info = dev_get_drvdata(dev);
@@ -387,9 +377,8 @@ static int tegra_rtc_resume(struct device *dev)
return 0;
}
-#endif
-static SIMPLE_DEV_PM_OPS(tegra_rtc_pm_ops, tegra_rtc_suspend, tegra_rtc_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(tegra_rtc_pm_ops, tegra_rtc_suspend, tegra_rtc_resume);
static void tegra_rtc_shutdown(struct platform_device *pdev)
{
@@ -399,12 +388,12 @@ static void tegra_rtc_shutdown(struct platform_device *pdev)
static struct platform_driver tegra_rtc_driver = {
.probe = tegra_rtc_probe,
- .remove = tegra_rtc_remove,
.shutdown = tegra_rtc_shutdown,
.driver = {
.name = "tegra_rtc",
.of_match_table = tegra_rtc_dt_match,
- .pm = &tegra_rtc_pm_ops,
+ .acpi_match_table = tegra_rtc_acpi_match,
+ .pm = pm_sleep_ptr(&tegra_rtc_pm_ops),
},
};
module_platform_driver(tegra_rtc_driver);
diff --git a/drivers/s390/char/sclp_mem.c b/drivers/s390/char/sclp_mem.c
index 676c085b4f8a..27f0d2f12a8b 100644
--- a/drivers/s390/char/sclp_mem.c
+++ b/drivers/s390/char/sclp_mem.c
@@ -44,6 +44,9 @@ struct sclp_mem {
unsigned int id;
unsigned int memmap_on_memory;
unsigned int config;
+#ifdef CONFIG_KASAN
+ unsigned int early_shadow_mapped;
+#endif
};
struct sclp_mem_arg {
@@ -244,6 +247,16 @@ static ssize_t sclp_config_mem_store(struct kobject *kobj, struct kobj_attribute
put_device(&mem->dev);
sclp_mem_change_state(addr, block_size, 0);
__remove_memory(addr, block_size);
+#ifdef CONFIG_KASAN
+ if (sclp_mem->early_shadow_mapped) {
+ unsigned long start, end;
+
+ start = (unsigned long)kasan_mem_to_shadow(__va(addr));
+ end = start + (block_size >> KASAN_SHADOW_SCALE_SHIFT);
+ vmemmap_free(start, end, NULL);
+ sclp_mem->early_shadow_mapped = 0;
+ }
+#endif
WRITE_ONCE(sclp_mem->config, 0);
}
out_unlock:
@@ -316,6 +329,9 @@ static int sclp_create_mem(struct sclp_mem *sclp_mem, struct kset *kset,
sclp_mem->memmap_on_memory = memmap_on_memory;
sclp_mem->config = config;
+#ifdef CONFIG_KASAN
+ sclp_mem->early_shadow_mapped = config;
+#endif
sclp_mem->id = id;
kobject_init(&sclp_mem->kobj, &ktype);
rc = kobject_add(&sclp_mem->kobj, &kset->kobj, "memory%d", id);
diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c
index e3e0e9f36527..a226ff208eda 100644
--- a/drivers/s390/char/vmur.c
+++ b/drivers/s390/char/vmur.c
@@ -154,7 +154,7 @@ static struct urdev *urdev_get_from_devno(u16 devno)
struct ccw_device *cdev;
struct urdev *urd;
- sprintf(bus_id, "0.0.%04x", devno);
+ scnprintf(bus_id, sizeof(bus_id), "0.0.%04x", devno);
cdev = get_ccwdev_by_busid(&ur_driver, bus_id);
if (!cdev)
return NULL;
@@ -904,11 +904,11 @@ static int ur_set_online(struct ccw_device *cdev)
goto fail_free_cdev;
if (urd->cdev->id.cu_type == READER_PUNCH_DEVTYPE) {
if (urd->class == DEV_CLASS_UR_I)
- sprintf(node_id, "vmrdr-%s", dev_name(&cdev->dev));
+ scnprintf(node_id, sizeof(node_id), "vmrdr-%s", dev_name(&cdev->dev));
if (urd->class == DEV_CLASS_UR_O)
- sprintf(node_id, "vmpun-%s", dev_name(&cdev->dev));
+ scnprintf(node_id, sizeof(node_id), "vmpun-%s", dev_name(&cdev->dev));
} else if (urd->cdev->id.cu_type == PRINTER_DEVTYPE) {
- sprintf(node_id, "vmprt-%s", dev_name(&cdev->dev));
+ scnprintf(node_id, sizeof(node_id), "vmprt-%s", dev_name(&cdev->dev));
} else {
rc = -EOPNOTSUPP;
goto fail_free_cdev;
diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
index 55c1db816534..fb68738dfb9b 100644
--- a/drivers/soundwire/bus.c
+++ b/drivers/soundwire/bus.c
@@ -2052,8 +2052,14 @@ EXPORT_SYMBOL(sdw_clear_slave_status);
int sdw_bpt_send_async(struct sdw_bus *bus, struct sdw_slave *slave, struct sdw_bpt_msg *msg)
{
- if (msg->len > SDW_BPT_MSG_MAX_BYTES) {
- dev_err(bus->dev, "Invalid BPT message length %d\n", msg->len);
+ int len = 0;
+ int i;
+
+ for (i = 0; i < msg->sections; i++)
+ len += msg->sec[i].len;
+
+ if (len > SDW_BPT_MSG_MAX_BYTES) {
+ dev_err(bus->dev, "Invalid BPT message length %d\n", len);
return -EINVAL;
}
diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h
index 02651fbb683a..8115c64dd48e 100644
--- a/drivers/soundwire/bus.h
+++ b/drivers/soundwire/bus.h
@@ -73,21 +73,31 @@ struct sdw_msg {
};
/**
- * struct sdw_btp_msg - Message structure
+ * struct sdw_btp_section - Message section structure
* @addr: Start Register address accessed in the Slave
* @len: number of bytes to transfer. More than 64Kb can be transferred
* but a practical limit of SDW_BPT_MSG_MAX_BYTES is enforced.
- * @dev_num: Slave device number
- * @flags: transfer flags, indicate if xfer is read or write
- * @buf: message data buffer (filled by host for write, filled
+ * @buf: section data buffer (filled by host for write, filled
* by Peripheral hardware for reads)
*/
-struct sdw_bpt_msg {
+struct sdw_bpt_section {
u32 addr;
u32 len;
+ u8 *buf;
+};
+
+/**
+ * struct sdw_btp_msg - Message structure
+ * @sec: Pointer to array of sections
+ * @sections: Number of sections in the array
+ * @dev_num: Slave device number
+ * @flags: transfer flags, indicate if xfer is read or write
+ */
+struct sdw_bpt_msg {
+ struct sdw_bpt_section *sec;
+ int sections;
u8 dev_num;
u8 flags;
- u8 *buf;
};
#define SDW_DOUBLE_RATE_FACTOR 2
diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
index 21bb491d026b..a106e5e482c8 100644
--- a/drivers/soundwire/cadence_master.c
+++ b/drivers/soundwire/cadence_master.c
@@ -2094,6 +2094,36 @@ static unsigned int sdw_cdns_read_pdi1_buffer_size(unsigned int actual_data_size
return total * 2;
}
+int sdw_cdns_bpt_find_bandwidth(int command, /* 0: write, 1: read */
+ int row, int col, int frame_rate,
+ unsigned int *tx_dma_bandwidth,
+ unsigned int *rx_dma_bandwidth)
+{
+ unsigned int bpt_bits = row * (col - 1);
+ unsigned int bpt_bytes = bpt_bits >> 3;
+ unsigned int pdi0_buffer_size;
+ unsigned int pdi1_buffer_size;
+ unsigned int data_per_frame;
+
+ data_per_frame = sdw_cdns_bra_actual_data_size(bpt_bytes);
+ if (!data_per_frame)
+ return -EINVAL;
+
+ if (command == 0) {
+ pdi0_buffer_size = sdw_cdns_write_pdi0_buffer_size(data_per_frame);
+ pdi1_buffer_size = SDW_CDNS_WRITE_PDI1_BUFFER_SIZE;
+ } else {
+ pdi0_buffer_size = SDW_CDNS_READ_PDI0_BUFFER_SIZE;
+ pdi1_buffer_size = sdw_cdns_read_pdi1_buffer_size(data_per_frame);
+ }
+
+ *tx_dma_bandwidth = pdi0_buffer_size * 8 * frame_rate;
+ *rx_dma_bandwidth = pdi1_buffer_size * 8 * frame_rate;
+
+ return 0;
+}
+EXPORT_SYMBOL(sdw_cdns_bpt_find_bandwidth);
+
int sdw_cdns_bpt_find_buffer_sizes(int command, /* 0: write, 1: read */
int row, int col, unsigned int data_bytes,
unsigned int requested_bytes_per_frame,
@@ -2114,9 +2144,6 @@ int sdw_cdns_bpt_find_buffer_sizes(int command, /* 0: write, 1: read */
if (!actual_bpt_bytes)
return -EINVAL;
- if (data_bytes < actual_bpt_bytes)
- actual_bpt_bytes = data_bytes;
-
/*
* the caller may want to set the number of bytes per frame,
* allow when possible
@@ -2126,6 +2153,9 @@ int sdw_cdns_bpt_find_buffer_sizes(int command, /* 0: write, 1: read */
*data_per_frame = actual_bpt_bytes;
+ if (data_bytes < actual_bpt_bytes)
+ actual_bpt_bytes = data_bytes;
+
if (command == 0) {
/*
* for writes we need to send all the data_bytes per frame,
@@ -2294,17 +2324,20 @@ static int sdw_cdns_prepare_read_pd0_buffer(u8 *header, unsigned int header_size
#define CDNS_BPT_ROLLING_COUNTER_START 1
-int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, u32 start_register, u8 *data, int data_size,
- int data_per_frame, u8 *dma_buffer, int dma_buffer_size,
- int *dma_buffer_total_bytes)
+int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, struct sdw_bpt_section *sec, int num_sec,
+ int data_per_frame, u8 *dma_buffer,
+ int dma_buffer_size, int *dma_buffer_total_bytes)
{
int total_dma_data_written = 0;
u8 *p_dma_buffer = dma_buffer;
u8 header[SDW_CDNS_BRA_HDR];
+ unsigned int start_register;
+ unsigned int section_size;
int dma_data_written;
- u8 *p_data = data;
+ u8 *p_data;
u8 counter;
int ret;
+ int i;
counter = CDNS_BPT_ROLLING_COUNTER_START;
@@ -2312,47 +2345,57 @@ int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, u32 start_register, u8 *data,
header[0] |= GENMASK(7, 6); /* header is active */
header[0] |= (dev_num << 2);
- while (data_size >= data_per_frame) {
- header[1] = data_per_frame;
- header[2] = start_register >> 24 & 0xFF;
- header[3] = start_register >> 16 & 0xFF;
- header[4] = start_register >> 8 & 0xFF;
- header[5] = start_register >> 0 & 0xFF;
-
- ret = sdw_cdns_prepare_write_pd0_buffer(header, SDW_CDNS_BRA_HDR,
- p_data, data_per_frame,
- p_dma_buffer, dma_buffer_size,
- &dma_data_written, counter);
- if (ret < 0)
- return ret;
+ for (i = 0; i < num_sec; i++) {
+ start_register = sec[i].addr;
+ section_size = sec[i].len;
+ p_data = sec[i].buf;
- counter++;
+ while (section_size >= data_per_frame) {
+ header[1] = data_per_frame;
+ header[2] = start_register >> 24 & 0xFF;
+ header[3] = start_register >> 16 & 0xFF;
+ header[4] = start_register >> 8 & 0xFF;
+ header[5] = start_register >> 0 & 0xFF;
- p_data += data_per_frame;
- data_size -= data_per_frame;
+ ret = sdw_cdns_prepare_write_pd0_buffer(header, SDW_CDNS_BRA_HDR,
+ p_data, data_per_frame,
+ p_dma_buffer, dma_buffer_size,
+ &dma_data_written, counter);
+ if (ret < 0)
+ return ret;
- p_dma_buffer += dma_data_written;
- dma_buffer_size -= dma_data_written;
- total_dma_data_written += dma_data_written;
+ counter++;
- start_register += data_per_frame;
- }
+ p_data += data_per_frame;
+ section_size -= data_per_frame;
- if (data_size) {
- header[1] = data_size;
- header[2] = start_register >> 24 & 0xFF;
- header[3] = start_register >> 16 & 0xFF;
- header[4] = start_register >> 8 & 0xFF;
- header[5] = start_register >> 0 & 0xFF;
+ p_dma_buffer += dma_data_written;
+ dma_buffer_size -= dma_data_written;
+ total_dma_data_written += dma_data_written;
- ret = sdw_cdns_prepare_write_pd0_buffer(header, SDW_CDNS_BRA_HDR,
- p_data, data_size,
- p_dma_buffer, dma_buffer_size,
- &dma_data_written, counter);
- if (ret < 0)
- return ret;
+ start_register += data_per_frame;
+ }
- total_dma_data_written += dma_data_written;
+ if (section_size) {
+ header[1] = section_size;
+ header[2] = start_register >> 24 & 0xFF;
+ header[3] = start_register >> 16 & 0xFF;
+ header[4] = start_register >> 8 & 0xFF;
+ header[5] = start_register >> 0 & 0xFF;
+
+ ret = sdw_cdns_prepare_write_pd0_buffer(header, SDW_CDNS_BRA_HDR,
+ p_data, section_size,
+ p_dma_buffer, dma_buffer_size,
+ &dma_data_written, counter);
+ if (ret < 0)
+ return ret;
+
+ counter++;
+
+ p_dma_buffer += dma_data_written;
+ dma_buffer_size -= dma_data_written;
+ total_dma_data_written += dma_data_written;
+ }
}
*dma_buffer_total_bytes = total_dma_data_written;
@@ -2361,16 +2404,19 @@ int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, u32 start_register, u8 *data,
}
EXPORT_SYMBOL(sdw_cdns_prepare_write_dma_buffer);
-int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, u32 start_register, int data_size,
+int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, struct sdw_bpt_section *sec, int num_sec,
int data_per_frame, u8 *dma_buffer, int dma_buffer_size,
- int *dma_buffer_total_bytes)
+ int *dma_buffer_total_bytes, unsigned int fake_size)
{
int total_dma_data_written = 0;
u8 *p_dma_buffer = dma_buffer;
u8 header[SDW_CDNS_BRA_HDR];
+ unsigned int start_register;
+ unsigned int data_size;
int dma_data_written;
u8 counter;
int ret;
+ int i;
counter = CDNS_BPT_ROLLING_COUNTER_START;
@@ -2378,13 +2424,58 @@ int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, u32 start_register, int data_si
header[0] |= GENMASK(7, 6); /* header is active */
header[0] |= (dev_num << 2);
- while (data_size >= data_per_frame) {
- header[1] = data_per_frame;
- header[2] = start_register >> 24 & 0xFF;
- header[3] = start_register >> 16 & 0xFF;
- header[4] = start_register >> 8 & 0xFF;
- header[5] = start_register >> 0 & 0xFF;
+ for (i = 0; i < num_sec; i++) {
+ start_register = sec[i].addr;
+ data_size = sec[i].len;
+ while (data_size >= data_per_frame) {
+ header[1] = data_per_frame;
+ header[2] = start_register >> 24 & 0xFF;
+ header[3] = start_register >> 16 & 0xFF;
+ header[4] = start_register >> 8 & 0xFF;
+ header[5] = start_register >> 0 & 0xFF;
+
+ ret = sdw_cdns_prepare_read_pd0_buffer(header, SDW_CDNS_BRA_HDR,
+ p_dma_buffer, dma_buffer_size,
+ &dma_data_written, counter);
+ if (ret < 0)
+ return ret;
+
+ counter++;
+
+ data_size -= data_per_frame;
+
+ p_dma_buffer += dma_data_written;
+ dma_buffer_size -= dma_data_written;
+ total_dma_data_written += dma_data_written;
+
+ start_register += data_per_frame;
+ }
+
+ if (data_size) {
+ header[1] = data_size;
+ header[2] = start_register >> 24 & 0xFF;
+ header[3] = start_register >> 16 & 0xFF;
+ header[4] = start_register >> 8 & 0xFF;
+ header[5] = start_register >> 0 & 0xFF;
+
+ ret = sdw_cdns_prepare_read_pd0_buffer(header, SDW_CDNS_BRA_HDR,
+ p_dma_buffer, dma_buffer_size,
+ &dma_data_written, counter);
+ if (ret < 0)
+ return ret;
+
+ counter++;
+ p_dma_buffer += dma_data_written;
+ dma_buffer_size -= dma_data_written;
+ total_dma_data_written += dma_data_written;
+ }
+ }
+
+ /* Add fake frame */
+ header[0] &= ~GENMASK(7, 6); /* Set inactive flag in BPT/BRA frame heade */
+ while (fake_size >= data_per_frame) {
+ header[1] = data_per_frame;
ret = sdw_cdns_prepare_read_pd0_buffer(header, SDW_CDNS_BRA_HDR, p_dma_buffer,
dma_buffer_size, &dma_data_written,
counter);
@@ -2393,28 +2484,24 @@ int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, u32 start_register, int data_si
counter++;
- data_size -= data_per_frame;
-
+ fake_size -= data_per_frame;
p_dma_buffer += dma_data_written;
dma_buffer_size -= dma_data_written;
total_dma_data_written += dma_data_written;
-
- start_register += data_per_frame;
}
- if (data_size) {
- header[1] = data_size;
- header[2] = start_register >> 24 & 0xFF;
- header[3] = start_register >> 16 & 0xFF;
- header[4] = start_register >> 8 & 0xFF;
- header[5] = start_register >> 0 & 0xFF;
-
+ if (fake_size) {
+ header[1] = fake_size;
ret = sdw_cdns_prepare_read_pd0_buffer(header, SDW_CDNS_BRA_HDR, p_dma_buffer,
dma_buffer_size, &dma_data_written,
counter);
if (ret < 0)
return ret;
+ counter++;
+
+ p_dma_buffer += dma_data_written;
+ dma_buffer_size -= dma_data_written;
total_dma_data_written += dma_data_written;
}
@@ -2495,14 +2582,14 @@ int sdw_cdns_check_write_response(struct device *dev, u8 *dma_buffer,
ret = check_frame_start(header, counter);
if (ret < 0) {
dev_err(dev, "%s: bad frame %d/%d start header %x\n",
- __func__, i, num_frames, header);
+ __func__, i + 1, num_frames, header);
return ret;
}
ret = check_frame_end(footer);
if (ret < 0) {
dev_err(dev, "%s: bad frame %d/%d end footer %x\n",
- __func__, i, num_frames, footer);
+ __func__, i + 1, num_frames, footer);
return ret;
}
@@ -2549,9 +2636,12 @@ static u8 extract_read_data(u32 *data, int num_bytes, u8 *buffer)
}
int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buffer_size,
- u8 *buffer, int buffer_size, int num_frames, int data_per_frame)
+ struct sdw_bpt_section *sec, int num_sec, int num_frames,
+ int data_per_frame)
{
int total_num_bytes = 0;
+ int buffer_size = 0;
+ int sec_index;
u32 *p_data;
u8 *p_buf;
int counter;
@@ -2565,7 +2655,10 @@ int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buf
counter = CDNS_BPT_ROLLING_COUNTER_START;
p_data = (u32 *)dma_buffer;
- p_buf = buffer;
+
+ sec_index = 0;
+ p_buf = sec[sec_index].buf;
+ buffer_size = sec[sec_index].len;
for (i = 0; i < num_frames; i++) {
header = *p_data++;
@@ -2573,7 +2666,7 @@ int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buf
ret = check_frame_start(header, counter);
if (ret < 0) {
dev_err(dev, "%s: bad frame %d/%d start header %x\n",
- __func__, i, num_frames, header);
+ __func__, i + 1, num_frames, header);
return ret;
}
@@ -2588,7 +2681,7 @@ int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buf
if (crc != expected_crc) {
dev_err(dev, "%s: bad frame %d/%d crc %#x expected %#x\n",
- __func__, i, num_frames, crc, expected_crc);
+ __func__, i + 1, num_frames, crc, expected_crc);
return -EIO;
}
@@ -2599,12 +2692,24 @@ int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buf
ret = check_frame_end(footer);
if (ret < 0) {
dev_err(dev, "%s: bad frame %d/%d end footer %x\n",
- __func__, i, num_frames, footer);
+ __func__, i + 1, num_frames, footer);
return ret;
}
counter++;
counter &= GENMASK(3, 0);
+
+ if (buffer_size == total_num_bytes && (i + 1) < num_frames) {
+ sec_index++;
+ if (sec_index >= num_sec) {
+ dev_err(dev, "%s: incorrect section index %d i %d\n",
+ __func__, sec_index, i);
+ return -EINVAL;
+ }
+ p_buf = sec[sec_index].buf;
+ buffer_size = sec[sec_index].len;
+ total_num_bytes = 0;
+ }
}
return 0;
}
diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h
index 9373426c7f63..668f807cff4b 100644
--- a/drivers/soundwire/cadence_master.h
+++ b/drivers/soundwire/cadence_master.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
/* Copyright(c) 2015-17 Intel Corporation. */
#include <sound/soc.h>
+#include "bus.h"
#ifndef __SDW_CADENCE_H
#define __SDW_CADENCE_H
@@ -209,23 +210,29 @@ void sdw_cdns_config_update(struct sdw_cdns *cdns);
int sdw_cdns_config_update_set_wait(struct sdw_cdns *cdns);
/* SoundWire BPT/BRA helpers to format data */
+int sdw_cdns_bpt_find_bandwidth(int command, /* 0: write, 1: read */
+ int row, int col, int frame_rate,
+ unsigned int *tx_dma_bandwidth,
+ unsigned int *rx_dma_bandwidth);
+
int sdw_cdns_bpt_find_buffer_sizes(int command, /* 0: write, 1: read */
int row, int col, unsigned int data_bytes,
unsigned int requested_bytes_per_frame,
unsigned int *data_per_frame, unsigned int *pdi0_buffer_size,
unsigned int *pdi1_buffer_size, unsigned int *num_frames);
-int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, u32 start_register, u8 *data, int data_size,
- int data_per_frame, u8 *dma_buffer, int dma_buffer_size,
- int *dma_buffer_total_bytes);
+int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, struct sdw_bpt_section *sec, int num_sec,
+ int data_per_frame, u8 *dma_buffer,
+ int dma_buffer_size, int *dma_buffer_total_bytes);
-int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, u32 start_register, int data_size,
+int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, struct sdw_bpt_section *sec, int num_sec,
int data_per_frame, u8 *dma_buffer, int dma_buffer_size,
- int *dma_buffer_total_bytes);
+ int *dma_buffer_total_bytes, unsigned int fake_size);
int sdw_cdns_check_write_response(struct device *dev, u8 *dma_buffer,
int dma_buffer_size, int num_frames);
int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buffer_size,
- u8 *buffer, int buffer_size, int num_frames, int data_per_frame);
+ struct sdw_bpt_section *sec, int num_sec, int num_frames,
+ int data_per_frame);
#endif /* __SDW_CADENCE_H */
diff --git a/drivers/soundwire/debugfs.c b/drivers/soundwire/debugfs.c
index 1e0f9318b616..6068011dd0d9 100644
--- a/drivers/soundwire/debugfs.c
+++ b/drivers/soundwire/debugfs.c
@@ -222,15 +222,23 @@ DEFINE_DEBUGFS_ATTRIBUTE(set_num_bytes_fops, NULL,
static int do_bpt_sequence(struct sdw_slave *slave, bool write, u8 *buffer)
{
struct sdw_bpt_msg msg = {0};
+ struct sdw_bpt_section *sec;
- msg.addr = start_addr;
- msg.len = num_bytes;
+ sec = kcalloc(1, sizeof(*sec), GFP_KERNEL);
+ if (!sec)
+ return -ENOMEM;
+ msg.sections = 1;
+
+ sec[0].addr = start_addr;
+ sec[0].len = num_bytes;
+
+ msg.sec = sec;
msg.dev_num = slave->dev_num;
if (write)
msg.flags = SDW_MSG_FLAG_WRITE;
else
msg.flags = SDW_MSG_FLAG_READ;
- msg.buf = buffer;
+ sec[0].buf = buffer;
return sdw_bpt_send_sync(slave->bus, slave, &msg);
}
diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c
index c18f0c16f929..530ac66ac6fa 100644
--- a/drivers/soundwire/generic_bandwidth_allocation.c
+++ b/drivers/soundwire/generic_bandwidth_allocation.c
@@ -124,6 +124,9 @@ static void sdw_compute_dp0_port_params(struct sdw_bus *bus)
struct sdw_master_runtime *m_rt;
list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
+ /* DP0 is for BPT only */
+ if (m_rt->stream->type != SDW_STREAM_BPT)
+ continue;
sdw_compute_dp0_master_ports(m_rt);
sdw_compute_dp0_slave_ports(m_rt);
}
diff --git a/drivers/soundwire/intel_ace2x.c b/drivers/soundwire/intel_ace2x.c
index 5d08364ad6d1..1ed0251d2592 100644
--- a/drivers/soundwire/intel_ace2x.c
+++ b/drivers/soundwire/intel_ace2x.c
@@ -44,6 +44,8 @@ static int sdw_slave_bpt_stream_add(struct sdw_slave *slave, struct sdw_stream_r
return ret;
}
+#define READ_PDI1_MIN_SIZE 12
+
static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave *slave,
struct sdw_bpt_msg *msg)
{
@@ -53,19 +55,31 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave *
struct sdw_stream_runtime *stream;
struct sdw_stream_config sconfig;
struct sdw_port_config *pconfig;
+ unsigned int pdi0_buf_size_pre_frame;
+ unsigned int pdi1_buf_size_pre_frame;
+ unsigned int pdi0_buffer_size_;
+ unsigned int pdi1_buffer_size_;
unsigned int pdi0_buffer_size;
unsigned int tx_dma_bandwidth;
unsigned int pdi1_buffer_size;
unsigned int rx_dma_bandwidth;
+ unsigned int fake_num_frames;
unsigned int data_per_frame;
unsigned int tx_total_bytes;
struct sdw_cdns_pdi *pdi0;
struct sdw_cdns_pdi *pdi1;
+ unsigned int rx_alignment;
+ unsigned int tx_alignment;
+ unsigned int num_frames_;
unsigned int num_frames;
+ unsigned int fake_size;
+ unsigned int tx_pad;
+ unsigned int rx_pad;
int command;
int ret1;
int ret;
int dir;
+ int len;
int i;
stream = sdw_alloc_stream("BPT", SDW_STREAM_BPT);
@@ -138,23 +152,77 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave *
command = (msg->flags & SDW_MSG_FLAG_WRITE) ? 0 : 1;
- ret = sdw_cdns_bpt_find_buffer_sizes(command, cdns->bus.params.row, cdns->bus.params.col,
- msg->len, SDW_BPT_MSG_MAX_BYTES, &data_per_frame,
- &pdi0_buffer_size, &pdi1_buffer_size, &num_frames);
+ ret = sdw_cdns_bpt_find_bandwidth(command, cdns->bus.params.row,
+ cdns->bus.params.col,
+ prop->default_frame_rate,
+ &tx_dma_bandwidth, &rx_dma_bandwidth);
if (ret < 0)
goto deprepare_stream;
+ len = 0;
+ pdi0_buffer_size = 0;
+ pdi1_buffer_size = 0;
+ num_frames = 0;
+ /* Add up pdi buffer size and frame numbers of each BPT sections */
+ for (i = 0; i < msg->sections; i++) {
+ ret = sdw_cdns_bpt_find_buffer_sizes(command, cdns->bus.params.row,
+ cdns->bus.params.col,
+ msg->sec[i].len, SDW_BPT_MSG_MAX_BYTES,
+ &data_per_frame, &pdi0_buffer_size_,
+ &pdi1_buffer_size_, &num_frames_);
+ if (ret < 0)
+ goto deprepare_stream;
+
+ len += msg->sec[i].len;
+ pdi0_buffer_size += pdi0_buffer_size_;
+ pdi1_buffer_size += pdi1_buffer_size_;
+ num_frames += num_frames_;
+ }
+
sdw->bpt_ctx.pdi0_buffer_size = pdi0_buffer_size;
sdw->bpt_ctx.pdi1_buffer_size = pdi1_buffer_size;
sdw->bpt_ctx.num_frames = num_frames;
sdw->bpt_ctx.data_per_frame = data_per_frame;
- tx_dma_bandwidth = div_u64((u64)pdi0_buffer_size * 8 * (u64)prop->default_frame_rate,
- num_frames);
- rx_dma_bandwidth = div_u64((u64)pdi1_buffer_size * 8 * (u64)prop->default_frame_rate,
- num_frames);
+
+ rx_alignment = hda_sdw_bpt_get_buf_size_alignment(rx_dma_bandwidth);
+ tx_alignment = hda_sdw_bpt_get_buf_size_alignment(tx_dma_bandwidth);
+
+ if (command) { /* read */
+ /* Get buffer size of a full frame */
+ ret = sdw_cdns_bpt_find_buffer_sizes(command, cdns->bus.params.row,
+ cdns->bus.params.col,
+ data_per_frame, SDW_BPT_MSG_MAX_BYTES,
+ &data_per_frame, &pdi0_buf_size_pre_frame,
+ &pdi1_buf_size_pre_frame, &fake_num_frames);
+ if (ret < 0)
+ goto deprepare_stream;
+
+ /* find fake pdi1 buffer size */
+ rx_pad = rx_alignment - (pdi1_buffer_size % rx_alignment);
+ while (rx_pad <= READ_PDI1_MIN_SIZE)
+ rx_pad += rx_alignment;
+
+ pdi1_buffer_size += rx_pad;
+ /* It is fine if we request more than enough byte to read */
+ fake_num_frames = DIV_ROUND_UP(rx_pad, pdi1_buf_size_pre_frame);
+ fake_size = fake_num_frames * data_per_frame;
+
+ /* find fake pdi0 buffer size */
+ pdi0_buffer_size += (fake_num_frames * pdi0_buf_size_pre_frame);
+ tx_pad = tx_alignment - (pdi0_buffer_size % tx_alignment);
+ pdi0_buffer_size += tx_pad;
+ } else { /* write */
+ /*
+ * For the write command, the rx data block is 4, and the rx buffer size of a frame
+ * is 8. So the rx buffer size (pdi0_buffer_size) is always a multiple of rx
+ * alignment.
+ */
+ tx_pad = tx_alignment - (pdi0_buffer_size % tx_alignment);
+ pdi0_buffer_size += tx_pad;
+ }
dev_dbg(cdns->dev, "Message len %d transferred in %d frames (%d per frame)\n",
- msg->len, num_frames, data_per_frame);
+ len, num_frames, data_per_frame);
dev_dbg(cdns->dev, "sizes pdi0 %d pdi1 %d tx_bandwidth %d rx_bandwidth %d\n",
pdi0_buffer_size, pdi1_buffer_size, tx_dma_bandwidth, rx_dma_bandwidth);
@@ -169,15 +237,16 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave *
}
if (!command) {
- ret = sdw_cdns_prepare_write_dma_buffer(msg->dev_num, msg->addr, msg->buf,
- msg->len, data_per_frame,
+ ret = sdw_cdns_prepare_write_dma_buffer(msg->dev_num, msg->sec, msg->sections,
+ data_per_frame,
sdw->bpt_ctx.dmab_tx_bdl.area,
pdi0_buffer_size, &tx_total_bytes);
} else {
- ret = sdw_cdns_prepare_read_dma_buffer(msg->dev_num, msg->addr, msg->len,
+ ret = sdw_cdns_prepare_read_dma_buffer(msg->dev_num, msg->sec, msg->sections,
data_per_frame,
sdw->bpt_ctx.dmab_tx_bdl.area,
- pdi0_buffer_size, &tx_total_bytes);
+ pdi0_buffer_size, &tx_total_bytes,
+ fake_size);
}
if (!ret)
@@ -252,11 +321,16 @@ static int intel_ace2x_bpt_send_async(struct sdw_intel *sdw, struct sdw_slave *s
struct sdw_bpt_msg *msg)
{
struct sdw_cdns *cdns = &sdw->cdns;
+ int len = 0;
int ret;
+ int i;
+
+ for (i = 0; i < msg->sections; i++)
+ len += msg->sec[i].len;
- if (msg->len < INTEL_BPT_MSG_BYTE_MIN) {
+ if (len < INTEL_BPT_MSG_BYTE_MIN) {
dev_err(cdns->dev, "BPT message length %d is less than the minimum bytes %d\n",
- msg->len, INTEL_BPT_MSG_BYTE_MIN);
+ len, INTEL_BPT_MSG_BYTE_MIN);
return -EINVAL;
}
@@ -316,7 +390,7 @@ static int intel_ace2x_bpt_wait(struct sdw_intel *sdw, struct sdw_slave *slave,
} else {
ret = sdw_cdns_check_read_response(cdns->dev, sdw->bpt_ctx.dmab_rx_bdl.area,
sdw->bpt_ctx.pdi1_buffer_size,
- msg->buf, msg->len, sdw->bpt_ctx.num_frames,
+ msg->sec, msg->sections, sdw->bpt_ctx.num_frames,
sdw->bpt_ctx.data_per_frame);
if (ret < 0)
dev_err(cdns->dev, "%s: BPT Read failed %d\n", __func__, ret);
diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index 5b3078220189..17afc5aa8b44 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -31,6 +31,7 @@
#define SWRM_VERSION_1_5_1 0x01050001
#define SWRM_VERSION_1_7_0 0x01070000
#define SWRM_VERSION_2_0_0 0x02000000
+#define SWRM_VERSION_3_1_0 0x03010000
#define SWRM_COMP_HW_VERSION 0x00
#define SWRM_COMP_CFG_ADDR 0x04
#define SWRM_COMP_CFG_IRQ_LEVEL_OR_PULSE_MSK BIT(1)
@@ -40,6 +41,9 @@
#define SWRM_COMP_PARAMS_RD_FIFO_DEPTH GENMASK(19, 15)
#define SWRM_COMP_PARAMS_DOUT_PORTS_MASK GENMASK(4, 0)
#define SWRM_COMP_PARAMS_DIN_PORTS_MASK GENMASK(9, 5)
+#define SWRM_V3_COMP_PARAMS_WR_FIFO_DEPTH GENMASK(17, 10)
+#define SWRM_V3_COMP_PARAMS_RD_FIFO_DEPTH GENMASK(23, 18)
+
#define SWRM_COMP_MASTER_ID 0x104
#define SWRM_V1_3_INTERRUPT_STATUS 0x200
#define SWRM_V2_0_INTERRUPT_STATUS 0x5000
@@ -99,14 +103,15 @@
#define SWRM_MCP_SLV_STATUS 0x1090
#define SWRM_MCP_SLV_STATUS_MASK GENMASK(1, 0)
#define SWRM_MCP_SLV_STATUS_SZ 2
-#define SWRM_DP_PORT_CTRL_BANK(n, m) (0x1124 + 0x100 * (n - 1) + 0x40 * m)
-#define SWRM_DP_PORT_CTRL_2_BANK(n, m) (0x1128 + 0x100 * (n - 1) + 0x40 * m)
-#define SWRM_DP_BLOCK_CTRL_1(n) (0x112C + 0x100 * (n - 1))
-#define SWRM_DP_BLOCK_CTRL2_BANK(n, m) (0x1130 + 0x100 * (n - 1) + 0x40 * m)
-#define SWRM_DP_PORT_HCTRL_BANK(n, m) (0x1134 + 0x100 * (n - 1) + 0x40 * m)
-#define SWRM_DP_BLOCK_CTRL3_BANK(n, m) (0x1138 + 0x100 * (n - 1) + 0x40 * m)
-#define SWRM_DP_SAMPLECTRL2_BANK(n, m) (0x113C + 0x100 * (n - 1) + 0x40 * m)
-#define SWRM_DIN_DPn_PCM_PORT_CTRL(n) (0x1054 + 0x100 * (n - 1))
+
+#define SWRM_DPn_PORT_CTRL_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m)
+#define SWRM_DPn_PORT_CTRL_2_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m)
+#define SWRM_DPn_BLOCK_CTRL_1(offset, n) (offset + 0x100 * (n - 1))
+#define SWRM_DPn_BLOCK_CTRL2_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m)
+#define SWRM_DPn_PORT_HCTRL_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m)
+#define SWRM_DPn_BLOCK_CTRL3_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m)
+#define SWRM_DPn_SAMPLECTRL2_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m)
+
#define SWR_V1_3_MSTR_MAX_REG_ADDR 0x1740
#define SWR_V2_0_MSTR_MAX_REG_ADDR 0x50ac
@@ -128,7 +133,6 @@
#define MAX_FREQ_NUM 1
#define TIMEOUT_MS 100
#define QCOM_SWRM_MAX_RD_LEN 0x1
-#define QCOM_SDW_MAX_PORTS 14
#define DEFAULT_CLK_FREQ 9600000
#define SWRM_MAX_DAIS 0xF
#define SWR_INVALID_PARAM 0xFF
@@ -172,6 +176,13 @@ enum {
SWRM_REG_CMD_FIFO_RD_CMD,
SWRM_REG_CMD_FIFO_STATUS,
SWRM_REG_CMD_FIFO_RD_FIFO_ADDR,
+ SWRM_OFFSET_DP_PORT_CTRL_BANK,
+ SWRM_OFFSET_DP_PORT_CTRL_2_BANK,
+ SWRM_OFFSET_DP_BLOCK_CTRL_1,
+ SWRM_OFFSET_DP_BLOCK_CTRL2_BANK,
+ SWRM_OFFSET_DP_PORT_HCTRL_BANK,
+ SWRM_OFFSET_DP_BLOCK_CTRL3_BANK,
+ SWRM_OFFSET_DP_SAMPLECTRL2_BANK,
};
struct qcom_swrm_ctrl {
@@ -195,6 +206,7 @@ struct qcom_swrm_ctrl {
int wake_irq;
int num_din_ports;
int num_dout_ports;
+ int nports;
int cols_index;
int rows_index;
unsigned long port_mask;
@@ -202,14 +214,13 @@ struct qcom_swrm_ctrl {
u8 rcmd_id;
u8 wcmd_id;
/* Port numbers are 1 - 14 */
- struct qcom_swrm_port_config pconfig[QCOM_SDW_MAX_PORTS + 1];
+ struct qcom_swrm_port_config *pconfig;
struct sdw_stream_runtime *sruntime[SWRM_MAX_DAIS];
enum sdw_slave_status status[SDW_MAX_DEVICES + 1];
int (*reg_read)(struct qcom_swrm_ctrl *ctrl, int reg, u32 *val);
int (*reg_write)(struct qcom_swrm_ctrl *ctrl, int reg, int val);
u32 slave_status;
u32 wr_fifo_depth;
- u32 rd_fifo_depth;
bool clock_stop_not_supported;
};
@@ -231,6 +242,13 @@ static const unsigned int swrm_v1_3_reg_layout[] = {
[SWRM_REG_CMD_FIFO_RD_CMD] = SWRM_V1_3_CMD_FIFO_RD_CMD,
[SWRM_REG_CMD_FIFO_STATUS] = SWRM_V1_3_CMD_FIFO_STATUS,
[SWRM_REG_CMD_FIFO_RD_FIFO_ADDR] = SWRM_V1_3_CMD_FIFO_RD_FIFO_ADDR,
+ [SWRM_OFFSET_DP_PORT_CTRL_BANK] = 0x1124,
+ [SWRM_OFFSET_DP_PORT_CTRL_2_BANK] = 0x1128,
+ [SWRM_OFFSET_DP_BLOCK_CTRL_1] = 0x112c,
+ [SWRM_OFFSET_DP_BLOCK_CTRL2_BANK] = 0x1130,
+ [SWRM_OFFSET_DP_PORT_HCTRL_BANK] = 0x1134,
+ [SWRM_OFFSET_DP_BLOCK_CTRL3_BANK] = 0x1138,
+ [SWRM_OFFSET_DP_SAMPLECTRL2_BANK] = 0x113c,
};
static const struct qcom_swrm_data swrm_v1_3_data = {
@@ -265,6 +283,13 @@ static const unsigned int swrm_v2_0_reg_layout[] = {
[SWRM_REG_CMD_FIFO_RD_CMD] = SWRM_V2_0_CMD_FIFO_RD_CMD,
[SWRM_REG_CMD_FIFO_STATUS] = SWRM_V2_0_CMD_FIFO_STATUS,
[SWRM_REG_CMD_FIFO_RD_FIFO_ADDR] = SWRM_V2_0_CMD_FIFO_RD_FIFO_ADDR,
+ [SWRM_OFFSET_DP_PORT_CTRL_BANK] = 0x1124,
+ [SWRM_OFFSET_DP_PORT_CTRL_2_BANK] = 0x1128,
+ [SWRM_OFFSET_DP_BLOCK_CTRL_1] = 0x112c,
+ [SWRM_OFFSET_DP_BLOCK_CTRL2_BANK] = 0x1130,
+ [SWRM_OFFSET_DP_PORT_HCTRL_BANK] = 0x1134,
+ [SWRM_OFFSET_DP_BLOCK_CTRL3_BANK] = 0x1138,
+ [SWRM_OFFSET_DP_SAMPLECTRL2_BANK] = 0x113c,
};
static const struct qcom_swrm_data swrm_v2_0_data = {
@@ -275,6 +300,32 @@ static const struct qcom_swrm_data swrm_v2_0_data = {
.reg_layout = swrm_v2_0_reg_layout,
};
+static const unsigned int swrm_v3_0_reg_layout[] = {
+ [SWRM_REG_FRAME_GEN_ENABLED] = SWRM_V2_0_LINK_STATUS,
+ [SWRM_REG_INTERRUPT_STATUS] = SWRM_V2_0_INTERRUPT_STATUS,
+ [SWRM_REG_INTERRUPT_MASK_ADDR] = 0, /* Not present */
+ [SWRM_REG_INTERRUPT_CLEAR] = SWRM_V2_0_INTERRUPT_CLEAR,
+ [SWRM_REG_INTERRUPT_CPU_EN] = SWRM_V2_0_INTERRUPT_CPU_EN,
+ [SWRM_REG_CMD_FIFO_WR_CMD] = SWRM_V2_0_CMD_FIFO_WR_CMD,
+ [SWRM_REG_CMD_FIFO_RD_CMD] = SWRM_V2_0_CMD_FIFO_RD_CMD,
+ [SWRM_REG_CMD_FIFO_STATUS] = SWRM_V2_0_CMD_FIFO_STATUS,
+ [SWRM_REG_CMD_FIFO_RD_FIFO_ADDR] = SWRM_V2_0_CMD_FIFO_RD_FIFO_ADDR,
+ [SWRM_OFFSET_DP_PORT_CTRL_BANK] = 0x1224,
+ [SWRM_OFFSET_DP_PORT_CTRL_2_BANK] = 0x1228,
+ [SWRM_OFFSET_DP_BLOCK_CTRL_1] = 0x122c,
+ [SWRM_OFFSET_DP_BLOCK_CTRL2_BANK] = 0x1230,
+ [SWRM_OFFSET_DP_PORT_HCTRL_BANK] = 0x1234,
+ [SWRM_OFFSET_DP_BLOCK_CTRL3_BANK] = 0x1238,
+ [SWRM_OFFSET_DP_SAMPLECTRL2_BANK] = 0x123c,
+};
+
+static const struct qcom_swrm_data swrm_v3_0_data = {
+ .default_rows = 50,
+ .default_cols = 16,
+ .sw_clk_gate_required = true,
+ .max_reg = SWR_V2_0_MSTR_MAX_REG_ADDR,
+ .reg_layout = swrm_v3_0_reg_layout,
+};
#define to_qcom_sdw(b) container_of(b, struct qcom_swrm_ctrl, bus)
static int qcom_swrm_ahb_reg_read(struct qcom_swrm_ctrl *ctrl, int reg,
@@ -898,8 +949,11 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl)
swrm_wait_for_frame_gen_enabled(ctrl);
ctrl->slave_status = 0;
ctrl->reg_read(ctrl, SWRM_COMP_PARAMS, &val);
- ctrl->rd_fifo_depth = FIELD_GET(SWRM_COMP_PARAMS_RD_FIFO_DEPTH, val);
- ctrl->wr_fifo_depth = FIELD_GET(SWRM_COMP_PARAMS_WR_FIFO_DEPTH, val);
+
+ if (ctrl->version >= SWRM_VERSION_3_1_0)
+ ctrl->wr_fifo_depth = FIELD_GET(SWRM_V3_COMP_PARAMS_WR_FIFO_DEPTH, val);
+ else
+ ctrl->wr_fifo_depth = FIELD_GET(SWRM_COMP_PARAMS_WR_FIFO_DEPTH, val);
return 0;
}
@@ -966,10 +1020,10 @@ static int qcom_swrm_port_params(struct sdw_bus *bus,
unsigned int bank)
{
struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
+ u32 offset = ctrl->reg_layout[SWRM_OFFSET_DP_BLOCK_CTRL_1];
- return ctrl->reg_write(ctrl, SWRM_DP_BLOCK_CTRL_1(p_params->num),
- p_params->bps - 1);
-
+ return ctrl->reg_write(ctrl, SWRM_DPn_BLOCK_CTRL_1(offset, p_params->num),
+ p_params->bps - 1);
}
static int qcom_swrm_transport_params(struct sdw_bus *bus,
@@ -979,9 +1033,11 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus,
struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
struct qcom_swrm_port_config *pcfg;
u32 value;
- int reg = SWRM_DP_PORT_CTRL_BANK((params->port_num), bank);
+ int reg, offset = ctrl->reg_layout[SWRM_OFFSET_DP_PORT_CTRL_BANK];
int ret;
+ reg = SWRM_DPn_PORT_CTRL_BANK(offset, params->port_num, bank);
+
pcfg = &ctrl->pconfig[params->port_num];
value = pcfg->off1 << SWRM_DP_PORT_CTRL_OFFSET1_SHFT;
@@ -993,15 +1049,19 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus,
goto err;
if (pcfg->si > 0xff) {
+ offset = ctrl->reg_layout[SWRM_OFFSET_DP_SAMPLECTRL2_BANK];
value = (pcfg->si >> 8) & 0xff;
- reg = SWRM_DP_SAMPLECTRL2_BANK(params->port_num, bank);
+ reg = SWRM_DPn_SAMPLECTRL2_BANK(offset, params->port_num, bank);
+
ret = ctrl->reg_write(ctrl, reg, value);
if (ret)
goto err;
}
if (pcfg->lane_control != SWR_INVALID_PARAM) {
- reg = SWRM_DP_PORT_CTRL_2_BANK(params->port_num, bank);
+ offset = ctrl->reg_layout[SWRM_OFFSET_DP_PORT_CTRL_2_BANK];
+ reg = SWRM_DPn_PORT_CTRL_2_BANK(offset, params->port_num, bank);
+
value = pcfg->lane_control;
ret = ctrl->reg_write(ctrl, reg, value);
if (ret)
@@ -1009,20 +1069,23 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus,
}
if (pcfg->blk_group_count != SWR_INVALID_PARAM) {
- reg = SWRM_DP_BLOCK_CTRL2_BANK(params->port_num, bank);
+ offset = ctrl->reg_layout[SWRM_OFFSET_DP_BLOCK_CTRL2_BANK];
+
+ reg = SWRM_DPn_BLOCK_CTRL2_BANK(offset, params->port_num, bank);
+
value = pcfg->blk_group_count;
ret = ctrl->reg_write(ctrl, reg, value);
if (ret)
goto err;
}
- if (pcfg->hstart != SWR_INVALID_PARAM
- && pcfg->hstop != SWR_INVALID_PARAM) {
- reg = SWRM_DP_PORT_HCTRL_BANK(params->port_num, bank);
+ offset = ctrl->reg_layout[SWRM_OFFSET_DP_PORT_HCTRL_BANK];
+ reg = SWRM_DPn_PORT_HCTRL_BANK(offset, params->port_num, bank);
+
+ if (pcfg->hstart != SWR_INVALID_PARAM && pcfg->hstop != SWR_INVALID_PARAM) {
value = (pcfg->hstop << 4) | pcfg->hstart;
ret = ctrl->reg_write(ctrl, reg, value);
} else {
- reg = SWRM_DP_PORT_HCTRL_BANK(params->port_num, bank);
value = (SWR_HSTOP_MAX_VAL << 4) | SWR_HSTART_MIN_VAL;
ret = ctrl->reg_write(ctrl, reg, value);
}
@@ -1031,7 +1094,8 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus,
goto err;
if (pcfg->bp_mode != SWR_INVALID_PARAM) {
- reg = SWRM_DP_BLOCK_CTRL3_BANK(params->port_num, bank);
+ offset = ctrl->reg_layout[SWRM_OFFSET_DP_BLOCK_CTRL3_BANK];
+ reg = SWRM_DPn_BLOCK_CTRL3_BANK(offset, params->port_num, bank);
ret = ctrl->reg_write(ctrl, reg, pcfg->bp_mode);
}
@@ -1043,9 +1107,12 @@ static int qcom_swrm_port_enable(struct sdw_bus *bus,
struct sdw_enable_ch *enable_ch,
unsigned int bank)
{
- u32 reg = SWRM_DP_PORT_CTRL_BANK(enable_ch->port_num, bank);
+ u32 reg;
struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
u32 val;
+ u32 offset = ctrl->reg_layout[SWRM_OFFSET_DP_PORT_CTRL_BANK];
+
+ reg = SWRM_DPn_PORT_CTRL_BANK(offset, enable_ch->port_num, bank);
ctrl->reg_read(ctrl, reg, &val);
@@ -1155,7 +1222,6 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl,
struct snd_pcm_hw_params *params,
int direction)
{
- struct sdw_port_config pconfig[QCOM_SDW_MAX_PORTS];
struct sdw_stream_config sconfig;
struct sdw_master_runtime *m_rt;
struct sdw_slave_runtime *s_rt;
@@ -1164,6 +1230,10 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl,
unsigned long *port_mask;
int maxport, pn, nports = 0, ret = 0;
unsigned int m_port;
+ struct sdw_port_config *pconfig __free(kfree) = kcalloc(ctrl->nports,
+ sizeof(*pconfig), GFP_KERNEL);
+ if (!pconfig)
+ return -ENOMEM;
if (direction == SNDRV_PCM_STREAM_CAPTURE)
sconfig.direction = SDW_DATA_DIR_TX;
@@ -1188,8 +1258,7 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl,
continue;
port_mask = &ctrl->port_mask;
- maxport = ctrl->num_dout_ports + ctrl->num_din_ports;
-
+ maxport = ctrl->nports;
list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
slave = s_rt->slave;
@@ -1349,17 +1418,8 @@ static int qcom_swrm_register_dais(struct qcom_swrm_ctrl *ctrl)
static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl)
{
struct device_node *np = ctrl->dev->of_node;
- u8 off1[QCOM_SDW_MAX_PORTS];
- u8 off2[QCOM_SDW_MAX_PORTS];
- u16 si[QCOM_SDW_MAX_PORTS];
- u8 bp_mode[QCOM_SDW_MAX_PORTS] = { 0, };
- u8 hstart[QCOM_SDW_MAX_PORTS];
- u8 hstop[QCOM_SDW_MAX_PORTS];
- u8 word_length[QCOM_SDW_MAX_PORTS];
- u8 blk_group_count[QCOM_SDW_MAX_PORTS];
- u8 lane_control[QCOM_SDW_MAX_PORTS];
- int i, ret, nports, val;
- bool si_16 = false;
+ struct qcom_swrm_port_config *pcfg;
+ int i, ret, val;
ctrl->reg_read(ctrl, SWRM_COMP_PARAMS, &val);
@@ -1367,88 +1427,78 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl)
ctrl->num_din_ports = FIELD_GET(SWRM_COMP_PARAMS_DIN_PORTS_MASK, val);
ret = of_property_read_u32(np, "qcom,din-ports", &val);
- if (ret)
- return ret;
-
- if (val > ctrl->num_din_ports)
- return -EINVAL;
+ if (!ret) { /* only if present */
+ if (val != ctrl->num_din_ports) {
+ dev_err(ctrl->dev, "din-ports (%d) mismatch with controller (%d)",
+ val, ctrl->num_din_ports);
+ }
- ctrl->num_din_ports = val;
+ ctrl->num_din_ports = val;
+ }
ret = of_property_read_u32(np, "qcom,dout-ports", &val);
- if (ret)
- return ret;
+ if (!ret) { /* only if present */
+ if (val != ctrl->num_dout_ports) {
+ dev_err(ctrl->dev, "dout-ports (%d) mismatch with controller (%d)",
+ val, ctrl->num_dout_ports);
+ }
- if (val > ctrl->num_dout_ports)
- return -EINVAL;
+ ctrl->num_dout_ports = val;
+ }
- ctrl->num_dout_ports = val;
+ ctrl->nports = ctrl->num_dout_ports + ctrl->num_din_ports;
- nports = ctrl->num_dout_ports + ctrl->num_din_ports;
- if (nports > QCOM_SDW_MAX_PORTS)
- return -EINVAL;
+ ctrl->pconfig = devm_kcalloc(ctrl->dev, ctrl->nports + 1,
+ sizeof(*ctrl->pconfig), GFP_KERNEL);
+ if (!ctrl->pconfig)
+ return -ENOMEM;
- /* Valid port numbers are from 1-14, so mask out port 0 explicitly */
set_bit(0, &ctrl->port_mask);
+ /* Valid port numbers are from 1, so mask out port 0 explicitly */
+ for (i = 0; i < ctrl->nports; i++) {
+ pcfg = &ctrl->pconfig[i + 1];
- ret = of_property_read_u8_array(np, "qcom,ports-offset1",
- off1, nports);
- if (ret)
- return ret;
-
- ret = of_property_read_u8_array(np, "qcom,ports-offset2",
- off2, nports);
- if (ret)
- return ret;
-
- ret = of_property_read_u8_array(np, "qcom,ports-sinterval-low",
- (u8 *)si, nports);
- if (ret) {
- ret = of_property_read_u16_array(np, "qcom,ports-sinterval",
- si, nports);
+ ret = of_property_read_u8_index(np, "qcom,ports-offset1", i, &pcfg->off1);
if (ret)
return ret;
- si_16 = true;
- }
- ret = of_property_read_u8_array(np, "qcom,ports-block-pack-mode",
- bp_mode, nports);
- if (ret) {
- if (ctrl->version <= SWRM_VERSION_1_3_0)
- memset(bp_mode, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS);
- else
+ ret = of_property_read_u8_index(np, "qcom,ports-offset2", i, &pcfg->off2);
+ if (ret)
return ret;
- }
- memset(hstart, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS);
- of_property_read_u8_array(np, "qcom,ports-hstart", hstart, nports);
+ ret = of_property_read_u8_index(np, "qcom,ports-sinterval-low", i, (u8 *)&pcfg->si);
+ if (ret) {
+ ret = of_property_read_u16_index(np, "qcom,ports-sinterval", i, &pcfg->si);
+ if (ret)
+ return ret;
+ }
+
+ ret = of_property_read_u8_index(np, "qcom,ports-block-pack-mode",
+ i, &pcfg->bp_mode);
+ if (ret) {
+ if (ctrl->version <= SWRM_VERSION_1_3_0)
+ pcfg->bp_mode = SWR_INVALID_PARAM;
+ else
+ return ret;
+ }
+
+ /* Optional properties */
+ pcfg->hstart = SWR_INVALID_PARAM;
+ pcfg->hstop = SWR_INVALID_PARAM;
+ pcfg->word_length = SWR_INVALID_PARAM;
+ pcfg->blk_group_count = SWR_INVALID_PARAM;
+ pcfg->lane_control = SWR_INVALID_PARAM;
- memset(hstop, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS);
- of_property_read_u8_array(np, "qcom,ports-hstop", hstop, nports);
+ of_property_read_u8_index(np, "qcom,ports-hstart", i, &pcfg->hstart);
- memset(word_length, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS);
- of_property_read_u8_array(np, "qcom,ports-word-length", word_length, nports);
+ of_property_read_u8_index(np, "qcom,ports-hstop", i, &pcfg->hstop);
- memset(blk_group_count, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS);
- of_property_read_u8_array(np, "qcom,ports-block-group-count", blk_group_count, nports);
+ of_property_read_u8_index(np, "qcom,ports-word-length", i, &pcfg->word_length);
- memset(lane_control, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS);
- of_property_read_u8_array(np, "qcom,ports-lane-control", lane_control, nports);
+ of_property_read_u8_index(np, "qcom,ports-block-group-count",
+ i, &pcfg->blk_group_count);
- for (i = 0; i < nports; i++) {
- /* Valid port number range is from 1-14 */
- if (si_16)
- ctrl->pconfig[i + 1].si = si[i];
- else
- ctrl->pconfig[i + 1].si = ((u8 *)si)[i];
- ctrl->pconfig[i + 1].off1 = off1[i];
- ctrl->pconfig[i + 1].off2 = off2[i];
- ctrl->pconfig[i + 1].bp_mode = bp_mode[i];
- ctrl->pconfig[i + 1].hstart = hstart[i];
- ctrl->pconfig[i + 1].hstop = hstop[i];
- ctrl->pconfig[i + 1].word_length = word_length[i];
- ctrl->pconfig[i + 1].blk_group_count = blk_group_count[i];
- ctrl->pconfig[i + 1].lane_control = lane_control[i];
+ of_property_read_u8_index(np, "qcom,ports-lane-control", i, &pcfg->lane_control);
}
return 0;
@@ -1769,6 +1819,7 @@ static const struct of_device_id qcom_swrm_of_match[] = {
{ .compatible = "qcom,soundwire-v1.6.0", .data = &swrm_v1_6_data },
{ .compatible = "qcom,soundwire-v1.7.0", .data = &swrm_v1_5_data },
{ .compatible = "qcom,soundwire-v2.0.0", .data = &swrm_v2_0_data },
+ { .compatible = "qcom,soundwire-v3.1.0", .data = &swrm_v3_0_data },
{/* sentinel */},
};
diff --git a/drivers/spi/spi-microchip-core-spi.c b/drivers/spi/spi-microchip-core-spi.c
index 98bf0e6cd00e..89e40fc45d73 100644
--- a/drivers/spi/spi-microchip-core-spi.c
+++ b/drivers/spi/spi-microchip-core-spi.c
@@ -387,6 +387,7 @@ static int mchp_corespi_probe(struct platform_device *pdev)
ret = devm_spi_register_controller(dev, host);
if (ret) {
+ mchp_corespi_disable_ints(spi);
mchp_corespi_disable(spi);
return dev_err_probe(dev, ret, "unable to register host for CoreSPI controller\n");
}
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
index c8b837006bb2..fabda0f6ec1a 100644
--- a/fs/nfs/callback.c
+++ b/fs/nfs/callback.c
@@ -258,7 +258,7 @@ err_start:
/*
* Kill the callback thread if it's no longer being used.
*/
-void nfs_callback_down(int minorversion, struct net *net)
+void nfs_callback_down(int minorversion, struct net *net, struct rpc_xprt *xprt)
{
struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion];
struct svc_serv *serv;
@@ -270,7 +270,7 @@ void nfs_callback_down(int minorversion, struct net *net)
if (cb_info->users == 0) {
svc_set_num_threads(serv, NULL, 0);
dprintk("nfs_callback_down: service destroyed\n");
- svc_destroy(&cb_info->serv);
+ xprt_svc_destroy_nullify_bc(xprt, &cb_info->serv);
}
mutex_unlock(&nfs_callback_mutex);
}
diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h
index 154a6ed1299f..8809f93d82c0 100644
--- a/fs/nfs/callback.h
+++ b/fs/nfs/callback.h
@@ -188,7 +188,8 @@ extern __be32 nfs4_callback_recall(void *argp, void *resp,
struct cb_process_state *cps);
#if IS_ENABLED(CONFIG_NFS_V4)
extern int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt);
-extern void nfs_callback_down(int minorversion, struct net *net);
+extern void nfs_callback_down(int minorversion, struct net *net,
+ struct rpc_xprt *xprt);
#endif /* CONFIG_NFS_V4 */
/*
* nfs41: Callbacks are expected to not cause substantial latency,
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 54699299d5b1..2aaea9c98c2c 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -784,10 +784,18 @@ static int nfs_init_server(struct nfs_server *server,
server->fattr_valid = NFS_ATTR_FATTR_V4;
}
- if (ctx->rsize)
+ if (ctx->bsize) {
+ server->bsize = ctx->bsize;
+ server->automount_inherit |= NFS_AUTOMOUNT_INHERIT_BSIZE;
+ }
+ if (ctx->rsize) {
server->rsize = nfs_io_size(ctx->rsize, clp->cl_proto);
- if (ctx->wsize)
+ server->automount_inherit |= NFS_AUTOMOUNT_INHERIT_RSIZE;
+ }
+ if (ctx->wsize) {
server->wsize = nfs_io_size(ctx->wsize, clp->cl_proto);
+ server->automount_inherit |= NFS_AUTOMOUNT_INHERIT_WSIZE;
+ }
server->acregmin = ctx->acregmin * HZ;
server->acregmax = ctx->acregmax * HZ;
@@ -977,8 +985,13 @@ EXPORT_SYMBOL_GPL(nfs_probe_server);
void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_server *source)
{
target->flags = source->flags;
- target->rsize = source->rsize;
- target->wsize = source->wsize;
+ target->automount_inherit = source->automount_inherit;
+ if (source->automount_inherit & NFS_AUTOMOUNT_INHERIT_BSIZE)
+ target->bsize = source->bsize;
+ if (source->automount_inherit & NFS_AUTOMOUNT_INHERIT_RSIZE)
+ target->rsize = source->rsize;
+ if (source->automount_inherit & NFS_AUTOMOUNT_INHERIT_WSIZE)
+ target->wsize = source->wsize;
target->acregmin = source->acregmin;
target->acregmax = source->acregmax;
target->acdirmin = source->acdirmin;
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index 9d3a5f29f17f..2248e3ad089a 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -30,6 +30,11 @@
static unsigned nfs_delegation_watermark = NFS_DEFAULT_DELEGATION_WATERMARK;
module_param_named(delegation_watermark, nfs_delegation_watermark, uint, 0644);
+bool directory_delegations = true;
+module_param(directory_delegations, bool, 0644);
+MODULE_PARM_DESC(directory_delegations,
+ "Enable the use of directory delegations, defaults to on.");
+
static struct hlist_head *nfs_delegation_hash(struct nfs_server *server,
const struct nfs_fh *fhandle)
{
@@ -143,6 +148,8 @@ static int nfs4_do_check_delegation(struct inode *inode, fmode_t type,
*/
int nfs4_have_delegation(struct inode *inode, fmode_t type, int flags)
{
+ if (S_ISDIR(inode->i_mode) && !directory_delegations)
+ nfs_inode_evict_delegation(inode);
return nfs4_do_check_delegation(inode, type, flags, true);
}
@@ -379,6 +386,7 @@ nfs_detach_delegation_locked(struct nfs_inode *nfsi,
delegation->inode = NULL;
rcu_assign_pointer(nfsi->delegation, NULL);
spin_unlock(&delegation->lock);
+ clear_bit(NFS_INO_REQ_DIR_DELEG, &nfsi->flags);
return delegation;
}
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h
index 08ec2e9c68a4..46d866adb5c2 100644
--- a/fs/nfs/delegation.h
+++ b/fs/nfs/delegation.h
@@ -124,6 +124,19 @@ static inline int nfs_have_delegated_mtime(struct inode *inode)
NFS_DELEGATION_FLAG_TIME);
}
+extern bool directory_delegations;
+
+static inline void nfs_request_directory_delegation(struct inode *inode)
+{
+ if (S_ISDIR(inode->i_mode))
+ set_bit(NFS_INO_REQ_DIR_DELEG, &NFS_I(inode)->flags);
+}
+
+static inline bool nfs_have_directory_delegation(struct inode *inode)
+{
+ return S_ISDIR(inode->i_mode) && nfs_have_delegated_attributes(inode);
+}
+
int nfs4_delegation_hash_alloc(struct nfs_server *server);
#endif
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index ea9f6ca8f30f..23a78a742b61 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -789,16 +789,17 @@ again:
goto out;
}
+ nfs_set_verifier(dentry, dir_verifier);
inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr);
alias = d_splice_alias(inode, dentry);
d_lookup_done(dentry);
if (alias) {
if (IS_ERR(alias))
goto out;
+ nfs_set_verifier(alias, dir_verifier);
dput(dentry);
dentry = alias;
}
- nfs_set_verifier(dentry, dir_verifier);
trace_nfs_readdir_lookup(d_inode(parent), dentry, 0);
out:
dput(dentry);
@@ -1514,6 +1515,15 @@ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry,
return 0;
if (!nfs_dentry_verify_change(dir, dentry))
return 0;
+
+ /*
+ * If we have a directory delegation then we don't need to revalidate
+ * the directory. The delegation will either get recalled or we will
+ * receive a notification when it changes.
+ */
+ if (nfs_have_directory_delegation(dir))
+ return 0;
+
/* Revalidate nfsi->cache_change_attribute before we declare a match */
if (nfs_mapping_need_revalidate_inode(dir)) {
if (rcu_walk)
@@ -1894,13 +1904,15 @@ static int nfs_dentry_delete(const struct dentry *dentry)
}
/* Ensure that we revalidate inode->i_nlink */
-static void nfs_drop_nlink(struct inode *inode)
+static void nfs_drop_nlink(struct inode *inode, unsigned long gencount)
{
+ struct nfs_inode *nfsi = NFS_I(inode);
+
spin_lock(&inode->i_lock);
/* drop the inode if we're reasonably sure this is the last link */
- if (inode->i_nlink > 0)
+ if (inode->i_nlink > 0 && gencount == nfsi->attr_gencount)
drop_nlink(inode);
- NFS_I(inode)->attr_gencount = nfs_inc_attr_generation_counter();
+ nfsi->attr_gencount = nfs_inc_attr_generation_counter();
nfs_set_cache_invalid(
inode, NFS_INO_INVALID_CHANGE | NFS_INO_INVALID_CTIME |
NFS_INO_INVALID_NLINK);
@@ -1914,8 +1926,9 @@ static void nfs_drop_nlink(struct inode *inode)
static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode)
{
if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
+ unsigned long gencount = READ_ONCE(NFS_I(inode)->attr_gencount);
nfs_complete_unlink(dentry, inode);
- nfs_drop_nlink(inode);
+ nfs_drop_nlink(inode, gencount);
}
iput(inode);
}
@@ -1991,13 +2004,14 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in
nfs_lookup_advise_force_readdirplus(dir, flags);
no_entry:
+ nfs_set_verifier(dentry, dir_verifier);
res = d_splice_alias(inode, dentry);
if (res != NULL) {
if (IS_ERR(res))
goto out;
+ nfs_set_verifier(res, dir_verifier);
dentry = res;
}
- nfs_set_verifier(dentry, dir_verifier);
out:
trace_nfs_lookup_exit(dir, dentry, flags, PTR_ERR_OR_ZERO(res));
nfs_free_fattr(fattr);
@@ -2139,12 +2153,12 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
d_drop(dentry);
switch (err) {
case -ENOENT:
- d_splice_alias(NULL, dentry);
if (nfs_server_capable(dir, NFS_CAP_CASE_INSENSITIVE))
dir_verifier = inode_peek_iversion_raw(dir);
else
dir_verifier = nfs_save_change_attribute(dir);
nfs_set_verifier(dentry, dir_verifier);
+ d_splice_alias(NULL, dentry);
break;
case -EISDIR:
case -ENOTDIR:
@@ -2203,6 +2217,13 @@ no_open:
EXPORT_SYMBOL_GPL(nfs_atomic_open);
static int
+nfs_lookup_revalidate_delegated_parent(struct inode *dir, struct dentry *dentry,
+ struct inode *inode)
+{
+ return nfs_lookup_revalidate_done(dir, dentry, inode, 1);
+}
+
+static int
nfs4_lookup_revalidate(struct inode *dir, const struct qstr *name,
struct dentry *dentry, unsigned int flags)
{
@@ -2229,6 +2250,9 @@ nfs4_lookup_revalidate(struct inode *dir, const struct qstr *name,
if (nfs_verifier_is_delegated(dentry))
return nfs_lookup_revalidate_delegated(dir, dentry, inode);
+ if (nfs_have_directory_delegation(dir))
+ return nfs_lookup_revalidate_delegated_parent(dir, dentry, inode);
+
/* NFS only supports OPEN on regular files */
if (!S_ISREG(inode->i_mode))
goto full_reval;
@@ -2507,9 +2531,11 @@ static int nfs_safe_remove(struct dentry *dentry)
trace_nfs_remove_enter(dir, dentry);
if (inode != NULL) {
+ unsigned long gencount = READ_ONCE(NFS_I(inode)->attr_gencount);
+
error = NFS_PROTO(dir)->remove(dir, dentry);
if (error == 0)
- nfs_drop_nlink(inode);
+ nfs_drop_nlink(inode, gencount);
} else
error = NFS_PROTO(dir)->remove(dir, dentry);
if (error == -ENOENT)
@@ -2709,6 +2735,7 @@ int nfs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
{
struct inode *old_inode = d_inode(old_dentry);
struct inode *new_inode = d_inode(new_dentry);
+ unsigned long new_gencount = 0;
struct dentry *dentry = NULL;
struct rpc_task *task;
bool must_unblock = false;
@@ -2761,6 +2788,7 @@ int nfs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
} else {
block_revalidate(new_dentry);
must_unblock = true;
+ new_gencount = NFS_I(new_inode)->attr_gencount;
spin_unlock(&new_dentry->d_lock);
}
@@ -2800,7 +2828,7 @@ out:
new_dir, new_dentry, error);
if (!error) {
if (new_inode != NULL)
- nfs_drop_nlink(new_inode);
+ nfs_drop_nlink(new_inode, new_gencount);
/*
* The d_move() should be here instead of in an async RPC completion
* handler because we need the proper locks to move the dentry. If
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index f76fe406937a..84049f3cd340 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -1389,6 +1389,9 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
status = pnfs_sync_inode(inode, false);
if (status)
goto out;
+ } else if (nfs_have_directory_delegation(inode)) {
+ status = 0;
+ goto out;
}
status = -ENOMEM;
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 2ecd38e1d17a..2e596244799f 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -13,7 +13,7 @@
#include <linux/nfslocalio.h>
#include <linux/wait_bit.h>
-#define NFS_SB_MASK (SB_NOSUID|SB_NODEV|SB_NOEXEC|SB_SYNCHRONOUS)
+#define NFS_SB_MASK (SB_RDONLY|SB_NOSUID|SB_NODEV|SB_NOEXEC|SB_SYNCHRONOUS)
extern const struct export_operations nfs_export_ops;
@@ -152,7 +152,6 @@ struct nfs_fs_context {
struct super_block *sb;
struct dentry *dentry;
struct nfs_fattr *fattr;
- unsigned int inherited_bsize;
} clone_data;
};
diff --git a/fs/nfs/localio.c b/fs/nfs/localio.c
index f33bfa7b58e6..a113bfdacfd6 100644
--- a/fs/nfs/localio.c
+++ b/fs/nfs/localio.c
@@ -43,8 +43,8 @@ struct nfs_local_kiocb {
size_t end_len;
short int end_iter_index;
atomic_t n_iters;
+ struct iov_iter iters[NFSLOCAL_MAX_IOS];
bool iter_is_dio_aligned[NFSLOCAL_MAX_IOS];
- struct iov_iter iters[NFSLOCAL_MAX_IOS] ____cacheline_aligned;
/* End mostly DIO-specific members */
};
@@ -339,8 +339,6 @@ nfs_is_local_dio_possible(struct nfs_local_kiocb *iocb, int rw,
if (unlikely(!nf_dio_mem_align || !nf_dio_offset_align))
return false;
- if (unlikely(nf_dio_offset_align > PAGE_SIZE))
- return false;
if (unlikely(len < nf_dio_offset_align))
return false;
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
index 5a4d193da1a9..af9be0c5f516 100644
--- a/fs/nfs/namespace.c
+++ b/fs/nfs/namespace.c
@@ -149,6 +149,7 @@ struct vfsmount *nfs_d_automount(struct path *path)
struct vfsmount *mnt = ERR_PTR(-ENOMEM);
struct nfs_server *server = NFS_SB(path->dentry->d_sb);
struct nfs_client *client = server->nfs_client;
+ unsigned long s_flags = path->dentry->d_sb->s_flags;
int timeout = READ_ONCE(nfs_mountpoint_expiry_timeout);
int ret;
@@ -169,11 +170,21 @@ struct vfsmount *nfs_d_automount(struct path *path)
if (!ctx->clone_data.fattr)
goto out_fc;
+ if (fc->cred != server->cred) {
+ put_cred(fc->cred);
+ fc->cred = get_cred(server->cred);
+ }
+
if (fc->net_ns != client->cl_net) {
put_net(fc->net_ns);
fc->net_ns = get_net(client->cl_net);
}
+ /* Inherit the flags covered by NFS_SB_MASK */
+ fc->sb_flags_mask |= NFS_SB_MASK;
+ fc->sb_flags &= ~NFS_SB_MASK;
+ fc->sb_flags |= s_flags & NFS_SB_MASK;
+
/* for submounts we want the same server; referrals will reassign */
memcpy(&ctx->nfs_server._address, &client->cl_addr, client->cl_addrlen);
ctx->nfs_server.addrlen = client->cl_addrlen;
@@ -184,6 +195,10 @@ struct vfsmount *nfs_d_automount(struct path *path)
ctx->nfs_mod = client->cl_nfs_mod;
get_nfs_version(ctx->nfs_mod);
+ /* Inherit block sizes if they were specified as mount parameters */
+ if (server->automount_inherit & NFS_AUTOMOUNT_INHERIT_BSIZE)
+ ctx->bsize = server->bsize;
+
ret = client->rpc_ops->submount(fc, server);
if (ret < 0) {
mnt = ERR_PTR(ret);
@@ -283,7 +298,6 @@ int nfs_do_submount(struct fs_context *fc)
return -ENOMEM;
ctx->internal = true;
- ctx->clone_data.inherited_bsize = ctx->clone_data.sb->s_blocksize_bits;
p = nfs_devname(dentry, buffer, 4096);
if (IS_ERR(p)) {
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index a4cb67573aa7..1181f9cc6dbd 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -483,7 +483,8 @@ nfs3_proc_unlink_done(struct rpc_task *task, struct inode *dir)
static void
nfs3_proc_rename_setup(struct rpc_message *msg,
struct dentry *old_dentry,
- struct dentry *new_dentry)
+ struct dentry *new_dentry,
+ struct inode *same_parent)
{
msg->rpc_proc = &nfs3_procedures[NFS3PROC_RENAME];
}
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c
index 3a4baed993c9..96bccefbe2cb 100644
--- a/fs/nfs/nfs4client.c
+++ b/fs/nfs/nfs4client.c
@@ -281,8 +281,13 @@ error:
*/
static void nfs4_destroy_callback(struct nfs_client *clp)
{
- if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state))
- nfs_callback_down(clp->cl_mvops->minor_version, clp->cl_net);
+ if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) {
+ struct rpc_xprt *xprt;
+
+ xprt = rcu_dereference_raw(clp->cl_rpcclient->cl_xprt);
+ nfs_callback_down(clp->cl_mvops->minor_version, clp->cl_net,
+ xprt);
+ }
}
static void nfs4_shutdown_client(struct nfs_client *clp)
@@ -1174,10 +1179,20 @@ static int nfs4_init_server(struct nfs_server *server, struct fs_context *fc)
if (error < 0)
return error;
- if (ctx->rsize)
- server->rsize = nfs_io_size(ctx->rsize, server->nfs_client->cl_proto);
- if (ctx->wsize)
- server->wsize = nfs_io_size(ctx->wsize, server->nfs_client->cl_proto);
+ if (ctx->bsize) {
+ server->bsize = ctx->bsize;
+ server->automount_inherit |= NFS_AUTOMOUNT_INHERIT_BSIZE;
+ }
+ if (ctx->rsize) {
+ server->rsize =
+ nfs_io_size(ctx->rsize, server->nfs_client->cl_proto);
+ server->automount_inherit |= NFS_AUTOMOUNT_INHERIT_RSIZE;
+ }
+ if (ctx->wsize) {
+ server->wsize =
+ nfs_io_size(ctx->wsize, server->nfs_client->cl_proto);
+ server->automount_inherit |= NFS_AUTOMOUNT_INHERIT_WSIZE;
+ }
server->acregmin = ctx->acregmin * HZ;
server->acregmax = ctx->acregmax * HZ;
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 93c6ce04332b..ec1ce593dea2 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -1780,8 +1780,17 @@ static void nfs_set_open_stateid_locked(struct nfs4_state *state,
if (nfs_stateid_is_sequential(state, stateid))
break;
- if (status)
- break;
+ if (status) {
+ if (nfs4_stateid_match_other(stateid, &state->open_stateid) &&
+ !nfs4_stateid_is_newer(stateid, &state->open_stateid)) {
+ trace_nfs4_open_stateid_update_skip(state->inode,
+ stateid, status);
+ return;
+ } else {
+ break;
+ }
+ }
+
/* Rely on seqids for serialisation with NFSv4.0 */
if (!nfs4_has_session(NFS_SERVER(state->inode)->nfs_client))
break;
@@ -3174,18 +3183,6 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
if (opendata->o_res.rflags & NFS4_OPEN_RESULT_PRESERVE_UNLINKED)
set_bit(NFS_INO_PRESERVE_UNLINKED, &NFS_I(state->inode)->flags);
- dentry = opendata->dentry;
- if (d_really_is_negative(dentry)) {
- struct dentry *alias;
- d_drop(dentry);
- alias = d_splice_alias(igrab(state->inode), dentry);
- /* d_splice_alias() can't fail here - it's a non-directory */
- if (alias) {
- dput(ctx->dentry);
- ctx->dentry = dentry = alias;
- }
- }
-
switch(opendata->o_arg.claim) {
default:
break;
@@ -3196,7 +3193,20 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
break;
if (opendata->o_res.delegation.type != 0)
dir_verifier = nfs_save_change_attribute(dir);
- nfs_set_verifier(dentry, dir_verifier);
+ }
+
+ dentry = opendata->dentry;
+ nfs_set_verifier(dentry, dir_verifier);
+ if (d_really_is_negative(dentry)) {
+ struct dentry *alias;
+ d_drop(dentry);
+ alias = d_splice_alias(igrab(state->inode), dentry);
+ /* d_splice_alias() can't fail here - it's a non-directory */
+ if (alias) {
+ dput(ctx->dentry);
+ nfs_set_verifier(alias, dir_verifier);
+ ctx->dentry = dentry = alias;
+ }
}
/* Parse layoutget results before we check for access */
@@ -4460,6 +4470,30 @@ out:
return status;
}
+#if IS_ENABLED(CONFIG_NFS_V4_1)
+static bool should_request_dir_deleg(struct inode *inode)
+{
+ if (!directory_delegations)
+ return false;
+ if (!inode)
+ return false;
+ if (!S_ISDIR(inode->i_mode))
+ return false;
+ if (!nfs_server_capable(inode, NFS_CAP_DIR_DELEG))
+ return false;
+ if (!test_and_clear_bit(NFS_INO_REQ_DIR_DELEG, &(NFS_I(inode)->flags)))
+ return false;
+ if (nfs4_have_delegation(inode, FMODE_READ, 0))
+ return false;
+ return true;
+}
+#else
+static bool should_request_dir_deleg(struct inode *inode)
+{
+ return false;
+}
+#endif /* CONFIG_NFS_V4_1 */
+
static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fattr *fattr, struct inode *inode)
{
@@ -4477,7 +4511,9 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
.rpc_argp = &args,
.rpc_resp = &res,
};
+ struct nfs4_gdd_res gdd_res;
unsigned short task_flags = 0;
+ int status;
if (nfs4_has_session(server->nfs_client))
task_flags = RPC_TASK_MOVEABLE;
@@ -4486,11 +4522,31 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
if (inode && (server->flags & NFS_MOUNT_SOFTREVAL))
task_flags |= RPC_TASK_TIMEOUT;
+ args.get_dir_deleg = should_request_dir_deleg(inode);
+ if (args.get_dir_deleg)
+ res.gdd_res = &gdd_res;
+
nfs4_bitmap_copy_adjust(bitmask, nfs4_bitmask(server, fattr->label), inode, 0);
nfs_fattr_init(fattr);
nfs4_init_sequence(&args.seq_args, &res.seq_res, 0, 0);
- return nfs4_do_call_sync(server->client, server, &msg,
- &args.seq_args, &res.seq_res, task_flags);
+
+ status = nfs4_do_call_sync(server->client, server, &msg,
+ &args.seq_args, &res.seq_res, task_flags);
+ if (args.get_dir_deleg) {
+ switch (status) {
+ case 0:
+ if (gdd_res.status != GDD4_OK)
+ break;
+ status = nfs_inode_set_delegation(
+ inode, current_cred(), FMODE_READ,
+ &gdd_res.deleg, 0, NFS4_OPEN_DELEGATE_READ);
+ break;
+ case -ENOTSUPP:
+ case -EOPNOTSUPP:
+ server->caps &= ~NFS_CAP_DIR_DELEG;
+ }
+ }
+ return status;
}
int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
@@ -4503,8 +4559,14 @@ int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
do {
err = _nfs4_proc_getattr(server, fhandle, fattr, inode);
trace_nfs4_getattr(server, fhandle, fattr, err);
- err = nfs4_handle_exception(server, err,
- &exception);
+ switch (err) {
+ default:
+ err = nfs4_handle_exception(server, err, &exception);
+ break;
+ case -ENOTSUPP:
+ case -EOPNOTSUPP:
+ exception.retry = true;
+ }
} while (exception.retry);
return err;
}
@@ -4768,6 +4830,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
int status = 0;
if (!nfs4_have_delegation(inode, FMODE_READ, 0)) {
+ nfs_request_directory_delegation(inode);
res.fattr = nfs_alloc_fattr();
if (res.fattr == NULL)
return -ENOMEM;
@@ -4875,6 +4938,8 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
ilabel = nfs4_label_init_security(dir, dentry, sattr, &l);
+ nfs_request_directory_delegation(dir);
+
if (!(server->attr_bitmask[2] & FATTR4_WORD2_MODE_UMASK))
sattr->ia_mode &= ~current_umask();
state = nfs4_do_open(dir, ctx, flags, sattr, ilabel, NULL);
@@ -4971,6 +5036,7 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg,
nfs4_init_sequence(&args->seq_args, &res->seq_res, 1, 0);
nfs_fattr_init(res->dir_attr);
+ nfs_request_directory_delegation(d_inode(dentry->d_parent));
if (inode) {
nfs4_inode_return_delegation(inode);
@@ -5005,7 +5071,8 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
static void nfs4_proc_rename_setup(struct rpc_message *msg,
struct dentry *old_dentry,
- struct dentry *new_dentry)
+ struct dentry *new_dentry,
+ struct inode *same_parent)
{
struct nfs_renameargs *arg = msg->rpc_argp;
struct nfs_renameres *res = msg->rpc_resp;
@@ -5016,6 +5083,8 @@ static void nfs4_proc_rename_setup(struct rpc_message *msg,
nfs4_inode_make_writeable(old_inode);
if (new_inode)
nfs4_inode_return_delegation(new_inode);
+ if (same_parent)
+ nfs_request_directory_delegation(same_parent);
msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME];
res->server = NFS_SB(old_dentry->d_sb);
nfs4_init_sequence(&arg->seq_args, &res->seq_res, 1, 0);
@@ -10822,6 +10891,7 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {
.minor_version = 1,
.init_caps = NFS_CAP_READDIRPLUS
| NFS_CAP_ATOMIC_OPEN
+ | NFS_CAP_DIR_DELEG
| NFS_CAP_POSIX_LOCK
| NFS_CAP_STATEID_NFSV41
| NFS_CAP_ATOMIC_OPEN_V1
@@ -10848,6 +10918,7 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = {
.minor_version = 2,
.init_caps = NFS_CAP_READDIRPLUS
| NFS_CAP_ATOMIC_OPEN
+ | NFS_CAP_DIR_DELEG
| NFS_CAP_POSIX_LOCK
| NFS_CAP_STATEID_NFSV41
| NFS_CAP_ATOMIC_OPEN_V1
diff --git a/fs/nfs/nfs4trace.h b/fs/nfs/nfs4trace.h
index 9776d220cec3..6285128e631a 100644
--- a/fs/nfs/nfs4trace.h
+++ b/fs/nfs/nfs4trace.h
@@ -1353,6 +1353,7 @@ DEFINE_NFS4_INODE_STATEID_EVENT(nfs4_setattr);
DEFINE_NFS4_INODE_STATEID_EVENT(nfs4_delegreturn);
DEFINE_NFS4_INODE_STATEID_EVENT(nfs4_open_stateid_update);
DEFINE_NFS4_INODE_STATEID_EVENT(nfs4_open_stateid_update_wait);
+DEFINE_NFS4_INODE_STATEID_EVENT(nfs4_open_stateid_update_skip);
DEFINE_NFS4_INODE_STATEID_EVENT(nfs4_close_stateid_update_wait);
DECLARE_EVENT_CLASS(nfs4_getattr_event,
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 1d0e6c10f921..b6fe30577fab 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -393,6 +393,20 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 5)
#define encode_reclaim_complete_maxsz (op_encode_hdr_maxsz + 4)
#define decode_reclaim_complete_maxsz (op_decode_hdr_maxsz + 4)
+#define encode_get_dir_deleg_maxsz (op_encode_hdr_maxsz + \
+ 4 /* gdda_signal_deleg_avail */ + \
+ 8 /* gdda_notification_types */ + \
+ nfstime4_maxsz /* gdda_child_attr_delay */ + \
+ nfstime4_maxsz /* gdda_dir_attr_delay */ + \
+ nfs4_fattr_bitmap_maxsz /* gdda_child_attributes */ + \
+ nfs4_fattr_bitmap_maxsz /* gdda_dir_attributes */)
+#define decode_get_dir_deleg_maxsz (op_decode_hdr_maxsz + \
+ 4 /* gddrnf_status */ + \
+ encode_verifier_maxsz /* gddr_cookieverf */ + \
+ encode_stateid_maxsz /* gddr_stateid */ + \
+ 8 /* gddr_notification */ + \
+ nfs4_fattr_maxsz /* gddr_child_attributes */ + \
+ nfs4_fattr_maxsz /* gddr_dir_attributes */)
#define encode_getdeviceinfo_maxsz (op_encode_hdr_maxsz + \
XDR_QUADLEN(NFS4_DEVICEID4_SIZE) + \
1 /* layout type */ + \
@@ -444,6 +458,8 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
#else /* CONFIG_NFS_V4_1 */
#define encode_sequence_maxsz 0
#define decode_sequence_maxsz 0
+#define encode_get_dir_deleg_maxsz 0
+#define decode_get_dir_deleg_maxsz 0
#define encode_layoutreturn_maxsz 0
#define decode_layoutreturn_maxsz 0
#define encode_layoutget_maxsz 0
@@ -631,11 +647,13 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
#define NFS4_enc_getattr_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putfh_maxsz + \
+ encode_get_dir_deleg_maxsz + \
encode_getattr_maxsz + \
encode_renew_maxsz)
#define NFS4_dec_getattr_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putfh_maxsz + \
+ decode_get_dir_deleg_maxsz + \
decode_getattr_maxsz + \
decode_renew_maxsz)
#define NFS4_enc_lookup_sz (compound_encode_hdr_maxsz + \
@@ -2008,6 +2026,33 @@ static void encode_sequence(struct xdr_stream *xdr,
#ifdef CONFIG_NFS_V4_1
static void
+encode_get_dir_delegation(struct xdr_stream *xdr, struct compound_hdr *hdr)
+{
+ struct timespec64 ts = { 0, 0 };
+ u32 notifications[1] = { 0 };
+ u32 attributes[1] = { 0 };
+ __be32 *p;
+
+ encode_op_hdr(xdr, OP_GET_DIR_DELEGATION, decode_get_dir_deleg_maxsz, hdr);
+
+ /* We don't handle CB_RECALLABLE_OBJ_AVAIL yet. */
+ xdr_stream_encode_bool(xdr, false);
+
+ xdr_encode_bitmap4(xdr, notifications, ARRAY_SIZE(notifications));
+
+ /* Request no delay on attribute updates */
+ p = reserve_space(xdr, 12 + 12);
+ p = xdr_encode_nfstime4(p, &ts);
+ xdr_encode_nfstime4(p, &ts);
+
+ /* Requested child attributes */
+ xdr_encode_bitmap4(xdr, attributes, ARRAY_SIZE(attributes));
+
+ /* Requested dir attributes */
+ xdr_encode_bitmap4(xdr, attributes, ARRAY_SIZE(attributes));
+}
+
+static void
encode_getdeviceinfo(struct xdr_stream *xdr,
const struct nfs4_getdeviceinfo_args *args,
struct compound_hdr *hdr)
@@ -2143,6 +2188,11 @@ static void encode_free_stateid(struct xdr_stream *xdr,
}
#else
static inline void
+encode_get_dir_delegation(struct xdr_stream *xdr, struct compound_hdr *hdr)
+{
+}
+
+static inline void
encode_layoutreturn(struct xdr_stream *xdr,
const struct nfs4_layoutreturn_args *args,
struct compound_hdr *hdr)
@@ -2356,6 +2406,8 @@ static void nfs4_xdr_enc_getattr(struct rpc_rqst *req, struct xdr_stream *xdr,
encode_compound_hdr(xdr, req, &hdr);
encode_sequence(xdr, &args->seq_args, &hdr);
encode_putfh(xdr, args->fh, &hdr);
+ if (args->get_dir_deleg)
+ encode_get_dir_delegation(xdr, &hdr);
encode_getfattr(xdr, args->bitmask, &hdr);
encode_nops(&hdr);
}
@@ -5994,6 +6046,49 @@ static int decode_layout_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid)
return decode_stateid(xdr, stateid);
}
+static int decode_get_dir_delegation(struct xdr_stream *xdr,
+ struct nfs4_getattr_res *res)
+{
+ struct nfs4_gdd_res *gdd_res = res->gdd_res;
+ nfs4_verifier cookieverf;
+ u32 bitmap[1];
+ int status;
+
+ status = decode_op_hdr(xdr, OP_GET_DIR_DELEGATION);
+ if (status)
+ return status;
+
+ if (xdr_stream_decode_u32(xdr, &gdd_res->status))
+ return -EIO;
+
+ if (gdd_res->status == GDD4_UNAVAIL)
+ return xdr_inline_decode(xdr, 4) ? 0 : -EIO;
+
+ status = decode_verifier(xdr, &cookieverf);
+ if (status)
+ return status;
+
+ status = decode_delegation_stateid(xdr, &gdd_res->deleg);
+ if (status)
+ return status;
+
+ /* Decode supported notification types. */
+ status = decode_bitmap4(xdr, bitmap, ARRAY_SIZE(bitmap));
+ if (status < 0)
+ return status;
+
+ /* Decode supported child attributes. */
+ status = decode_bitmap4(xdr, bitmap, ARRAY_SIZE(bitmap));
+ if (status < 0)
+ return status;
+
+ /* Decode supported attributes. */
+ status = decode_bitmap4(xdr, bitmap, ARRAY_SIZE(bitmap));
+ if (status < 0)
+ return status;
+ return 0;
+}
+
static int decode_getdeviceinfo(struct xdr_stream *xdr,
struct nfs4_getdeviceinfo_res *res)
{
@@ -6208,6 +6303,12 @@ static int decode_free_stateid(struct xdr_stream *xdr,
return res->status;
}
#else
+static int decode_get_dir_delegation(struct xdr_stream *xdr,
+ struct nfs4_getattr_res *res)
+{
+ return 0;
+}
+
static inline
int decode_layoutreturn(struct xdr_stream *xdr,
struct nfs4_layoutreturn_res *res)
@@ -6525,6 +6626,11 @@ static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
status = decode_putfh(xdr);
if (status)
goto out;
+ if (res->gdd_res) {
+ status = decode_get_dir_delegation(xdr, res);
+ if (status)
+ goto out;
+ }
status = decode_getfattr(xdr, res->fattr, res->server);
out:
return status;
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index f157d43d1312..b72d7cc36766 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -464,6 +464,7 @@ pnfs_mark_layout_stateid_invalid(struct pnfs_layout_hdr *lo,
struct pnfs_layout_segment *lseg, *next;
set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags);
+ clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(lo->plh_inode)->flags);
list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list)
pnfs_clear_lseg_state(lseg, lseg_list);
pnfs_clear_layoutreturn_info(lo);
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 63e71310b9f6..39df80e4ae6f 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -353,7 +353,8 @@ static int nfs_proc_unlink_done(struct rpc_task *task, struct inode *dir)
static void
nfs_proc_rename_setup(struct rpc_message *msg,
struct dentry *old_dentry,
- struct dentry *new_dentry)
+ struct dentry *new_dentry,
+ struct inode *same_parent)
{
msg->rpc_proc = &nfs_procedures[NFSPROC_RENAME];
}
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 72dee6f3050e..57d372db03b9 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -1052,16 +1052,6 @@ int nfs_reconfigure(struct fs_context *fc)
sync_filesystem(sb);
/*
- * The SB_RDONLY flag has been removed from the superblock during
- * mounts to prevent interference between different filesystems.
- * Similarly, it is also necessary to ignore the SB_RDONLY flag
- * during reconfiguration; otherwise, it may also result in the
- * creation of redundant superblocks when mounting a directory with
- * different rw and ro flags multiple times.
- */
- fc->sb_flags_mask &= ~SB_RDONLY;
-
- /*
* Userspace mount programs that send binary options generally send
* them populated with default values. We have no way to know which
* ones were explicitly specified. Fall back to legacy behavior and
@@ -1101,8 +1091,9 @@ static void nfs_fill_super(struct super_block *sb, struct nfs_fs_context *ctx)
sb->s_blocksize = 0;
sb->s_xattr = server->nfs_client->cl_nfs_mod->xattr;
sb->s_op = server->nfs_client->cl_nfs_mod->sops;
- if (ctx->bsize)
- sb->s_blocksize = nfs_block_size(ctx->bsize, &sb->s_blocksize_bits);
+ if (server->bsize)
+ sb->s_blocksize =
+ nfs_block_size(server->bsize, &sb->s_blocksize_bits);
switch (server->nfs_client->rpc_ops->version) {
case 2:
@@ -1318,26 +1309,13 @@ int nfs_get_tree_common(struct fs_context *fc)
if (IS_ERR(server))
return PTR_ERR(server);
- /*
- * When NFS_MOUNT_UNSHARED is not set, NFS forces the sharing of a
- * superblock among each filesystem that mounts sub-directories
- * belonging to a single exported root path.
- * To prevent interference between different filesystems, the
- * SB_RDONLY flag should be removed from the superblock.
- */
if (server->flags & NFS_MOUNT_UNSHARED)
compare_super = NULL;
- else
- fc->sb_flags &= ~SB_RDONLY;
/* -o noac implies -o sync */
if (server->flags & NFS_MOUNT_NOAC)
fc->sb_flags |= SB_SYNCHRONOUS;
- if (ctx->clone_data.sb)
- if (ctx->clone_data.sb->s_flags & SB_SYNCHRONOUS)
- fc->sb_flags |= SB_SYNCHRONOUS;
-
/* Get a superblock - note that we may end up sharing one that already exists */
fc->s_fs_info = server;
s = sget_fc(fc, compare_super, nfs_set_super);
@@ -1361,13 +1339,8 @@ int nfs_get_tree_common(struct fs_context *fc)
}
if (!s->s_root) {
- unsigned bsize = ctx->clone_data.inherited_bsize;
/* initial superblock/root creation */
nfs_fill_super(s, ctx);
- if (bsize) {
- s->s_blocksize_bits = bsize;
- s->s_blocksize = 1U << bsize;
- }
error = nfs_get_cache_cookie(s, ctx);
if (error < 0)
goto error_splat_super;
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c
index b55467911648..4db818c0f9dd 100644
--- a/fs/nfs/unlink.c
+++ b/fs/nfs/unlink.c
@@ -390,7 +390,8 @@ nfs_async_rename(struct inode *old_dir, struct inode *new_dir,
nfs_sb_active(old_dir->i_sb);
- NFS_PROTO(data->old_dir)->rename_setup(&msg, old_dentry, new_dentry);
+ NFS_PROTO(data->old_dir)->rename_setup(&msg, old_dentry, new_dentry,
+ old_dir == new_dir ? old_dir : NULL);
return rpc_run_task(&task_setup_data);
}
diff --git a/fs/nls/nls_base.c b/fs/nls/nls_base.c
index 18d597e49a19..a5c3a9f1b8dc 100644
--- a/fs/nls/nls_base.c
+++ b/fs/nls/nls_base.c
@@ -67,19 +67,22 @@ int utf8_to_utf32(const u8 *s, int inlen, unicode_t *pu)
l &= t->lmask;
if (l < t->lval || l > UNICODE_MAX ||
(l & SURROGATE_MASK) == SURROGATE_PAIR)
- return -1;
+ return -EILSEQ;
+
*pu = (unicode_t) l;
return nc;
}
if (inlen <= nc)
- return -1;
+ return -EOVERFLOW;
+
s++;
c = (*s ^ 0x80) & 0xFF;
if (c & 0xC0)
- return -1;
+ return -EILSEQ;
+
l = (l << 6) | c;
}
- return -1;
+ return -EILSEQ;
}
EXPORT_SYMBOL(utf8_to_utf32);
@@ -94,7 +97,7 @@ int utf32_to_utf8(unicode_t u, u8 *s, int maxout)
l = u;
if (l > UNICODE_MAX || (l & SURROGATE_MASK) == SURROGATE_PAIR)
- return -1;
+ return -EILSEQ;
nc = 0;
for (t = utf8_table; t->cmask && maxout; t++, maxout--) {
@@ -110,7 +113,7 @@ int utf32_to_utf8(unicode_t u, u8 *s, int maxout)
return nc;
}
}
- return -1;
+ return -EOVERFLOW;
}
EXPORT_SYMBOL(utf32_to_utf8);
@@ -217,8 +220,16 @@ int utf16s_to_utf8s(const wchar_t *pwcs, int inlen, enum utf16_endian endian,
inlen--;
}
size = utf32_to_utf8(u, op, maxout);
- if (size == -1) {
- /* Ignore character and move on */
+ if (size < 0) {
+ if (size == -EILSEQ) {
+ /* Ignore character and move on */
+ continue;
+ }
+ /*
+ * Stop filling the buffer with data once a character
+ * does not fit anymore.
+ */
+ break;
} else {
op += size;
maxout -= size;
diff --git a/fs/smb/client/cifspdu.h b/fs/smb/client/cifspdu.h
index 37b23664ddf3..eeb4011cb217 100644
--- a/fs/smb/client/cifspdu.h
+++ b/fs/smb/client/cifspdu.h
@@ -1357,37 +1357,6 @@ typedef struct smb_com_transaction_change_notify_rsp {
__u16 ByteCount;
/* __u8 Pad[3]; */
} __packed TRANSACT_CHANGE_NOTIFY_RSP;
-/* Completion Filter flags for Notify */
-#define FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001
-#define FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002
-#define FILE_NOTIFY_CHANGE_NAME 0x00000003
-#define FILE_NOTIFY_CHANGE_ATTRIBUTES 0x00000004
-#define FILE_NOTIFY_CHANGE_SIZE 0x00000008
-#define FILE_NOTIFY_CHANGE_LAST_WRITE 0x00000010
-#define FILE_NOTIFY_CHANGE_LAST_ACCESS 0x00000020
-#define FILE_NOTIFY_CHANGE_CREATION 0x00000040
-#define FILE_NOTIFY_CHANGE_EA 0x00000080
-#define FILE_NOTIFY_CHANGE_SECURITY 0x00000100
-#define FILE_NOTIFY_CHANGE_STREAM_NAME 0x00000200
-#define FILE_NOTIFY_CHANGE_STREAM_SIZE 0x00000400
-#define FILE_NOTIFY_CHANGE_STREAM_WRITE 0x00000800
-
-#define FILE_ACTION_ADDED 0x00000001
-#define FILE_ACTION_REMOVED 0x00000002
-#define FILE_ACTION_MODIFIED 0x00000003
-#define FILE_ACTION_RENAMED_OLD_NAME 0x00000004
-#define FILE_ACTION_RENAMED_NEW_NAME 0x00000005
-#define FILE_ACTION_ADDED_STREAM 0x00000006
-#define FILE_ACTION_REMOVED_STREAM 0x00000007
-#define FILE_ACTION_MODIFIED_STREAM 0x00000008
-
-/* response contains array of the following structures */
-struct file_notify_information {
- __le32 NextEntryOffset;
- __le32 Action;
- __le32 FileNameLength;
- __u8 FileName[];
-} __packed;
struct cifs_quota_data {
__u32 rsrvd1; /* 0 */
@@ -2034,40 +2003,6 @@ typedef struct {
#define CIFS_POSIX_EXTENSIONS 0x00000010 /* support for new QFSInfo */
-/* DeviceType Flags */
-#define FILE_DEVICE_CD_ROM 0x00000002
-#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003
-#define FILE_DEVICE_DFS 0x00000006
-#define FILE_DEVICE_DISK 0x00000007
-#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008
-#define FILE_DEVICE_FILE_SYSTEM 0x00000009
-#define FILE_DEVICE_NAMED_PIPE 0x00000011
-#define FILE_DEVICE_NETWORK 0x00000012
-#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014
-#define FILE_DEVICE_NULL 0x00000015
-#define FILE_DEVICE_PARALLEL_PORT 0x00000016
-#define FILE_DEVICE_PRINTER 0x00000018
-#define FILE_DEVICE_SERIAL_PORT 0x0000001b
-#define FILE_DEVICE_STREAMS 0x0000001e
-#define FILE_DEVICE_TAPE 0x0000001f
-#define FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020
-#define FILE_DEVICE_VIRTUAL_DISK 0x00000024
-#define FILE_DEVICE_NETWORK_REDIRECTOR 0x00000028
-
-/* Device Characteristics */
-#define FILE_REMOVABLE_MEDIA 0x00000001
-#define FILE_READ_ONLY_DEVICE 0x00000002
-#define FILE_FLOPPY_DISKETTE 0x00000004
-#define FILE_WRITE_ONCE_MEDIA 0x00000008
-#define FILE_REMOTE_DEVICE 0x00000010
-#define FILE_DEVICE_IS_MOUNTED 0x00000020
-#define FILE_VIRTUAL_VOLUME 0x00000040
-#define FILE_DEVICE_SECURE_OPEN 0x00000100
-#define FILE_CHARACTERISTIC_TS_DEVICE 0x00001000
-#define FILE_CHARACTERISTIC_WEBDAV_DEVICE 0x00002000
-#define FILE_PORTABLE_DEVICE 0x00004000
-#define FILE_DEVICE_ALLOW_APPCONTAINER_TRAVERSAL 0x00020000
-
/******************************************************************************/
/* QueryFileInfo/QueryPathinfo (also for SetPath/SetFile) data buffer formats */
/******************************************************************************/
diff --git a/fs/smb/client/nterr.c b/fs/smb/client/nterr.c
index 8f0bc441295e..77f84767b7df 100644
--- a/fs/smb/client/nterr.c
+++ b/fs/smb/client/nterr.c
@@ -13,6 +13,7 @@
const struct nt_err_code_struct nt_errs[] = {
{"NT_STATUS_OK", NT_STATUS_OK},
+ {"NT_STATUS_PENDING", NT_STATUS_PENDING},
{"NT_STATUS_MEDIA_CHANGED", NT_STATUS_MEDIA_CHANGED},
{"NT_STATUS_END_OF_MEDIA", NT_STATUS_END_OF_MEDIA},
{"NT_STATUS_MEDIA_CHECK", NT_STATUS_MEDIA_CHECK},
@@ -544,6 +545,7 @@ const struct nt_err_code_struct nt_errs[] = {
{"NT_STATUS_DOMAIN_TRUST_INCONSISTENT",
NT_STATUS_DOMAIN_TRUST_INCONSISTENT},
{"NT_STATUS_FS_DRIVER_REQUIRED", NT_STATUS_FS_DRIVER_REQUIRED},
+ {"NT_STATUS_INVALID_LOCK_RANGE", NT_STATUS_INVALID_LOCK_RANGE},
{"NT_STATUS_NO_USER_SESSION_KEY", NT_STATUS_NO_USER_SESSION_KEY},
{"NT_STATUS_USER_SESSION_DELETED", NT_STATUS_USER_SESSION_DELETED},
{"NT_STATUS_RESOURCE_LANG_NOT_FOUND",
@@ -675,9 +677,12 @@ const struct nt_err_code_struct nt_errs[] = {
NT_STATUS_QUOTA_LIST_INCONSISTENT},
{"NT_STATUS_FILE_IS_OFFLINE", NT_STATUS_FILE_IS_OFFLINE},
{"NT_STATUS_NOT_A_REPARSE_POINT", NT_STATUS_NOT_A_REPARSE_POINT},
+ {"NT_STATUS_NETWORK_SESSION_EXPIRED", NT_STATUS_NETWORK_SESSION_EXPIRED},
{"NT_STATUS_NO_MORE_ENTRIES", NT_STATUS_NO_MORE_ENTRIES},
{"NT_STATUS_MORE_ENTRIES", NT_STATUS_MORE_ENTRIES},
{"NT_STATUS_SOME_UNMAPPED", NT_STATUS_SOME_UNMAPPED},
{"NT_STATUS_NO_SUCH_JOB", NT_STATUS_NO_SUCH_JOB},
+ {"NT_STATUS_NO_PREAUTH_INTEGRITY_HASH_OVERLAP",
+ NT_STATUS_NO_PREAUTH_INTEGRITY_HASH_OVERLAP},
{NULL, 0}
};
diff --git a/fs/smb/client/nterr.h b/fs/smb/client/nterr.h
index 180602c22355..81f1a78cf41f 100644
--- a/fs/smb/client/nterr.h
+++ b/fs/smb/client/nterr.h
@@ -35,518 +35,522 @@ extern const struct nt_err_code_struct nt_errs[];
*/
#define NT_STATUS_OK 0x0000
+#define NT_STATUS_PENDING 0x0103
#define NT_STATUS_SOME_UNMAPPED 0x0107
#define NT_STATUS_BUFFER_OVERFLOW 0x80000005
#define NT_STATUS_NO_MORE_ENTRIES 0x8000001a
#define NT_STATUS_MEDIA_CHANGED 0x8000001c
#define NT_STATUS_END_OF_MEDIA 0x8000001e
#define NT_STATUS_MEDIA_CHECK 0x80000020
-#define NT_STATUS_NO_DATA_DETECTED 0x8000001c
+#define NT_STATUS_NO_DATA_DETECTED 0x80000022
#define NT_STATUS_STOPPED_ON_SYMLINK 0x8000002d
#define NT_STATUS_DEVICE_REQUIRES_CLEANING 0x80000288
-#define NT_STATUS_DEVICE_DOOR_OPEN 0x80000288
-#define NT_STATUS_UNSUCCESSFUL 0xC0000000 | 0x0001
-#define NT_STATUS_NOT_IMPLEMENTED 0xC0000000 | 0x0002
-#define NT_STATUS_INVALID_INFO_CLASS 0xC0000000 | 0x0003
-#define NT_STATUS_INFO_LENGTH_MISMATCH 0xC0000000 | 0x0004
-#define NT_STATUS_ACCESS_VIOLATION 0xC0000000 | 0x0005
-#define NT_STATUS_IN_PAGE_ERROR 0xC0000000 | 0x0006
-#define NT_STATUS_PAGEFILE_QUOTA 0xC0000000 | 0x0007
-#define NT_STATUS_INVALID_HANDLE 0xC0000000 | 0x0008
-#define NT_STATUS_BAD_INITIAL_STACK 0xC0000000 | 0x0009
-#define NT_STATUS_BAD_INITIAL_PC 0xC0000000 | 0x000a
-#define NT_STATUS_INVALID_CID 0xC0000000 | 0x000b
-#define NT_STATUS_TIMER_NOT_CANCELED 0xC0000000 | 0x000c
-#define NT_STATUS_INVALID_PARAMETER 0xC0000000 | 0x000d
-#define NT_STATUS_NO_SUCH_DEVICE 0xC0000000 | 0x000e
-#define NT_STATUS_NO_SUCH_FILE 0xC0000000 | 0x000f
-#define NT_STATUS_INVALID_DEVICE_REQUEST 0xC0000000 | 0x0010
-#define NT_STATUS_END_OF_FILE 0xC0000000 | 0x0011
-#define NT_STATUS_WRONG_VOLUME 0xC0000000 | 0x0012
-#define NT_STATUS_NO_MEDIA_IN_DEVICE 0xC0000000 | 0x0013
-#define NT_STATUS_UNRECOGNIZED_MEDIA 0xC0000000 | 0x0014
-#define NT_STATUS_NONEXISTENT_SECTOR 0xC0000000 | 0x0015
-#define NT_STATUS_MORE_PROCESSING_REQUIRED 0xC0000000 | 0x0016
-#define NT_STATUS_NO_MEMORY 0xC0000000 | 0x0017
-#define NT_STATUS_CONFLICTING_ADDRESSES 0xC0000000 | 0x0018
-#define NT_STATUS_NOT_MAPPED_VIEW 0xC0000000 | 0x0019
-#define NT_STATUS_UNABLE_TO_FREE_VM 0x80000000 | 0x001a
-#define NT_STATUS_UNABLE_TO_DELETE_SECTION 0xC0000000 | 0x001b
-#define NT_STATUS_INVALID_SYSTEM_SERVICE 0xC0000000 | 0x001c
-#define NT_STATUS_ILLEGAL_INSTRUCTION 0xC0000000 | 0x001d
-#define NT_STATUS_INVALID_LOCK_SEQUENCE 0xC0000000 | 0x001e
-#define NT_STATUS_INVALID_VIEW_SIZE 0xC0000000 | 0x001f
-#define NT_STATUS_INVALID_FILE_FOR_SECTION 0xC0000000 | 0x0020
-#define NT_STATUS_ALREADY_COMMITTED 0xC0000000 | 0x0021
-#define NT_STATUS_ACCESS_DENIED 0xC0000000 | 0x0022
-#define NT_STATUS_BUFFER_TOO_SMALL 0xC0000000 | 0x0023
-#define NT_STATUS_OBJECT_TYPE_MISMATCH 0xC0000000 | 0x0024
-#define NT_STATUS_NONCONTINUABLE_EXCEPTION 0xC0000000 | 0x0025
-#define NT_STATUS_INVALID_DISPOSITION 0xC0000000 | 0x0026
-#define NT_STATUS_UNWIND 0xC0000000 | 0x0027
-#define NT_STATUS_BAD_STACK 0xC0000000 | 0x0028
-#define NT_STATUS_INVALID_UNWIND_TARGET 0xC0000000 | 0x0029
-#define NT_STATUS_NOT_LOCKED 0xC0000000 | 0x002a
-#define NT_STATUS_PARITY_ERROR 0xC0000000 | 0x002b
-#define NT_STATUS_UNABLE_TO_DECOMMIT_VM 0xC0000000 | 0x002c
-#define NT_STATUS_NOT_COMMITTED 0xC0000000 | 0x002d
-#define NT_STATUS_INVALID_PORT_ATTRIBUTES 0xC0000000 | 0x002e
-#define NT_STATUS_PORT_MESSAGE_TOO_LONG 0xC0000000 | 0x002f
-#define NT_STATUS_INVALID_PARAMETER_MIX 0xC0000000 | 0x0030
-#define NT_STATUS_INVALID_QUOTA_LOWER 0xC0000000 | 0x0031
-#define NT_STATUS_DISK_CORRUPT_ERROR 0xC0000000 | 0x0032
-#define NT_STATUS_OBJECT_NAME_INVALID 0xC0000000 | 0x0033
-#define NT_STATUS_OBJECT_NAME_NOT_FOUND 0xC0000000 | 0x0034
-#define NT_STATUS_OBJECT_NAME_COLLISION 0xC0000000 | 0x0035
-#define NT_STATUS_HANDLE_NOT_WAITABLE 0xC0000000 | 0x0036
-#define NT_STATUS_PORT_DISCONNECTED 0xC0000000 | 0x0037
-#define NT_STATUS_DEVICE_ALREADY_ATTACHED 0xC0000000 | 0x0038
-#define NT_STATUS_OBJECT_PATH_INVALID 0xC0000000 | 0x0039
-#define NT_STATUS_OBJECT_PATH_NOT_FOUND 0xC0000000 | 0x003a
-#define NT_STATUS_OBJECT_PATH_SYNTAX_BAD 0xC0000000 | 0x003b
-#define NT_STATUS_DATA_OVERRUN 0xC0000000 | 0x003c
-#define NT_STATUS_DATA_LATE_ERROR 0xC0000000 | 0x003d
-#define NT_STATUS_DATA_ERROR 0xC0000000 | 0x003e
-#define NT_STATUS_CRC_ERROR 0xC0000000 | 0x003f
-#define NT_STATUS_SECTION_TOO_BIG 0xC0000000 | 0x0040
-#define NT_STATUS_PORT_CONNECTION_REFUSED 0xC0000000 | 0x0041
-#define NT_STATUS_INVALID_PORT_HANDLE 0xC0000000 | 0x0042
-#define NT_STATUS_SHARING_VIOLATION 0xC0000000 | 0x0043
-#define NT_STATUS_QUOTA_EXCEEDED 0xC0000000 | 0x0044
-#define NT_STATUS_INVALID_PAGE_PROTECTION 0xC0000000 | 0x0045
-#define NT_STATUS_MUTANT_NOT_OWNED 0xC0000000 | 0x0046
-#define NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED 0xC0000000 | 0x0047
-#define NT_STATUS_PORT_ALREADY_SET 0xC0000000 | 0x0048
-#define NT_STATUS_SECTION_NOT_IMAGE 0xC0000000 | 0x0049
-#define NT_STATUS_SUSPEND_COUNT_EXCEEDED 0xC0000000 | 0x004a
-#define NT_STATUS_THREAD_IS_TERMINATING 0xC0000000 | 0x004b
-#define NT_STATUS_BAD_WORKING_SET_LIMIT 0xC0000000 | 0x004c
-#define NT_STATUS_INCOMPATIBLE_FILE_MAP 0xC0000000 | 0x004d
-#define NT_STATUS_SECTION_PROTECTION 0xC0000000 | 0x004e
-#define NT_STATUS_EAS_NOT_SUPPORTED 0xC0000000 | 0x004f
-#define NT_STATUS_EA_TOO_LARGE 0xC0000000 | 0x0050
-#define NT_STATUS_NONEXISTENT_EA_ENTRY 0xC0000000 | 0x0051
-#define NT_STATUS_NO_EAS_ON_FILE 0xC0000000 | 0x0052
-#define NT_STATUS_EA_CORRUPT_ERROR 0xC0000000 | 0x0053
-#define NT_STATUS_FILE_LOCK_CONFLICT 0xC0000000 | 0x0054
-#define NT_STATUS_LOCK_NOT_GRANTED 0xC0000000 | 0x0055
-#define NT_STATUS_DELETE_PENDING 0xC0000000 | 0x0056
-#define NT_STATUS_CTL_FILE_NOT_SUPPORTED 0xC0000000 | 0x0057
-#define NT_STATUS_UNKNOWN_REVISION 0xC0000000 | 0x0058
-#define NT_STATUS_REVISION_MISMATCH 0xC0000000 | 0x0059
-#define NT_STATUS_INVALID_OWNER 0xC0000000 | 0x005a
-#define NT_STATUS_INVALID_PRIMARY_GROUP 0xC0000000 | 0x005b
-#define NT_STATUS_NO_IMPERSONATION_TOKEN 0xC0000000 | 0x005c
-#define NT_STATUS_CANT_DISABLE_MANDATORY 0xC0000000 | 0x005d
-#define NT_STATUS_NO_LOGON_SERVERS 0xC0000000 | 0x005e
-#define NT_STATUS_NO_SUCH_LOGON_SESSION 0xC0000000 | 0x005f
-#define NT_STATUS_NO_SUCH_PRIVILEGE 0xC0000000 | 0x0060
-#define NT_STATUS_PRIVILEGE_NOT_HELD 0xC0000000 | 0x0061
-#define NT_STATUS_INVALID_ACCOUNT_NAME 0xC0000000 | 0x0062
-#define NT_STATUS_USER_EXISTS 0xC0000000 | 0x0063
-#define NT_STATUS_NO_SUCH_USER 0xC0000000 | 0x0064
-#define NT_STATUS_GROUP_EXISTS 0xC0000000 | 0x0065
-#define NT_STATUS_NO_SUCH_GROUP 0xC0000000 | 0x0066
-#define NT_STATUS_MEMBER_IN_GROUP 0xC0000000 | 0x0067
-#define NT_STATUS_MEMBER_NOT_IN_GROUP 0xC0000000 | 0x0068
-#define NT_STATUS_LAST_ADMIN 0xC0000000 | 0x0069
-#define NT_STATUS_WRONG_PASSWORD 0xC0000000 | 0x006a
-#define NT_STATUS_ILL_FORMED_PASSWORD 0xC0000000 | 0x006b
-#define NT_STATUS_PASSWORD_RESTRICTION 0xC0000000 | 0x006c
-#define NT_STATUS_LOGON_FAILURE 0xC0000000 | 0x006d
-#define NT_STATUS_ACCOUNT_RESTRICTION 0xC0000000 | 0x006e
-#define NT_STATUS_INVALID_LOGON_HOURS 0xC0000000 | 0x006f
-#define NT_STATUS_INVALID_WORKSTATION 0xC0000000 | 0x0070
-#define NT_STATUS_PASSWORD_EXPIRED 0xC0000000 | 0x0071
-#define NT_STATUS_ACCOUNT_DISABLED 0xC0000000 | 0x0072
-#define NT_STATUS_NONE_MAPPED 0xC0000000 | 0x0073
-#define NT_STATUS_TOO_MANY_LUIDS_REQUESTED 0xC0000000 | 0x0074
-#define NT_STATUS_LUIDS_EXHAUSTED 0xC0000000 | 0x0075
-#define NT_STATUS_INVALID_SUB_AUTHORITY 0xC0000000 | 0x0076
-#define NT_STATUS_INVALID_ACL 0xC0000000 | 0x0077
-#define NT_STATUS_INVALID_SID 0xC0000000 | 0x0078
-#define NT_STATUS_INVALID_SECURITY_DESCR 0xC0000000 | 0x0079
-#define NT_STATUS_PROCEDURE_NOT_FOUND 0xC0000000 | 0x007a
-#define NT_STATUS_INVALID_IMAGE_FORMAT 0xC0000000 | 0x007b
-#define NT_STATUS_NO_TOKEN 0xC0000000 | 0x007c
-#define NT_STATUS_BAD_INHERITANCE_ACL 0xC0000000 | 0x007d
-#define NT_STATUS_RANGE_NOT_LOCKED 0xC0000000 | 0x007e
-#define NT_STATUS_DISK_FULL 0xC0000000 | 0x007f
-#define NT_STATUS_SERVER_DISABLED 0xC0000000 | 0x0080
-#define NT_STATUS_SERVER_NOT_DISABLED 0xC0000000 | 0x0081
-#define NT_STATUS_TOO_MANY_GUIDS_REQUESTED 0xC0000000 | 0x0082
-#define NT_STATUS_GUIDS_EXHAUSTED 0xC0000000 | 0x0083
-#define NT_STATUS_INVALID_ID_AUTHORITY 0xC0000000 | 0x0084
-#define NT_STATUS_AGENTS_EXHAUSTED 0xC0000000 | 0x0085
-#define NT_STATUS_INVALID_VOLUME_LABEL 0xC0000000 | 0x0086
-#define NT_STATUS_SECTION_NOT_EXTENDED 0xC0000000 | 0x0087
-#define NT_STATUS_NOT_MAPPED_DATA 0xC0000000 | 0x0088
-#define NT_STATUS_RESOURCE_DATA_NOT_FOUND 0xC0000000 | 0x0089
-#define NT_STATUS_RESOURCE_TYPE_NOT_FOUND 0xC0000000 | 0x008a
-#define NT_STATUS_RESOURCE_NAME_NOT_FOUND 0xC0000000 | 0x008b
-#define NT_STATUS_ARRAY_BOUNDS_EXCEEDED 0xC0000000 | 0x008c
-#define NT_STATUS_FLOAT_DENORMAL_OPERAND 0xC0000000 | 0x008d
-#define NT_STATUS_FLOAT_DIVIDE_BY_ZERO 0xC0000000 | 0x008e
-#define NT_STATUS_FLOAT_INEXACT_RESULT 0xC0000000 | 0x008f
-#define NT_STATUS_FLOAT_INVALID_OPERATION 0xC0000000 | 0x0090
-#define NT_STATUS_FLOAT_OVERFLOW 0xC0000000 | 0x0091
-#define NT_STATUS_FLOAT_STACK_CHECK 0xC0000000 | 0x0092
-#define NT_STATUS_FLOAT_UNDERFLOW 0xC0000000 | 0x0093
-#define NT_STATUS_INTEGER_DIVIDE_BY_ZERO 0xC0000000 | 0x0094
-#define NT_STATUS_INTEGER_OVERFLOW 0xC0000000 | 0x0095
-#define NT_STATUS_PRIVILEGED_INSTRUCTION 0xC0000000 | 0x0096
-#define NT_STATUS_TOO_MANY_PAGING_FILES 0xC0000000 | 0x0097
-#define NT_STATUS_FILE_INVALID 0xC0000000 | 0x0098
-#define NT_STATUS_ALLOTTED_SPACE_EXCEEDED 0xC0000000 | 0x0099
-#define NT_STATUS_INSUFFICIENT_RESOURCES 0xC0000000 | 0x009a
-#define NT_STATUS_DFS_EXIT_PATH_FOUND 0xC0000000 | 0x009b
-#define NT_STATUS_DEVICE_DATA_ERROR 0xC0000000 | 0x009c
-#define NT_STATUS_DEVICE_NOT_CONNECTED 0xC0000000 | 0x009d
-#define NT_STATUS_DEVICE_POWER_FAILURE 0xC0000000 | 0x009e
-#define NT_STATUS_FREE_VM_NOT_AT_BASE 0xC0000000 | 0x009f
-#define NT_STATUS_MEMORY_NOT_ALLOCATED 0xC0000000 | 0x00a0
-#define NT_STATUS_WORKING_SET_QUOTA 0xC0000000 | 0x00a1
-#define NT_STATUS_MEDIA_WRITE_PROTECTED 0xC0000000 | 0x00a2
-#define NT_STATUS_DEVICE_NOT_READY 0xC0000000 | 0x00a3
-#define NT_STATUS_INVALID_GROUP_ATTRIBUTES 0xC0000000 | 0x00a4
-#define NT_STATUS_BAD_IMPERSONATION_LEVEL 0xC0000000 | 0x00a5
-#define NT_STATUS_CANT_OPEN_ANONYMOUS 0xC0000000 | 0x00a6
-#define NT_STATUS_BAD_VALIDATION_CLASS 0xC0000000 | 0x00a7
-#define NT_STATUS_BAD_TOKEN_TYPE 0xC0000000 | 0x00a8
-#define NT_STATUS_BAD_MASTER_BOOT_RECORD 0xC0000000 | 0x00a9
-#define NT_STATUS_INSTRUCTION_MISALIGNMENT 0xC0000000 | 0x00aa
-#define NT_STATUS_INSTANCE_NOT_AVAILABLE 0xC0000000 | 0x00ab
-#define NT_STATUS_PIPE_NOT_AVAILABLE 0xC0000000 | 0x00ac
-#define NT_STATUS_INVALID_PIPE_STATE 0xC0000000 | 0x00ad
-#define NT_STATUS_PIPE_BUSY 0xC0000000 | 0x00ae
-#define NT_STATUS_ILLEGAL_FUNCTION 0xC0000000 | 0x00af
-#define NT_STATUS_PIPE_DISCONNECTED 0xC0000000 | 0x00b0
-#define NT_STATUS_PIPE_CLOSING 0xC0000000 | 0x00b1
-#define NT_STATUS_PIPE_CONNECTED 0xC0000000 | 0x00b2
-#define NT_STATUS_PIPE_LISTENING 0xC0000000 | 0x00b3
-#define NT_STATUS_INVALID_READ_MODE 0xC0000000 | 0x00b4
-#define NT_STATUS_IO_TIMEOUT 0xC0000000 | 0x00b5
-#define NT_STATUS_FILE_FORCED_CLOSED 0xC0000000 | 0x00b6
-#define NT_STATUS_PROFILING_NOT_STARTED 0xC0000000 | 0x00b7
-#define NT_STATUS_PROFILING_NOT_STOPPED 0xC0000000 | 0x00b8
-#define NT_STATUS_COULD_NOT_INTERPRET 0xC0000000 | 0x00b9
-#define NT_STATUS_FILE_IS_A_DIRECTORY 0xC0000000 | 0x00ba
-#define NT_STATUS_NOT_SUPPORTED 0xC0000000 | 0x00bb
-#define NT_STATUS_REMOTE_NOT_LISTENING 0xC0000000 | 0x00bc
-#define NT_STATUS_DUPLICATE_NAME 0xC0000000 | 0x00bd
-#define NT_STATUS_BAD_NETWORK_PATH 0xC0000000 | 0x00be
-#define NT_STATUS_NETWORK_BUSY 0xC0000000 | 0x00bf
-#define NT_STATUS_DEVICE_DOES_NOT_EXIST 0xC0000000 | 0x00c0
-#define NT_STATUS_TOO_MANY_COMMANDS 0xC0000000 | 0x00c1
-#define NT_STATUS_ADAPTER_HARDWARE_ERROR 0xC0000000 | 0x00c2
-#define NT_STATUS_INVALID_NETWORK_RESPONSE 0xC0000000 | 0x00c3
-#define NT_STATUS_UNEXPECTED_NETWORK_ERROR 0xC0000000 | 0x00c4
-#define NT_STATUS_BAD_REMOTE_ADAPTER 0xC0000000 | 0x00c5
-#define NT_STATUS_PRINT_QUEUE_FULL 0xC0000000 | 0x00c6
-#define NT_STATUS_NO_SPOOL_SPACE 0xC0000000 | 0x00c7
-#define NT_STATUS_PRINT_CANCELLED 0xC0000000 | 0x00c8
-#define NT_STATUS_NETWORK_NAME_DELETED 0xC0000000 | 0x00c9
-#define NT_STATUS_NETWORK_ACCESS_DENIED 0xC0000000 | 0x00ca
-#define NT_STATUS_BAD_DEVICE_TYPE 0xC0000000 | 0x00cb
-#define NT_STATUS_BAD_NETWORK_NAME 0xC0000000 | 0x00cc
-#define NT_STATUS_TOO_MANY_NAMES 0xC0000000 | 0x00cd
-#define NT_STATUS_TOO_MANY_SESSIONS 0xC0000000 | 0x00ce
-#define NT_STATUS_SHARING_PAUSED 0xC0000000 | 0x00cf
-#define NT_STATUS_REQUEST_NOT_ACCEPTED 0xC0000000 | 0x00d0
-#define NT_STATUS_REDIRECTOR_PAUSED 0xC0000000 | 0x00d1
-#define NT_STATUS_NET_WRITE_FAULT 0xC0000000 | 0x00d2
-#define NT_STATUS_PROFILING_AT_LIMIT 0xC0000000 | 0x00d3
-#define NT_STATUS_NOT_SAME_DEVICE 0xC0000000 | 0x00d4
-#define NT_STATUS_FILE_RENAMED 0xC0000000 | 0x00d5
-#define NT_STATUS_VIRTUAL_CIRCUIT_CLOSED 0xC0000000 | 0x00d6
-#define NT_STATUS_NO_SECURITY_ON_OBJECT 0xC0000000 | 0x00d7
-#define NT_STATUS_CANT_WAIT 0xC0000000 | 0x00d8
-#define NT_STATUS_PIPE_EMPTY 0xC0000000 | 0x00d9
-#define NT_STATUS_CANT_ACCESS_DOMAIN_INFO 0xC0000000 | 0x00da
-#define NT_STATUS_CANT_TERMINATE_SELF 0xC0000000 | 0x00db
-#define NT_STATUS_INVALID_SERVER_STATE 0xC0000000 | 0x00dc
-#define NT_STATUS_INVALID_DOMAIN_STATE 0xC0000000 | 0x00dd
-#define NT_STATUS_INVALID_DOMAIN_ROLE 0xC0000000 | 0x00de
-#define NT_STATUS_NO_SUCH_DOMAIN 0xC0000000 | 0x00df
-#define NT_STATUS_DOMAIN_EXISTS 0xC0000000 | 0x00e0
-#define NT_STATUS_DOMAIN_LIMIT_EXCEEDED 0xC0000000 | 0x00e1
-#define NT_STATUS_OPLOCK_NOT_GRANTED 0xC0000000 | 0x00e2
-#define NT_STATUS_INVALID_OPLOCK_PROTOCOL 0xC0000000 | 0x00e3
-#define NT_STATUS_INTERNAL_DB_CORRUPTION 0xC0000000 | 0x00e4
-#define NT_STATUS_INTERNAL_ERROR 0xC0000000 | 0x00e5
-#define NT_STATUS_GENERIC_NOT_MAPPED 0xC0000000 | 0x00e6
-#define NT_STATUS_BAD_DESCRIPTOR_FORMAT 0xC0000000 | 0x00e7
-#define NT_STATUS_INVALID_USER_BUFFER 0xC0000000 | 0x00e8
-#define NT_STATUS_UNEXPECTED_IO_ERROR 0xC0000000 | 0x00e9
-#define NT_STATUS_UNEXPECTED_MM_CREATE_ERR 0xC0000000 | 0x00ea
-#define NT_STATUS_UNEXPECTED_MM_MAP_ERROR 0xC0000000 | 0x00eb
-#define NT_STATUS_UNEXPECTED_MM_EXTEND_ERR 0xC0000000 | 0x00ec
-#define NT_STATUS_NOT_LOGON_PROCESS 0xC0000000 | 0x00ed
-#define NT_STATUS_LOGON_SESSION_EXISTS 0xC0000000 | 0x00ee
-#define NT_STATUS_INVALID_PARAMETER_1 0xC0000000 | 0x00ef
-#define NT_STATUS_INVALID_PARAMETER_2 0xC0000000 | 0x00f0
-#define NT_STATUS_INVALID_PARAMETER_3 0xC0000000 | 0x00f1
-#define NT_STATUS_INVALID_PARAMETER_4 0xC0000000 | 0x00f2
-#define NT_STATUS_INVALID_PARAMETER_5 0xC0000000 | 0x00f3
-#define NT_STATUS_INVALID_PARAMETER_6 0xC0000000 | 0x00f4
-#define NT_STATUS_INVALID_PARAMETER_7 0xC0000000 | 0x00f5
-#define NT_STATUS_INVALID_PARAMETER_8 0xC0000000 | 0x00f6
-#define NT_STATUS_INVALID_PARAMETER_9 0xC0000000 | 0x00f7
-#define NT_STATUS_INVALID_PARAMETER_10 0xC0000000 | 0x00f8
-#define NT_STATUS_INVALID_PARAMETER_11 0xC0000000 | 0x00f9
-#define NT_STATUS_INVALID_PARAMETER_12 0xC0000000 | 0x00fa
-#define NT_STATUS_REDIRECTOR_NOT_STARTED 0xC0000000 | 0x00fb
-#define NT_STATUS_REDIRECTOR_STARTED 0xC0000000 | 0x00fc
-#define NT_STATUS_STACK_OVERFLOW 0xC0000000 | 0x00fd
-#define NT_STATUS_NO_SUCH_PACKAGE 0xC0000000 | 0x00fe
-#define NT_STATUS_BAD_FUNCTION_TABLE 0xC0000000 | 0x00ff
-#define NT_STATUS_DIRECTORY_NOT_EMPTY 0xC0000000 | 0x0101
-#define NT_STATUS_FILE_CORRUPT_ERROR 0xC0000000 | 0x0102
-#define NT_STATUS_NOT_A_DIRECTORY 0xC0000000 | 0x0103
-#define NT_STATUS_BAD_LOGON_SESSION_STATE 0xC0000000 | 0x0104
-#define NT_STATUS_LOGON_SESSION_COLLISION 0xC0000000 | 0x0105
-#define NT_STATUS_NAME_TOO_LONG 0xC0000000 | 0x0106
-#define NT_STATUS_FILES_OPEN 0xC0000000 | 0x0107
-#define NT_STATUS_CONNECTION_IN_USE 0xC0000000 | 0x0108
-#define NT_STATUS_MESSAGE_NOT_FOUND 0xC0000000 | 0x0109
-#define NT_STATUS_PROCESS_IS_TERMINATING 0xC0000000 | 0x010a
-#define NT_STATUS_INVALID_LOGON_TYPE 0xC0000000 | 0x010b
-#define NT_STATUS_NO_GUID_TRANSLATION 0xC0000000 | 0x010c
-#define NT_STATUS_CANNOT_IMPERSONATE 0xC0000000 | 0x010d
-#define NT_STATUS_IMAGE_ALREADY_LOADED 0xC0000000 | 0x010e
-#define NT_STATUS_ABIOS_NOT_PRESENT 0xC0000000 | 0x010f
-#define NT_STATUS_ABIOS_LID_NOT_EXIST 0xC0000000 | 0x0110
-#define NT_STATUS_ABIOS_LID_ALREADY_OWNED 0xC0000000 | 0x0111
-#define NT_STATUS_ABIOS_NOT_LID_OWNER 0xC0000000 | 0x0112
-#define NT_STATUS_ABIOS_INVALID_COMMAND 0xC0000000 | 0x0113
-#define NT_STATUS_ABIOS_INVALID_LID 0xC0000000 | 0x0114
-#define NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE 0xC0000000 | 0x0115
-#define NT_STATUS_ABIOS_INVALID_SELECTOR 0xC0000000 | 0x0116
-#define NT_STATUS_NO_LDT 0xC0000000 | 0x0117
-#define NT_STATUS_INVALID_LDT_SIZE 0xC0000000 | 0x0118
-#define NT_STATUS_INVALID_LDT_OFFSET 0xC0000000 | 0x0119
-#define NT_STATUS_INVALID_LDT_DESCRIPTOR 0xC0000000 | 0x011a
-#define NT_STATUS_INVALID_IMAGE_NE_FORMAT 0xC0000000 | 0x011b
-#define NT_STATUS_RXACT_INVALID_STATE 0xC0000000 | 0x011c
-#define NT_STATUS_RXACT_COMMIT_FAILURE 0xC0000000 | 0x011d
-#define NT_STATUS_MAPPED_FILE_SIZE_ZERO 0xC0000000 | 0x011e
-#define NT_STATUS_TOO_MANY_OPENED_FILES 0xC0000000 | 0x011f
-#define NT_STATUS_CANCELLED 0xC0000000 | 0x0120
-#define NT_STATUS_CANNOT_DELETE 0xC0000000 | 0x0121
-#define NT_STATUS_INVALID_COMPUTER_NAME 0xC0000000 | 0x0122
-#define NT_STATUS_FILE_DELETED 0xC0000000 | 0x0123
-#define NT_STATUS_SPECIAL_ACCOUNT 0xC0000000 | 0x0124
-#define NT_STATUS_SPECIAL_GROUP 0xC0000000 | 0x0125
-#define NT_STATUS_SPECIAL_USER 0xC0000000 | 0x0126
-#define NT_STATUS_MEMBERS_PRIMARY_GROUP 0xC0000000 | 0x0127
-#define NT_STATUS_FILE_CLOSED 0xC0000000 | 0x0128
-#define NT_STATUS_TOO_MANY_THREADS 0xC0000000 | 0x0129
-#define NT_STATUS_THREAD_NOT_IN_PROCESS 0xC0000000 | 0x012a
-#define NT_STATUS_TOKEN_ALREADY_IN_USE 0xC0000000 | 0x012b
-#define NT_STATUS_PAGEFILE_QUOTA_EXCEEDED 0xC0000000 | 0x012c
-#define NT_STATUS_COMMITMENT_LIMIT 0xC0000000 | 0x012d
-#define NT_STATUS_INVALID_IMAGE_LE_FORMAT 0xC0000000 | 0x012e
-#define NT_STATUS_INVALID_IMAGE_NOT_MZ 0xC0000000 | 0x012f
-#define NT_STATUS_INVALID_IMAGE_PROTECT 0xC0000000 | 0x0130
-#define NT_STATUS_INVALID_IMAGE_WIN_16 0xC0000000 | 0x0131
-#define NT_STATUS_LOGON_SERVER_CONFLICT 0xC0000000 | 0x0132
-#define NT_STATUS_TIME_DIFFERENCE_AT_DC 0xC0000000 | 0x0133
-#define NT_STATUS_SYNCHRONIZATION_REQUIRED 0xC0000000 | 0x0134
-#define NT_STATUS_DLL_NOT_FOUND 0xC0000000 | 0x0135
-#define NT_STATUS_OPEN_FAILED 0xC0000000 | 0x0136
-#define NT_STATUS_IO_PRIVILEGE_FAILED 0xC0000000 | 0x0137
-#define NT_STATUS_ORDINAL_NOT_FOUND 0xC0000000 | 0x0138
-#define NT_STATUS_ENTRYPOINT_NOT_FOUND 0xC0000000 | 0x0139
-#define NT_STATUS_CONTROL_C_EXIT 0xC0000000 | 0x013a
-#define NT_STATUS_LOCAL_DISCONNECT 0xC0000000 | 0x013b
-#define NT_STATUS_REMOTE_DISCONNECT 0xC0000000 | 0x013c
-#define NT_STATUS_REMOTE_RESOURCES 0xC0000000 | 0x013d
-#define NT_STATUS_LINK_FAILED 0xC0000000 | 0x013e
-#define NT_STATUS_LINK_TIMEOUT 0xC0000000 | 0x013f
-#define NT_STATUS_INVALID_CONNECTION 0xC0000000 | 0x0140
-#define NT_STATUS_INVALID_ADDRESS 0xC0000000 | 0x0141
-#define NT_STATUS_DLL_INIT_FAILED 0xC0000000 | 0x0142
-#define NT_STATUS_MISSING_SYSTEMFILE 0xC0000000 | 0x0143
-#define NT_STATUS_UNHANDLED_EXCEPTION 0xC0000000 | 0x0144
-#define NT_STATUS_APP_INIT_FAILURE 0xC0000000 | 0x0145
-#define NT_STATUS_PAGEFILE_CREATE_FAILED 0xC0000000 | 0x0146
-#define NT_STATUS_NO_PAGEFILE 0xC0000000 | 0x0147
-#define NT_STATUS_INVALID_LEVEL 0xC0000000 | 0x0148
-#define NT_STATUS_WRONG_PASSWORD_CORE 0xC0000000 | 0x0149
-#define NT_STATUS_ILLEGAL_FLOAT_CONTEXT 0xC0000000 | 0x014a
-#define NT_STATUS_PIPE_BROKEN 0xC0000000 | 0x014b
-#define NT_STATUS_REGISTRY_CORRUPT 0xC0000000 | 0x014c
-#define NT_STATUS_REGISTRY_IO_FAILED 0xC0000000 | 0x014d
-#define NT_STATUS_NO_EVENT_PAIR 0xC0000000 | 0x014e
-#define NT_STATUS_UNRECOGNIZED_VOLUME 0xC0000000 | 0x014f
-#define NT_STATUS_SERIAL_NO_DEVICE_INITED 0xC0000000 | 0x0150
-#define NT_STATUS_NO_SUCH_ALIAS 0xC0000000 | 0x0151
-#define NT_STATUS_MEMBER_NOT_IN_ALIAS 0xC0000000 | 0x0152
-#define NT_STATUS_MEMBER_IN_ALIAS 0xC0000000 | 0x0153
-#define NT_STATUS_ALIAS_EXISTS 0xC0000000 | 0x0154
-#define NT_STATUS_LOGON_NOT_GRANTED 0xC0000000 | 0x0155
-#define NT_STATUS_TOO_MANY_SECRETS 0xC0000000 | 0x0156
-#define NT_STATUS_SECRET_TOO_LONG 0xC0000000 | 0x0157
-#define NT_STATUS_INTERNAL_DB_ERROR 0xC0000000 | 0x0158
-#define NT_STATUS_FULLSCREEN_MODE 0xC0000000 | 0x0159
-#define NT_STATUS_TOO_MANY_CONTEXT_IDS 0xC0000000 | 0x015a
-#define NT_STATUS_LOGON_TYPE_NOT_GRANTED 0xC0000000 | 0x015b
-#define NT_STATUS_NOT_REGISTRY_FILE 0xC0000000 | 0x015c
-#define NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED 0xC0000000 | 0x015d
-#define NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR 0xC0000000 | 0x015e
-#define NT_STATUS_FT_MISSING_MEMBER 0xC0000000 | 0x015f
-#define NT_STATUS_ILL_FORMED_SERVICE_ENTRY 0xC0000000 | 0x0160
-#define NT_STATUS_ILLEGAL_CHARACTER 0xC0000000 | 0x0161
-#define NT_STATUS_UNMAPPABLE_CHARACTER 0xC0000000 | 0x0162
-#define NT_STATUS_UNDEFINED_CHARACTER 0xC0000000 | 0x0163
-#define NT_STATUS_FLOPPY_VOLUME 0xC0000000 | 0x0164
-#define NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND 0xC0000000 | 0x0165
-#define NT_STATUS_FLOPPY_WRONG_CYLINDER 0xC0000000 | 0x0166
-#define NT_STATUS_FLOPPY_UNKNOWN_ERROR 0xC0000000 | 0x0167
-#define NT_STATUS_FLOPPY_BAD_REGISTERS 0xC0000000 | 0x0168
-#define NT_STATUS_DISK_RECALIBRATE_FAILED 0xC0000000 | 0x0169
-#define NT_STATUS_DISK_OPERATION_FAILED 0xC0000000 | 0x016a
-#define NT_STATUS_DISK_RESET_FAILED 0xC0000000 | 0x016b
-#define NT_STATUS_SHARED_IRQ_BUSY 0xC0000000 | 0x016c
-#define NT_STATUS_FT_ORPHANING 0xC0000000 | 0x016d
-#define NT_STATUS_PARTITION_FAILURE 0xC0000000 | 0x0172
-#define NT_STATUS_INVALID_BLOCK_LENGTH 0xC0000000 | 0x0173
-#define NT_STATUS_DEVICE_NOT_PARTITIONED 0xC0000000 | 0x0174
-#define NT_STATUS_UNABLE_TO_LOCK_MEDIA 0xC0000000 | 0x0175
-#define NT_STATUS_UNABLE_TO_UNLOAD_MEDIA 0xC0000000 | 0x0176
-#define NT_STATUS_EOM_OVERFLOW 0xC0000000 | 0x0177
-#define NT_STATUS_NO_MEDIA 0xC0000000 | 0x0178
-#define NT_STATUS_NO_SUCH_MEMBER 0xC0000000 | 0x017a
-#define NT_STATUS_INVALID_MEMBER 0xC0000000 | 0x017b
-#define NT_STATUS_KEY_DELETED 0xC0000000 | 0x017c
-#define NT_STATUS_NO_LOG_SPACE 0xC0000000 | 0x017d
-#define NT_STATUS_TOO_MANY_SIDS 0xC0000000 | 0x017e
-#define NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED 0xC0000000 | 0x017f
-#define NT_STATUS_KEY_HAS_CHILDREN 0xC0000000 | 0x0180
-#define NT_STATUS_CHILD_MUST_BE_VOLATILE 0xC0000000 | 0x0181
-#define NT_STATUS_DEVICE_CONFIGURATION_ERROR 0xC0000000 | 0x0182
-#define NT_STATUS_DRIVER_INTERNAL_ERROR 0xC0000000 | 0x0183
-#define NT_STATUS_INVALID_DEVICE_STATE 0xC0000000 | 0x0184
-#define NT_STATUS_IO_DEVICE_ERROR 0xC0000000 | 0x0185
-#define NT_STATUS_DEVICE_PROTOCOL_ERROR 0xC0000000 | 0x0186
-#define NT_STATUS_BACKUP_CONTROLLER 0xC0000000 | 0x0187
-#define NT_STATUS_LOG_FILE_FULL 0xC0000000 | 0x0188
-#define NT_STATUS_TOO_LATE 0xC0000000 | 0x0189
-#define NT_STATUS_NO_TRUST_LSA_SECRET 0xC0000000 | 0x018a
-#define NT_STATUS_NO_TRUST_SAM_ACCOUNT 0xC0000000 | 0x018b
-#define NT_STATUS_TRUSTED_DOMAIN_FAILURE 0xC0000000 | 0x018c
-#define NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE 0xC0000000 | 0x018d
-#define NT_STATUS_EVENTLOG_FILE_CORRUPT 0xC0000000 | 0x018e
-#define NT_STATUS_EVENTLOG_CANT_START 0xC0000000 | 0x018f
-#define NT_STATUS_TRUST_FAILURE 0xC0000000 | 0x0190
-#define NT_STATUS_MUTANT_LIMIT_EXCEEDED 0xC0000000 | 0x0191
-#define NT_STATUS_NETLOGON_NOT_STARTED 0xC0000000 | 0x0192
-#define NT_STATUS_ACCOUNT_EXPIRED 0xC0000000 | 0x0193
-#define NT_STATUS_POSSIBLE_DEADLOCK 0xC0000000 | 0x0194
-#define NT_STATUS_NETWORK_CREDENTIAL_CONFLICT 0xC0000000 | 0x0195
-#define NT_STATUS_REMOTE_SESSION_LIMIT 0xC0000000 | 0x0196
-#define NT_STATUS_EVENTLOG_FILE_CHANGED 0xC0000000 | 0x0197
-#define NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT 0xC0000000 | 0x0198
-#define NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT 0xC0000000 | 0x0199
-#define NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT 0xC0000000 | 0x019a
-#define NT_STATUS_DOMAIN_TRUST_INCONSISTENT 0xC0000000 | 0x019b
-#define NT_STATUS_FS_DRIVER_REQUIRED 0xC0000000 | 0x019c
-#define NT_STATUS_NO_USER_SESSION_KEY 0xC0000000 | 0x0202
-#define NT_STATUS_USER_SESSION_DELETED 0xC0000000 | 0x0203
-#define NT_STATUS_RESOURCE_LANG_NOT_FOUND 0xC0000000 | 0x0204
-#define NT_STATUS_INSUFF_SERVER_RESOURCES 0xC0000000 | 0x0205
-#define NT_STATUS_INVALID_BUFFER_SIZE 0xC0000000 | 0x0206
-#define NT_STATUS_INVALID_ADDRESS_COMPONENT 0xC0000000 | 0x0207
-#define NT_STATUS_INVALID_ADDRESS_WILDCARD 0xC0000000 | 0x0208
-#define NT_STATUS_TOO_MANY_ADDRESSES 0xC0000000 | 0x0209
-#define NT_STATUS_ADDRESS_ALREADY_EXISTS 0xC0000000 | 0x020a
-#define NT_STATUS_ADDRESS_CLOSED 0xC0000000 | 0x020b
-#define NT_STATUS_CONNECTION_DISCONNECTED 0xC0000000 | 0x020c
-#define NT_STATUS_CONNECTION_RESET 0xC0000000 | 0x020d
-#define NT_STATUS_TOO_MANY_NODES 0xC0000000 | 0x020e
-#define NT_STATUS_TRANSACTION_ABORTED 0xC0000000 | 0x020f
-#define NT_STATUS_TRANSACTION_TIMED_OUT 0xC0000000 | 0x0210
-#define NT_STATUS_TRANSACTION_NO_RELEASE 0xC0000000 | 0x0211
-#define NT_STATUS_TRANSACTION_NO_MATCH 0xC0000000 | 0x0212
-#define NT_STATUS_TRANSACTION_RESPONDED 0xC0000000 | 0x0213
-#define NT_STATUS_TRANSACTION_INVALID_ID 0xC0000000 | 0x0214
-#define NT_STATUS_TRANSACTION_INVALID_TYPE 0xC0000000 | 0x0215
-#define NT_STATUS_NOT_SERVER_SESSION 0xC0000000 | 0x0216
-#define NT_STATUS_NOT_CLIENT_SESSION 0xC0000000 | 0x0217
-#define NT_STATUS_CANNOT_LOAD_REGISTRY_FILE 0xC0000000 | 0x0218
-#define NT_STATUS_DEBUG_ATTACH_FAILED 0xC0000000 | 0x0219
-#define NT_STATUS_SYSTEM_PROCESS_TERMINATED 0xC0000000 | 0x021a
-#define NT_STATUS_DATA_NOT_ACCEPTED 0xC0000000 | 0x021b
-#define NT_STATUS_NO_BROWSER_SERVERS_FOUND 0xC0000000 | 0x021c
-#define NT_STATUS_VDM_HARD_ERROR 0xC0000000 | 0x021d
-#define NT_STATUS_DRIVER_CANCEL_TIMEOUT 0xC0000000 | 0x021e
-#define NT_STATUS_REPLY_MESSAGE_MISMATCH 0xC0000000 | 0x021f
-#define NT_STATUS_MAPPED_ALIGNMENT 0xC0000000 | 0x0220
-#define NT_STATUS_IMAGE_CHECKSUM_MISMATCH 0xC0000000 | 0x0221
-#define NT_STATUS_LOST_WRITEBEHIND_DATA 0xC0000000 | 0x0222
-#define NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID 0xC0000000 | 0x0223
-#define NT_STATUS_PASSWORD_MUST_CHANGE 0xC0000000 | 0x0224
-#define NT_STATUS_NOT_FOUND 0xC0000000 | 0x0225
-#define NT_STATUS_NOT_TINY_STREAM 0xC0000000 | 0x0226
-#define NT_STATUS_RECOVERY_FAILURE 0xC0000000 | 0x0227
-#define NT_STATUS_STACK_OVERFLOW_READ 0xC0000000 | 0x0228
-#define NT_STATUS_FAIL_CHECK 0xC0000000 | 0x0229
-#define NT_STATUS_DUPLICATE_OBJECTID 0xC0000000 | 0x022a
-#define NT_STATUS_OBJECTID_EXISTS 0xC0000000 | 0x022b
-#define NT_STATUS_CONVERT_TO_LARGE 0xC0000000 | 0x022c
-#define NT_STATUS_RETRY 0xC0000000 | 0x022d
-#define NT_STATUS_FOUND_OUT_OF_SCOPE 0xC0000000 | 0x022e
-#define NT_STATUS_ALLOCATE_BUCKET 0xC0000000 | 0x022f
-#define NT_STATUS_PROPSET_NOT_FOUND 0xC0000000 | 0x0230
-#define NT_STATUS_MARSHALL_OVERFLOW 0xC0000000 | 0x0231
-#define NT_STATUS_INVALID_VARIANT 0xC0000000 | 0x0232
-#define NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND 0xC0000000 | 0x0233
-#define NT_STATUS_ACCOUNT_LOCKED_OUT 0xC0000000 | 0x0234
-#define NT_STATUS_HANDLE_NOT_CLOSABLE 0xC0000000 | 0x0235
-#define NT_STATUS_CONNECTION_REFUSED 0xC0000000 | 0x0236
-#define NT_STATUS_GRACEFUL_DISCONNECT 0xC0000000 | 0x0237
-#define NT_STATUS_ADDRESS_ALREADY_ASSOCIATED 0xC0000000 | 0x0238
-#define NT_STATUS_ADDRESS_NOT_ASSOCIATED 0xC0000000 | 0x0239
-#define NT_STATUS_CONNECTION_INVALID 0xC0000000 | 0x023a
-#define NT_STATUS_CONNECTION_ACTIVE 0xC0000000 | 0x023b
-#define NT_STATUS_NETWORK_UNREACHABLE 0xC0000000 | 0x023c
-#define NT_STATUS_HOST_UNREACHABLE 0xC0000000 | 0x023d
-#define NT_STATUS_PROTOCOL_UNREACHABLE 0xC0000000 | 0x023e
-#define NT_STATUS_PORT_UNREACHABLE 0xC0000000 | 0x023f
-#define NT_STATUS_REQUEST_ABORTED 0xC0000000 | 0x0240
-#define NT_STATUS_CONNECTION_ABORTED 0xC0000000 | 0x0241
-#define NT_STATUS_BAD_COMPRESSION_BUFFER 0xC0000000 | 0x0242
-#define NT_STATUS_USER_MAPPED_FILE 0xC0000000 | 0x0243
-#define NT_STATUS_AUDIT_FAILED 0xC0000000 | 0x0244
-#define NT_STATUS_TIMER_RESOLUTION_NOT_SET 0xC0000000 | 0x0245
-#define NT_STATUS_CONNECTION_COUNT_LIMIT 0xC0000000 | 0x0246
-#define NT_STATUS_LOGIN_TIME_RESTRICTION 0xC0000000 | 0x0247
-#define NT_STATUS_LOGIN_WKSTA_RESTRICTION 0xC0000000 | 0x0248
-#define NT_STATUS_IMAGE_MP_UP_MISMATCH 0xC0000000 | 0x0249
-#define NT_STATUS_INSUFFICIENT_LOGON_INFO 0xC0000000 | 0x0250
-#define NT_STATUS_BAD_DLL_ENTRYPOINT 0xC0000000 | 0x0251
-#define NT_STATUS_BAD_SERVICE_ENTRYPOINT 0xC0000000 | 0x0252
-#define NT_STATUS_LPC_REPLY_LOST 0xC0000000 | 0x0253
-#define NT_STATUS_IP_ADDRESS_CONFLICT1 0xC0000000 | 0x0254
-#define NT_STATUS_IP_ADDRESS_CONFLICT2 0xC0000000 | 0x0255
-#define NT_STATUS_REGISTRY_QUOTA_LIMIT 0xC0000000 | 0x0256
-#define NT_STATUS_PATH_NOT_COVERED 0xC0000000 | 0x0257
-#define NT_STATUS_NO_CALLBACK_ACTIVE 0xC0000000 | 0x0258
-#define NT_STATUS_LICENSE_QUOTA_EXCEEDED 0xC0000000 | 0x0259
-#define NT_STATUS_PWD_TOO_SHORT 0xC0000000 | 0x025a
-#define NT_STATUS_PWD_TOO_RECENT 0xC0000000 | 0x025b
-#define NT_STATUS_PWD_HISTORY_CONFLICT 0xC0000000 | 0x025c
-#define NT_STATUS_PLUGPLAY_NO_DEVICE 0xC0000000 | 0x025e
-#define NT_STATUS_UNSUPPORTED_COMPRESSION 0xC0000000 | 0x025f
-#define NT_STATUS_INVALID_HW_PROFILE 0xC0000000 | 0x0260
-#define NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH 0xC0000000 | 0x0261
-#define NT_STATUS_DRIVER_ORDINAL_NOT_FOUND 0xC0000000 | 0x0262
-#define NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND 0xC0000000 | 0x0263
-#define NT_STATUS_RESOURCE_NOT_OWNED 0xC0000000 | 0x0264
-#define NT_STATUS_TOO_MANY_LINKS 0xC0000000 | 0x0265
-#define NT_STATUS_QUOTA_LIST_INCONSISTENT 0xC0000000 | 0x0266
-#define NT_STATUS_FILE_IS_OFFLINE 0xC0000000 | 0x0267
-#define NT_STATUS_NOT_A_REPARSE_POINT 0xC0000000 | 0x0275
-#define NT_STATUS_NO_SUCH_JOB 0xC0000000 | 0xEDE /* scheduler */
+#define NT_STATUS_DEVICE_DOOR_OPEN 0x80000289
+#define NT_STATUS_UNSUCCESSFUL (0xC0000000 | 0x0001)
+#define NT_STATUS_NOT_IMPLEMENTED (0xC0000000 | 0x0002)
+#define NT_STATUS_INVALID_INFO_CLASS (0xC0000000 | 0x0003)
+#define NT_STATUS_INFO_LENGTH_MISMATCH (0xC0000000 | 0x0004)
+#define NT_STATUS_ACCESS_VIOLATION (0xC0000000 | 0x0005)
+#define NT_STATUS_IN_PAGE_ERROR (0xC0000000 | 0x0006)
+#define NT_STATUS_PAGEFILE_QUOTA (0xC0000000 | 0x0007)
+#define NT_STATUS_INVALID_HANDLE (0xC0000000 | 0x0008)
+#define NT_STATUS_BAD_INITIAL_STACK (0xC0000000 | 0x0009)
+#define NT_STATUS_BAD_INITIAL_PC (0xC0000000 | 0x000a)
+#define NT_STATUS_INVALID_CID (0xC0000000 | 0x000b)
+#define NT_STATUS_TIMER_NOT_CANCELED (0xC0000000 | 0x000c)
+#define NT_STATUS_INVALID_PARAMETER (0xC0000000 | 0x000d)
+#define NT_STATUS_NO_SUCH_DEVICE (0xC0000000 | 0x000e)
+#define NT_STATUS_NO_SUCH_FILE (0xC0000000 | 0x000f)
+#define NT_STATUS_INVALID_DEVICE_REQUEST (0xC0000000 | 0x0010)
+#define NT_STATUS_END_OF_FILE (0xC0000000 | 0x0011)
+#define NT_STATUS_WRONG_VOLUME (0xC0000000 | 0x0012)
+#define NT_STATUS_NO_MEDIA_IN_DEVICE (0xC0000000 | 0x0013)
+#define NT_STATUS_UNRECOGNIZED_MEDIA (0xC0000000 | 0x0014)
+#define NT_STATUS_NONEXISTENT_SECTOR (0xC0000000 | 0x0015)
+#define NT_STATUS_MORE_PROCESSING_REQUIRED (0xC0000000 | 0x0016)
+#define NT_STATUS_NO_MEMORY (0xC0000000 | 0x0017)
+#define NT_STATUS_CONFLICTING_ADDRESSES (0xC0000000 | 0x0018)
+#define NT_STATUS_NOT_MAPPED_VIEW (0xC0000000 | 0x0019)
+#define NT_STATUS_UNABLE_TO_FREE_VM (0xC0000000 | 0x001a)
+#define NT_STATUS_UNABLE_TO_DELETE_SECTION (0xC0000000 | 0x001b)
+#define NT_STATUS_INVALID_SYSTEM_SERVICE (0xC0000000 | 0x001c)
+#define NT_STATUS_ILLEGAL_INSTRUCTION (0xC0000000 | 0x001d)
+#define NT_STATUS_INVALID_LOCK_SEQUENCE (0xC0000000 | 0x001e)
+#define NT_STATUS_INVALID_VIEW_SIZE (0xC0000000 | 0x001f)
+#define NT_STATUS_INVALID_FILE_FOR_SECTION (0xC0000000 | 0x0020)
+#define NT_STATUS_ALREADY_COMMITTED (0xC0000000 | 0x0021)
+#define NT_STATUS_ACCESS_DENIED (0xC0000000 | 0x0022)
+#define NT_STATUS_BUFFER_TOO_SMALL (0xC0000000 | 0x0023)
+#define NT_STATUS_OBJECT_TYPE_MISMATCH (0xC0000000 | 0x0024)
+#define NT_STATUS_NONCONTINUABLE_EXCEPTION (0xC0000000 | 0x0025)
+#define NT_STATUS_INVALID_DISPOSITION (0xC0000000 | 0x0026)
+#define NT_STATUS_UNWIND (0xC0000000 | 0x0027)
+#define NT_STATUS_BAD_STACK (0xC0000000 | 0x0028)
+#define NT_STATUS_INVALID_UNWIND_TARGET (0xC0000000 | 0x0029)
+#define NT_STATUS_NOT_LOCKED (0xC0000000 | 0x002a)
+#define NT_STATUS_PARITY_ERROR (0xC0000000 | 0x002b)
+#define NT_STATUS_UNABLE_TO_DECOMMIT_VM (0xC0000000 | 0x002c)
+#define NT_STATUS_NOT_COMMITTED (0xC0000000 | 0x002d)
+#define NT_STATUS_INVALID_PORT_ATTRIBUTES (0xC0000000 | 0x002e)
+#define NT_STATUS_PORT_MESSAGE_TOO_LONG (0xC0000000 | 0x002f)
+#define NT_STATUS_INVALID_PARAMETER_MIX (0xC0000000 | 0x0030)
+#define NT_STATUS_INVALID_QUOTA_LOWER (0xC0000000 | 0x0031)
+#define NT_STATUS_DISK_CORRUPT_ERROR (0xC0000000 | 0x0032)
+#define NT_STATUS_OBJECT_NAME_INVALID (0xC0000000 | 0x0033)
+#define NT_STATUS_OBJECT_NAME_NOT_FOUND (0xC0000000 | 0x0034)
+#define NT_STATUS_OBJECT_NAME_COLLISION (0xC0000000 | 0x0035)
+#define NT_STATUS_HANDLE_NOT_WAITABLE (0xC0000000 | 0x0036)
+#define NT_STATUS_PORT_DISCONNECTED (0xC0000000 | 0x0037)
+#define NT_STATUS_DEVICE_ALREADY_ATTACHED (0xC0000000 | 0x0038)
+#define NT_STATUS_OBJECT_PATH_INVALID (0xC0000000 | 0x0039)
+#define NT_STATUS_OBJECT_PATH_NOT_FOUND (0xC0000000 | 0x003a)
+#define NT_STATUS_OBJECT_PATH_SYNTAX_BAD (0xC0000000 | 0x003b)
+#define NT_STATUS_DATA_OVERRUN (0xC0000000 | 0x003c)
+#define NT_STATUS_DATA_LATE_ERROR (0xC0000000 | 0x003d)
+#define NT_STATUS_DATA_ERROR (0xC0000000 | 0x003e)
+#define NT_STATUS_CRC_ERROR (0xC0000000 | 0x003f)
+#define NT_STATUS_SECTION_TOO_BIG (0xC0000000 | 0x0040)
+#define NT_STATUS_PORT_CONNECTION_REFUSED (0xC0000000 | 0x0041)
+#define NT_STATUS_INVALID_PORT_HANDLE (0xC0000000 | 0x0042)
+#define NT_STATUS_SHARING_VIOLATION (0xC0000000 | 0x0043)
+#define NT_STATUS_QUOTA_EXCEEDED (0xC0000000 | 0x0044)
+#define NT_STATUS_INVALID_PAGE_PROTECTION (0xC0000000 | 0x0045)
+#define NT_STATUS_MUTANT_NOT_OWNED (0xC0000000 | 0x0046)
+#define NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED (0xC0000000 | 0x0047)
+#define NT_STATUS_PORT_ALREADY_SET (0xC0000000 | 0x0048)
+#define NT_STATUS_SECTION_NOT_IMAGE (0xC0000000 | 0x0049)
+#define NT_STATUS_SUSPEND_COUNT_EXCEEDED (0xC0000000 | 0x004a)
+#define NT_STATUS_THREAD_IS_TERMINATING (0xC0000000 | 0x004b)
+#define NT_STATUS_BAD_WORKING_SET_LIMIT (0xC0000000 | 0x004c)
+#define NT_STATUS_INCOMPATIBLE_FILE_MAP (0xC0000000 | 0x004d)
+#define NT_STATUS_SECTION_PROTECTION (0xC0000000 | 0x004e)
+#define NT_STATUS_EAS_NOT_SUPPORTED (0xC0000000 | 0x004f)
+#define NT_STATUS_EA_TOO_LARGE (0xC0000000 | 0x0050)
+#define NT_STATUS_NONEXISTENT_EA_ENTRY (0xC0000000 | 0x0051)
+#define NT_STATUS_NO_EAS_ON_FILE (0xC0000000 | 0x0052)
+#define NT_STATUS_EA_CORRUPT_ERROR (0xC0000000 | 0x0053)
+#define NT_STATUS_FILE_LOCK_CONFLICT (0xC0000000 | 0x0054)
+#define NT_STATUS_LOCK_NOT_GRANTED (0xC0000000 | 0x0055)
+#define NT_STATUS_DELETE_PENDING (0xC0000000 | 0x0056)
+#define NT_STATUS_CTL_FILE_NOT_SUPPORTED (0xC0000000 | 0x0057)
+#define NT_STATUS_UNKNOWN_REVISION (0xC0000000 | 0x0058)
+#define NT_STATUS_REVISION_MISMATCH (0xC0000000 | 0x0059)
+#define NT_STATUS_INVALID_OWNER (0xC0000000 | 0x005a)
+#define NT_STATUS_INVALID_PRIMARY_GROUP (0xC0000000 | 0x005b)
+#define NT_STATUS_NO_IMPERSONATION_TOKEN (0xC0000000 | 0x005c)
+#define NT_STATUS_CANT_DISABLE_MANDATORY (0xC0000000 | 0x005d)
+#define NT_STATUS_NO_LOGON_SERVERS (0xC0000000 | 0x005e)
+#define NT_STATUS_NO_SUCH_LOGON_SESSION (0xC0000000 | 0x005f)
+#define NT_STATUS_NO_SUCH_PRIVILEGE (0xC0000000 | 0x0060)
+#define NT_STATUS_PRIVILEGE_NOT_HELD (0xC0000000 | 0x0061)
+#define NT_STATUS_INVALID_ACCOUNT_NAME (0xC0000000 | 0x0062)
+#define NT_STATUS_USER_EXISTS (0xC0000000 | 0x0063)
+#define NT_STATUS_NO_SUCH_USER (0xC0000000 | 0x0064)
+#define NT_STATUS_GROUP_EXISTS (0xC0000000 | 0x0065)
+#define NT_STATUS_NO_SUCH_GROUP (0xC0000000 | 0x0066)
+#define NT_STATUS_MEMBER_IN_GROUP (0xC0000000 | 0x0067)
+#define NT_STATUS_MEMBER_NOT_IN_GROUP (0xC0000000 | 0x0068)
+#define NT_STATUS_LAST_ADMIN (0xC0000000 | 0x0069)
+#define NT_STATUS_WRONG_PASSWORD (0xC0000000 | 0x006a)
+#define NT_STATUS_ILL_FORMED_PASSWORD (0xC0000000 | 0x006b)
+#define NT_STATUS_PASSWORD_RESTRICTION (0xC0000000 | 0x006c)
+#define NT_STATUS_LOGON_FAILURE (0xC0000000 | 0x006d)
+#define NT_STATUS_ACCOUNT_RESTRICTION (0xC0000000 | 0x006e)
+#define NT_STATUS_INVALID_LOGON_HOURS (0xC0000000 | 0x006f)
+#define NT_STATUS_INVALID_WORKSTATION (0xC0000000 | 0x0070)
+#define NT_STATUS_PASSWORD_EXPIRED (0xC0000000 | 0x0071)
+#define NT_STATUS_ACCOUNT_DISABLED (0xC0000000 | 0x0072)
+#define NT_STATUS_NONE_MAPPED (0xC0000000 | 0x0073)
+#define NT_STATUS_TOO_MANY_LUIDS_REQUESTED (0xC0000000 | 0x0074)
+#define NT_STATUS_LUIDS_EXHAUSTED (0xC0000000 | 0x0075)
+#define NT_STATUS_INVALID_SUB_AUTHORITY (0xC0000000 | 0x0076)
+#define NT_STATUS_INVALID_ACL (0xC0000000 | 0x0077)
+#define NT_STATUS_INVALID_SID (0xC0000000 | 0x0078)
+#define NT_STATUS_INVALID_SECURITY_DESCR (0xC0000000 | 0x0079)
+#define NT_STATUS_PROCEDURE_NOT_FOUND (0xC0000000 | 0x007a)
+#define NT_STATUS_INVALID_IMAGE_FORMAT (0xC0000000 | 0x007b)
+#define NT_STATUS_NO_TOKEN (0xC0000000 | 0x007c)
+#define NT_STATUS_BAD_INHERITANCE_ACL (0xC0000000 | 0x007d)
+#define NT_STATUS_RANGE_NOT_LOCKED (0xC0000000 | 0x007e)
+#define NT_STATUS_DISK_FULL (0xC0000000 | 0x007f)
+#define NT_STATUS_SERVER_DISABLED (0xC0000000 | 0x0080)
+#define NT_STATUS_SERVER_NOT_DISABLED (0xC0000000 | 0x0081)
+#define NT_STATUS_TOO_MANY_GUIDS_REQUESTED (0xC0000000 | 0x0082)
+#define NT_STATUS_GUIDS_EXHAUSTED (0xC0000000 | 0x0083)
+#define NT_STATUS_INVALID_ID_AUTHORITY (0xC0000000 | 0x0084)
+#define NT_STATUS_AGENTS_EXHAUSTED (0xC0000000 | 0x0085)
+#define NT_STATUS_INVALID_VOLUME_LABEL (0xC0000000 | 0x0086)
+#define NT_STATUS_SECTION_NOT_EXTENDED (0xC0000000 | 0x0087)
+#define NT_STATUS_NOT_MAPPED_DATA (0xC0000000 | 0x0088)
+#define NT_STATUS_RESOURCE_DATA_NOT_FOUND (0xC0000000 | 0x0089)
+#define NT_STATUS_RESOURCE_TYPE_NOT_FOUND (0xC0000000 | 0x008a)
+#define NT_STATUS_RESOURCE_NAME_NOT_FOUND (0xC0000000 | 0x008b)
+#define NT_STATUS_ARRAY_BOUNDS_EXCEEDED (0xC0000000 | 0x008c)
+#define NT_STATUS_FLOAT_DENORMAL_OPERAND (0xC0000000 | 0x008d)
+#define NT_STATUS_FLOAT_DIVIDE_BY_ZERO (0xC0000000 | 0x008e)
+#define NT_STATUS_FLOAT_INEXACT_RESULT (0xC0000000 | 0x008f)
+#define NT_STATUS_FLOAT_INVALID_OPERATION (0xC0000000 | 0x0090)
+#define NT_STATUS_FLOAT_OVERFLOW (0xC0000000 | 0x0091)
+#define NT_STATUS_FLOAT_STACK_CHECK (0xC0000000 | 0x0092)
+#define NT_STATUS_FLOAT_UNDERFLOW (0xC0000000 | 0x0093)
+#define NT_STATUS_INTEGER_DIVIDE_BY_ZERO (0xC0000000 | 0x0094)
+#define NT_STATUS_INTEGER_OVERFLOW (0xC0000000 | 0x0095)
+#define NT_STATUS_PRIVILEGED_INSTRUCTION (0xC0000000 | 0x0096)
+#define NT_STATUS_TOO_MANY_PAGING_FILES (0xC0000000 | 0x0097)
+#define NT_STATUS_FILE_INVALID (0xC0000000 | 0x0098)
+#define NT_STATUS_ALLOTTED_SPACE_EXCEEDED (0xC0000000 | 0x0099)
+#define NT_STATUS_INSUFFICIENT_RESOURCES (0xC0000000 | 0x009a)
+#define NT_STATUS_DFS_EXIT_PATH_FOUND (0xC0000000 | 0x009b)
+#define NT_STATUS_DEVICE_DATA_ERROR (0xC0000000 | 0x009c)
+#define NT_STATUS_DEVICE_NOT_CONNECTED (0xC0000000 | 0x009d)
+#define NT_STATUS_DEVICE_POWER_FAILURE (0xC0000000 | 0x009e)
+#define NT_STATUS_FREE_VM_NOT_AT_BASE (0xC0000000 | 0x009f)
+#define NT_STATUS_MEMORY_NOT_ALLOCATED (0xC0000000 | 0x00a0)
+#define NT_STATUS_WORKING_SET_QUOTA (0xC0000000 | 0x00a1)
+#define NT_STATUS_MEDIA_WRITE_PROTECTED (0xC0000000 | 0x00a2)
+#define NT_STATUS_DEVICE_NOT_READY (0xC0000000 | 0x00a3)
+#define NT_STATUS_INVALID_GROUP_ATTRIBUTES (0xC0000000 | 0x00a4)
+#define NT_STATUS_BAD_IMPERSONATION_LEVEL (0xC0000000 | 0x00a5)
+#define NT_STATUS_CANT_OPEN_ANONYMOUS (0xC0000000 | 0x00a6)
+#define NT_STATUS_BAD_VALIDATION_CLASS (0xC0000000 | 0x00a7)
+#define NT_STATUS_BAD_TOKEN_TYPE (0xC0000000 | 0x00a8)
+#define NT_STATUS_BAD_MASTER_BOOT_RECORD (0xC0000000 | 0x00a9)
+#define NT_STATUS_INSTRUCTION_MISALIGNMENT (0xC0000000 | 0x00aa)
+#define NT_STATUS_INSTANCE_NOT_AVAILABLE (0xC0000000 | 0x00ab)
+#define NT_STATUS_PIPE_NOT_AVAILABLE (0xC0000000 | 0x00ac)
+#define NT_STATUS_INVALID_PIPE_STATE (0xC0000000 | 0x00ad)
+#define NT_STATUS_PIPE_BUSY (0xC0000000 | 0x00ae)
+#define NT_STATUS_ILLEGAL_FUNCTION (0xC0000000 | 0x00af)
+#define NT_STATUS_PIPE_DISCONNECTED (0xC0000000 | 0x00b0)
+#define NT_STATUS_PIPE_CLOSING (0xC0000000 | 0x00b1)
+#define NT_STATUS_PIPE_CONNECTED (0xC0000000 | 0x00b2)
+#define NT_STATUS_PIPE_LISTENING (0xC0000000 | 0x00b3)
+#define NT_STATUS_INVALID_READ_MODE (0xC0000000 | 0x00b4)
+#define NT_STATUS_IO_TIMEOUT (0xC0000000 | 0x00b5)
+#define NT_STATUS_FILE_FORCED_CLOSED (0xC0000000 | 0x00b6)
+#define NT_STATUS_PROFILING_NOT_STARTED (0xC0000000 | 0x00b7)
+#define NT_STATUS_PROFILING_NOT_STOPPED (0xC0000000 | 0x00b8)
+#define NT_STATUS_COULD_NOT_INTERPRET (0xC0000000 | 0x00b9)
+#define NT_STATUS_FILE_IS_A_DIRECTORY (0xC0000000 | 0x00ba)
+#define NT_STATUS_NOT_SUPPORTED (0xC0000000 | 0x00bb)
+#define NT_STATUS_REMOTE_NOT_LISTENING (0xC0000000 | 0x00bc)
+#define NT_STATUS_DUPLICATE_NAME (0xC0000000 | 0x00bd)
+#define NT_STATUS_BAD_NETWORK_PATH (0xC0000000 | 0x00be)
+#define NT_STATUS_NETWORK_BUSY (0xC0000000 | 0x00bf)
+#define NT_STATUS_DEVICE_DOES_NOT_EXIST (0xC0000000 | 0x00c0)
+#define NT_STATUS_TOO_MANY_COMMANDS (0xC0000000 | 0x00c1)
+#define NT_STATUS_ADAPTER_HARDWARE_ERROR (0xC0000000 | 0x00c2)
+#define NT_STATUS_INVALID_NETWORK_RESPONSE (0xC0000000 | 0x00c3)
+#define NT_STATUS_UNEXPECTED_NETWORK_ERROR (0xC0000000 | 0x00c4)
+#define NT_STATUS_BAD_REMOTE_ADAPTER (0xC0000000 | 0x00c5)
+#define NT_STATUS_PRINT_QUEUE_FULL (0xC0000000 | 0x00c6)
+#define NT_STATUS_NO_SPOOL_SPACE (0xC0000000 | 0x00c7)
+#define NT_STATUS_PRINT_CANCELLED (0xC0000000 | 0x00c8)
+#define NT_STATUS_NETWORK_NAME_DELETED (0xC0000000 | 0x00c9)
+#define NT_STATUS_NETWORK_ACCESS_DENIED (0xC0000000 | 0x00ca)
+#define NT_STATUS_BAD_DEVICE_TYPE (0xC0000000 | 0x00cb)
+#define NT_STATUS_BAD_NETWORK_NAME (0xC0000000 | 0x00cc)
+#define NT_STATUS_TOO_MANY_NAMES (0xC0000000 | 0x00cd)
+#define NT_STATUS_TOO_MANY_SESSIONS (0xC0000000 | 0x00ce)
+#define NT_STATUS_SHARING_PAUSED (0xC0000000 | 0x00cf)
+#define NT_STATUS_REQUEST_NOT_ACCEPTED (0xC0000000 | 0x00d0)
+#define NT_STATUS_REDIRECTOR_PAUSED (0xC0000000 | 0x00d1)
+#define NT_STATUS_NET_WRITE_FAULT (0xC0000000 | 0x00d2)
+#define NT_STATUS_PROFILING_AT_LIMIT (0xC0000000 | 0x00d3)
+#define NT_STATUS_NOT_SAME_DEVICE (0xC0000000 | 0x00d4)
+#define NT_STATUS_FILE_RENAMED (0xC0000000 | 0x00d5)
+#define NT_STATUS_VIRTUAL_CIRCUIT_CLOSED (0xC0000000 | 0x00d6)
+#define NT_STATUS_NO_SECURITY_ON_OBJECT (0xC0000000 | 0x00d7)
+#define NT_STATUS_CANT_WAIT (0xC0000000 | 0x00d8)
+#define NT_STATUS_PIPE_EMPTY (0xC0000000 | 0x00d9)
+#define NT_STATUS_CANT_ACCESS_DOMAIN_INFO (0xC0000000 | 0x00da)
+#define NT_STATUS_CANT_TERMINATE_SELF (0xC0000000 | 0x00db)
+#define NT_STATUS_INVALID_SERVER_STATE (0xC0000000 | 0x00dc)
+#define NT_STATUS_INVALID_DOMAIN_STATE (0xC0000000 | 0x00dd)
+#define NT_STATUS_INVALID_DOMAIN_ROLE (0xC0000000 | 0x00de)
+#define NT_STATUS_NO_SUCH_DOMAIN (0xC0000000 | 0x00df)
+#define NT_STATUS_DOMAIN_EXISTS (0xC0000000 | 0x00e0)
+#define NT_STATUS_DOMAIN_LIMIT_EXCEEDED (0xC0000000 | 0x00e1)
+#define NT_STATUS_OPLOCK_NOT_GRANTED (0xC0000000 | 0x00e2)
+#define NT_STATUS_INVALID_OPLOCK_PROTOCOL (0xC0000000 | 0x00e3)
+#define NT_STATUS_INTERNAL_DB_CORRUPTION (0xC0000000 | 0x00e4)
+#define NT_STATUS_INTERNAL_ERROR (0xC0000000 | 0x00e5)
+#define NT_STATUS_GENERIC_NOT_MAPPED (0xC0000000 | 0x00e6)
+#define NT_STATUS_BAD_DESCRIPTOR_FORMAT (0xC0000000 | 0x00e7)
+#define NT_STATUS_INVALID_USER_BUFFER (0xC0000000 | 0x00e8)
+#define NT_STATUS_UNEXPECTED_IO_ERROR (0xC0000000 | 0x00e9)
+#define NT_STATUS_UNEXPECTED_MM_CREATE_ERR (0xC0000000 | 0x00ea)
+#define NT_STATUS_UNEXPECTED_MM_MAP_ERROR (0xC0000000 | 0x00eb)
+#define NT_STATUS_UNEXPECTED_MM_EXTEND_ERR (0xC0000000 | 0x00ec)
+#define NT_STATUS_NOT_LOGON_PROCESS (0xC0000000 | 0x00ed)
+#define NT_STATUS_LOGON_SESSION_EXISTS (0xC0000000 | 0x00ee)
+#define NT_STATUS_INVALID_PARAMETER_1 (0xC0000000 | 0x00ef)
+#define NT_STATUS_INVALID_PARAMETER_2 (0xC0000000 | 0x00f0)
+#define NT_STATUS_INVALID_PARAMETER_3 (0xC0000000 | 0x00f1)
+#define NT_STATUS_INVALID_PARAMETER_4 (0xC0000000 | 0x00f2)
+#define NT_STATUS_INVALID_PARAMETER_5 (0xC0000000 | 0x00f3)
+#define NT_STATUS_INVALID_PARAMETER_6 (0xC0000000 | 0x00f4)
+#define NT_STATUS_INVALID_PARAMETER_7 (0xC0000000 | 0x00f5)
+#define NT_STATUS_INVALID_PARAMETER_8 (0xC0000000 | 0x00f6)
+#define NT_STATUS_INVALID_PARAMETER_9 (0xC0000000 | 0x00f7)
+#define NT_STATUS_INVALID_PARAMETER_10 (0xC0000000 | 0x00f8)
+#define NT_STATUS_INVALID_PARAMETER_11 (0xC0000000 | 0x00f9)
+#define NT_STATUS_INVALID_PARAMETER_12 (0xC0000000 | 0x00fa)
+#define NT_STATUS_REDIRECTOR_NOT_STARTED (0xC0000000 | 0x00fb)
+#define NT_STATUS_REDIRECTOR_STARTED (0xC0000000 | 0x00fc)
+#define NT_STATUS_STACK_OVERFLOW (0xC0000000 | 0x00fd)
+#define NT_STATUS_NO_SUCH_PACKAGE (0xC0000000 | 0x00fe)
+#define NT_STATUS_BAD_FUNCTION_TABLE (0xC0000000 | 0x00ff)
+#define NT_STATUS_DIRECTORY_NOT_EMPTY (0xC0000000 | 0x0101)
+#define NT_STATUS_FILE_CORRUPT_ERROR (0xC0000000 | 0x0102)
+#define NT_STATUS_NOT_A_DIRECTORY (0xC0000000 | 0x0103)
+#define NT_STATUS_BAD_LOGON_SESSION_STATE (0xC0000000 | 0x0104)
+#define NT_STATUS_LOGON_SESSION_COLLISION (0xC0000000 | 0x0105)
+#define NT_STATUS_NAME_TOO_LONG (0xC0000000 | 0x0106)
+#define NT_STATUS_FILES_OPEN (0xC0000000 | 0x0107)
+#define NT_STATUS_CONNECTION_IN_USE (0xC0000000 | 0x0108)
+#define NT_STATUS_MESSAGE_NOT_FOUND (0xC0000000 | 0x0109)
+#define NT_STATUS_PROCESS_IS_TERMINATING (0xC0000000 | 0x010a)
+#define NT_STATUS_INVALID_LOGON_TYPE (0xC0000000 | 0x010b)
+#define NT_STATUS_NO_GUID_TRANSLATION (0xC0000000 | 0x010c)
+#define NT_STATUS_CANNOT_IMPERSONATE (0xC0000000 | 0x010d)
+#define NT_STATUS_IMAGE_ALREADY_LOADED (0xC0000000 | 0x010e)
+#define NT_STATUS_ABIOS_NOT_PRESENT (0xC0000000 | 0x010f)
+#define NT_STATUS_ABIOS_LID_NOT_EXIST (0xC0000000 | 0x0110)
+#define NT_STATUS_ABIOS_LID_ALREADY_OWNED (0xC0000000 | 0x0111)
+#define NT_STATUS_ABIOS_NOT_LID_OWNER (0xC0000000 | 0x0112)
+#define NT_STATUS_ABIOS_INVALID_COMMAND (0xC0000000 | 0x0113)
+#define NT_STATUS_ABIOS_INVALID_LID (0xC0000000 | 0x0114)
+#define NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE (0xC0000000 | 0x0115)
+#define NT_STATUS_ABIOS_INVALID_SELECTOR (0xC0000000 | 0x0116)
+#define NT_STATUS_NO_LDT (0xC0000000 | 0x0117)
+#define NT_STATUS_INVALID_LDT_SIZE (0xC0000000 | 0x0118)
+#define NT_STATUS_INVALID_LDT_OFFSET (0xC0000000 | 0x0119)
+#define NT_STATUS_INVALID_LDT_DESCRIPTOR (0xC0000000 | 0x011a)
+#define NT_STATUS_INVALID_IMAGE_NE_FORMAT (0xC0000000 | 0x011b)
+#define NT_STATUS_RXACT_INVALID_STATE (0xC0000000 | 0x011c)
+#define NT_STATUS_RXACT_COMMIT_FAILURE (0xC0000000 | 0x011d)
+#define NT_STATUS_MAPPED_FILE_SIZE_ZERO (0xC0000000 | 0x011e)
+#define NT_STATUS_TOO_MANY_OPENED_FILES (0xC0000000 | 0x011f)
+#define NT_STATUS_CANCELLED (0xC0000000 | 0x0120)
+#define NT_STATUS_CANNOT_DELETE (0xC0000000 | 0x0121)
+#define NT_STATUS_INVALID_COMPUTER_NAME (0xC0000000 | 0x0122)
+#define NT_STATUS_FILE_DELETED (0xC0000000 | 0x0123)
+#define NT_STATUS_SPECIAL_ACCOUNT (0xC0000000 | 0x0124)
+#define NT_STATUS_SPECIAL_GROUP (0xC0000000 | 0x0125)
+#define NT_STATUS_SPECIAL_USER (0xC0000000 | 0x0126)
+#define NT_STATUS_MEMBERS_PRIMARY_GROUP (0xC0000000 | 0x0127)
+#define NT_STATUS_FILE_CLOSED (0xC0000000 | 0x0128)
+#define NT_STATUS_TOO_MANY_THREADS (0xC0000000 | 0x0129)
+#define NT_STATUS_THREAD_NOT_IN_PROCESS (0xC0000000 | 0x012a)
+#define NT_STATUS_TOKEN_ALREADY_IN_USE (0xC0000000 | 0x012b)
+#define NT_STATUS_PAGEFILE_QUOTA_EXCEEDED (0xC0000000 | 0x012c)
+#define NT_STATUS_COMMITMENT_LIMIT (0xC0000000 | 0x012d)
+#define NT_STATUS_INVALID_IMAGE_LE_FORMAT (0xC0000000 | 0x012e)
+#define NT_STATUS_INVALID_IMAGE_NOT_MZ (0xC0000000 | 0x012f)
+#define NT_STATUS_INVALID_IMAGE_PROTECT (0xC0000000 | 0x0130)
+#define NT_STATUS_INVALID_IMAGE_WIN_16 (0xC0000000 | 0x0131)
+#define NT_STATUS_LOGON_SERVER_CONFLICT (0xC0000000 | 0x0132)
+#define NT_STATUS_TIME_DIFFERENCE_AT_DC (0xC0000000 | 0x0133)
+#define NT_STATUS_SYNCHRONIZATION_REQUIRED (0xC0000000 | 0x0134)
+#define NT_STATUS_DLL_NOT_FOUND (0xC0000000 | 0x0135)
+#define NT_STATUS_OPEN_FAILED (0xC0000000 | 0x0136)
+#define NT_STATUS_IO_PRIVILEGE_FAILED (0xC0000000 | 0x0137)
+#define NT_STATUS_ORDINAL_NOT_FOUND (0xC0000000 | 0x0138)
+#define NT_STATUS_ENTRYPOINT_NOT_FOUND (0xC0000000 | 0x0139)
+#define NT_STATUS_CONTROL_C_EXIT (0xC0000000 | 0x013a)
+#define NT_STATUS_LOCAL_DISCONNECT (0xC0000000 | 0x013b)
+#define NT_STATUS_REMOTE_DISCONNECT (0xC0000000 | 0x013c)
+#define NT_STATUS_REMOTE_RESOURCES (0xC0000000 | 0x013d)
+#define NT_STATUS_LINK_FAILED (0xC0000000 | 0x013e)
+#define NT_STATUS_LINK_TIMEOUT (0xC0000000 | 0x013f)
+#define NT_STATUS_INVALID_CONNECTION (0xC0000000 | 0x0140)
+#define NT_STATUS_INVALID_ADDRESS (0xC0000000 | 0x0141)
+#define NT_STATUS_DLL_INIT_FAILED (0xC0000000 | 0x0142)
+#define NT_STATUS_MISSING_SYSTEMFILE (0xC0000000 | 0x0143)
+#define NT_STATUS_UNHANDLED_EXCEPTION (0xC0000000 | 0x0144)
+#define NT_STATUS_APP_INIT_FAILURE (0xC0000000 | 0x0145)
+#define NT_STATUS_PAGEFILE_CREATE_FAILED (0xC0000000 | 0x0146)
+#define NT_STATUS_NO_PAGEFILE (0xC0000000 | 0x0147)
+#define NT_STATUS_INVALID_LEVEL (0xC0000000 | 0x0148)
+#define NT_STATUS_WRONG_PASSWORD_CORE (0xC0000000 | 0x0149)
+#define NT_STATUS_ILLEGAL_FLOAT_CONTEXT (0xC0000000 | 0x014a)
+#define NT_STATUS_PIPE_BROKEN (0xC0000000 | 0x014b)
+#define NT_STATUS_REGISTRY_CORRUPT (0xC0000000 | 0x014c)
+#define NT_STATUS_REGISTRY_IO_FAILED (0xC0000000 | 0x014d)
+#define NT_STATUS_NO_EVENT_PAIR (0xC0000000 | 0x014e)
+#define NT_STATUS_UNRECOGNIZED_VOLUME (0xC0000000 | 0x014f)
+#define NT_STATUS_SERIAL_NO_DEVICE_INITED (0xC0000000 | 0x0150)
+#define NT_STATUS_NO_SUCH_ALIAS (0xC0000000 | 0x0151)
+#define NT_STATUS_MEMBER_NOT_IN_ALIAS (0xC0000000 | 0x0152)
+#define NT_STATUS_MEMBER_IN_ALIAS (0xC0000000 | 0x0153)
+#define NT_STATUS_ALIAS_EXISTS (0xC0000000 | 0x0154)
+#define NT_STATUS_LOGON_NOT_GRANTED (0xC0000000 | 0x0155)
+#define NT_STATUS_TOO_MANY_SECRETS (0xC0000000 | 0x0156)
+#define NT_STATUS_SECRET_TOO_LONG (0xC0000000 | 0x0157)
+#define NT_STATUS_INTERNAL_DB_ERROR (0xC0000000 | 0x0158)
+#define NT_STATUS_FULLSCREEN_MODE (0xC0000000 | 0x0159)
+#define NT_STATUS_TOO_MANY_CONTEXT_IDS (0xC0000000 | 0x015a)
+#define NT_STATUS_LOGON_TYPE_NOT_GRANTED (0xC0000000 | 0x015b)
+#define NT_STATUS_NOT_REGISTRY_FILE (0xC0000000 | 0x015c)
+#define NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED (0xC0000000 | 0x015d)
+#define NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR (0xC0000000 | 0x015e)
+#define NT_STATUS_FT_MISSING_MEMBER (0xC0000000 | 0x015f)
+#define NT_STATUS_ILL_FORMED_SERVICE_ENTRY (0xC0000000 | 0x0160)
+#define NT_STATUS_ILLEGAL_CHARACTER (0xC0000000 | 0x0161)
+#define NT_STATUS_UNMAPPABLE_CHARACTER (0xC0000000 | 0x0162)
+#define NT_STATUS_UNDEFINED_CHARACTER (0xC0000000 | 0x0163)
+#define NT_STATUS_FLOPPY_VOLUME (0xC0000000 | 0x0164)
+#define NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND (0xC0000000 | 0x0165)
+#define NT_STATUS_FLOPPY_WRONG_CYLINDER (0xC0000000 | 0x0166)
+#define NT_STATUS_FLOPPY_UNKNOWN_ERROR (0xC0000000 | 0x0167)
+#define NT_STATUS_FLOPPY_BAD_REGISTERS (0xC0000000 | 0x0168)
+#define NT_STATUS_DISK_RECALIBRATE_FAILED (0xC0000000 | 0x0169)
+#define NT_STATUS_DISK_OPERATION_FAILED (0xC0000000 | 0x016a)
+#define NT_STATUS_DISK_RESET_FAILED (0xC0000000 | 0x016b)
+#define NT_STATUS_SHARED_IRQ_BUSY (0xC0000000 | 0x016c)
+#define NT_STATUS_FT_ORPHANING (0xC0000000 | 0x016d)
+#define NT_STATUS_PARTITION_FAILURE (0xC0000000 | 0x0172)
+#define NT_STATUS_INVALID_BLOCK_LENGTH (0xC0000000 | 0x0173)
+#define NT_STATUS_DEVICE_NOT_PARTITIONED (0xC0000000 | 0x0174)
+#define NT_STATUS_UNABLE_TO_LOCK_MEDIA (0xC0000000 | 0x0175)
+#define NT_STATUS_UNABLE_TO_UNLOAD_MEDIA (0xC0000000 | 0x0176)
+#define NT_STATUS_EOM_OVERFLOW (0xC0000000 | 0x0177)
+#define NT_STATUS_NO_MEDIA (0xC0000000 | 0x0178)
+#define NT_STATUS_NO_SUCH_MEMBER (0xC0000000 | 0x017a)
+#define NT_STATUS_INVALID_MEMBER (0xC0000000 | 0x017b)
+#define NT_STATUS_KEY_DELETED (0xC0000000 | 0x017c)
+#define NT_STATUS_NO_LOG_SPACE (0xC0000000 | 0x017d)
+#define NT_STATUS_TOO_MANY_SIDS (0xC0000000 | 0x017e)
+#define NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED (0xC0000000 | 0x017f)
+#define NT_STATUS_KEY_HAS_CHILDREN (0xC0000000 | 0x0180)
+#define NT_STATUS_CHILD_MUST_BE_VOLATILE (0xC0000000 | 0x0181)
+#define NT_STATUS_DEVICE_CONFIGURATION_ERROR (0xC0000000 | 0x0182)
+#define NT_STATUS_DRIVER_INTERNAL_ERROR (0xC0000000 | 0x0183)
+#define NT_STATUS_INVALID_DEVICE_STATE (0xC0000000 | 0x0184)
+#define NT_STATUS_IO_DEVICE_ERROR (0xC0000000 | 0x0185)
+#define NT_STATUS_DEVICE_PROTOCOL_ERROR (0xC0000000 | 0x0186)
+#define NT_STATUS_BACKUP_CONTROLLER (0xC0000000 | 0x0187)
+#define NT_STATUS_LOG_FILE_FULL (0xC0000000 | 0x0188)
+#define NT_STATUS_TOO_LATE (0xC0000000 | 0x0189)
+#define NT_STATUS_NO_TRUST_LSA_SECRET (0xC0000000 | 0x018a)
+#define NT_STATUS_NO_TRUST_SAM_ACCOUNT (0xC0000000 | 0x018b)
+#define NT_STATUS_TRUSTED_DOMAIN_FAILURE (0xC0000000 | 0x018c)
+#define NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE (0xC0000000 | 0x018d)
+#define NT_STATUS_EVENTLOG_FILE_CORRUPT (0xC0000000 | 0x018e)
+#define NT_STATUS_EVENTLOG_CANT_START (0xC0000000 | 0x018f)
+#define NT_STATUS_TRUST_FAILURE (0xC0000000 | 0x0190)
+#define NT_STATUS_MUTANT_LIMIT_EXCEEDED (0xC0000000 | 0x0191)
+#define NT_STATUS_NETLOGON_NOT_STARTED (0xC0000000 | 0x0192)
+#define NT_STATUS_ACCOUNT_EXPIRED (0xC0000000 | 0x0193)
+#define NT_STATUS_POSSIBLE_DEADLOCK (0xC0000000 | 0x0194)
+#define NT_STATUS_NETWORK_CREDENTIAL_CONFLICT (0xC0000000 | 0x0195)
+#define NT_STATUS_REMOTE_SESSION_LIMIT (0xC0000000 | 0x0196)
+#define NT_STATUS_EVENTLOG_FILE_CHANGED (0xC0000000 | 0x0197)
+#define NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT (0xC0000000 | 0x0198)
+#define NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT (0xC0000000 | 0x0199)
+#define NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT (0xC0000000 | 0x019a)
+#define NT_STATUS_DOMAIN_TRUST_INCONSISTENT (0xC0000000 | 0x019b)
+#define NT_STATUS_FS_DRIVER_REQUIRED (0xC0000000 | 0x019c)
+#define NT_STATUS_INVALID_LOCK_RANGE (0xC0000000 | 0x01a1)
+#define NT_STATUS_NO_USER_SESSION_KEY (0xC0000000 | 0x0202)
+#define NT_STATUS_USER_SESSION_DELETED (0xC0000000 | 0x0203)
+#define NT_STATUS_RESOURCE_LANG_NOT_FOUND (0xC0000000 | 0x0204)
+#define NT_STATUS_INSUFF_SERVER_RESOURCES (0xC0000000 | 0x0205)
+#define NT_STATUS_INVALID_BUFFER_SIZE (0xC0000000 | 0x0206)
+#define NT_STATUS_INVALID_ADDRESS_COMPONENT (0xC0000000 | 0x0207)
+#define NT_STATUS_INVALID_ADDRESS_WILDCARD (0xC0000000 | 0x0208)
+#define NT_STATUS_TOO_MANY_ADDRESSES (0xC0000000 | 0x0209)
+#define NT_STATUS_ADDRESS_ALREADY_EXISTS (0xC0000000 | 0x020a)
+#define NT_STATUS_ADDRESS_CLOSED (0xC0000000 | 0x020b)
+#define NT_STATUS_CONNECTION_DISCONNECTED (0xC0000000 | 0x020c)
+#define NT_STATUS_CONNECTION_RESET (0xC0000000 | 0x020d)
+#define NT_STATUS_TOO_MANY_NODES (0xC0000000 | 0x020e)
+#define NT_STATUS_TRANSACTION_ABORTED (0xC0000000 | 0x020f)
+#define NT_STATUS_TRANSACTION_TIMED_OUT (0xC0000000 | 0x0210)
+#define NT_STATUS_TRANSACTION_NO_RELEASE (0xC0000000 | 0x0211)
+#define NT_STATUS_TRANSACTION_NO_MATCH (0xC0000000 | 0x0212)
+#define NT_STATUS_TRANSACTION_RESPONDED (0xC0000000 | 0x0213)
+#define NT_STATUS_TRANSACTION_INVALID_ID (0xC0000000 | 0x0214)
+#define NT_STATUS_TRANSACTION_INVALID_TYPE (0xC0000000 | 0x0215)
+#define NT_STATUS_NOT_SERVER_SESSION (0xC0000000 | 0x0216)
+#define NT_STATUS_NOT_CLIENT_SESSION (0xC0000000 | 0x0217)
+#define NT_STATUS_CANNOT_LOAD_REGISTRY_FILE (0xC0000000 | 0x0218)
+#define NT_STATUS_DEBUG_ATTACH_FAILED (0xC0000000 | 0x0219)
+#define NT_STATUS_SYSTEM_PROCESS_TERMINATED (0xC0000000 | 0x021a)
+#define NT_STATUS_DATA_NOT_ACCEPTED (0xC0000000 | 0x021b)
+#define NT_STATUS_NO_BROWSER_SERVERS_FOUND (0xC0000000 | 0x021c)
+#define NT_STATUS_VDM_HARD_ERROR (0xC0000000 | 0x021d)
+#define NT_STATUS_DRIVER_CANCEL_TIMEOUT (0xC0000000 | 0x021e)
+#define NT_STATUS_REPLY_MESSAGE_MISMATCH (0xC0000000 | 0x021f)
+#define NT_STATUS_MAPPED_ALIGNMENT (0xC0000000 | 0x0220)
+#define NT_STATUS_IMAGE_CHECKSUM_MISMATCH (0xC0000000 | 0x0221)
+#define NT_STATUS_LOST_WRITEBEHIND_DATA (0xC0000000 | 0x0222)
+#define NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID (0xC0000000 | 0x0223)
+#define NT_STATUS_PASSWORD_MUST_CHANGE (0xC0000000 | 0x0224)
+#define NT_STATUS_NOT_FOUND (0xC0000000 | 0x0225)
+#define NT_STATUS_NOT_TINY_STREAM (0xC0000000 | 0x0226)
+#define NT_STATUS_RECOVERY_FAILURE (0xC0000000 | 0x0227)
+#define NT_STATUS_STACK_OVERFLOW_READ (0xC0000000 | 0x0228)
+#define NT_STATUS_FAIL_CHECK (0xC0000000 | 0x0229)
+#define NT_STATUS_DUPLICATE_OBJECTID (0xC0000000 | 0x022a)
+#define NT_STATUS_OBJECTID_EXISTS (0xC0000000 | 0x022b)
+#define NT_STATUS_CONVERT_TO_LARGE (0xC0000000 | 0x022c)
+#define NT_STATUS_RETRY (0xC0000000 | 0x022d)
+#define NT_STATUS_FOUND_OUT_OF_SCOPE (0xC0000000 | 0x022e)
+#define NT_STATUS_ALLOCATE_BUCKET (0xC0000000 | 0x022f)
+#define NT_STATUS_PROPSET_NOT_FOUND (0xC0000000 | 0x0230)
+#define NT_STATUS_MARSHALL_OVERFLOW (0xC0000000 | 0x0231)
+#define NT_STATUS_INVALID_VARIANT (0xC0000000 | 0x0232)
+#define NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND (0xC0000000 | 0x0233)
+#define NT_STATUS_ACCOUNT_LOCKED_OUT (0xC0000000 | 0x0234)
+#define NT_STATUS_HANDLE_NOT_CLOSABLE (0xC0000000 | 0x0235)
+#define NT_STATUS_CONNECTION_REFUSED (0xC0000000 | 0x0236)
+#define NT_STATUS_GRACEFUL_DISCONNECT (0xC0000000 | 0x0237)
+#define NT_STATUS_ADDRESS_ALREADY_ASSOCIATED (0xC0000000 | 0x0238)
+#define NT_STATUS_ADDRESS_NOT_ASSOCIATED (0xC0000000 | 0x0239)
+#define NT_STATUS_CONNECTION_INVALID (0xC0000000 | 0x023a)
+#define NT_STATUS_CONNECTION_ACTIVE (0xC0000000 | 0x023b)
+#define NT_STATUS_NETWORK_UNREACHABLE (0xC0000000 | 0x023c)
+#define NT_STATUS_HOST_UNREACHABLE (0xC0000000 | 0x023d)
+#define NT_STATUS_PROTOCOL_UNREACHABLE (0xC0000000 | 0x023e)
+#define NT_STATUS_PORT_UNREACHABLE (0xC0000000 | 0x023f)
+#define NT_STATUS_REQUEST_ABORTED (0xC0000000 | 0x0240)
+#define NT_STATUS_CONNECTION_ABORTED (0xC0000000 | 0x0241)
+#define NT_STATUS_BAD_COMPRESSION_BUFFER (0xC0000000 | 0x0242)
+#define NT_STATUS_USER_MAPPED_FILE (0xC0000000 | 0x0243)
+#define NT_STATUS_AUDIT_FAILED (0xC0000000 | 0x0244)
+#define NT_STATUS_TIMER_RESOLUTION_NOT_SET (0xC0000000 | 0x0245)
+#define NT_STATUS_CONNECTION_COUNT_LIMIT (0xC0000000 | 0x0246)
+#define NT_STATUS_LOGIN_TIME_RESTRICTION (0xC0000000 | 0x0247)
+#define NT_STATUS_LOGIN_WKSTA_RESTRICTION (0xC0000000 | 0x0248)
+#define NT_STATUS_IMAGE_MP_UP_MISMATCH (0xC0000000 | 0x0249)
+#define NT_STATUS_INSUFFICIENT_LOGON_INFO (0xC0000000 | 0x0250)
+#define NT_STATUS_BAD_DLL_ENTRYPOINT (0xC0000000 | 0x0251)
+#define NT_STATUS_BAD_SERVICE_ENTRYPOINT (0xC0000000 | 0x0252)
+#define NT_STATUS_LPC_REPLY_LOST (0xC0000000 | 0x0253)
+#define NT_STATUS_IP_ADDRESS_CONFLICT1 (0xC0000000 | 0x0254)
+#define NT_STATUS_IP_ADDRESS_CONFLICT2 (0xC0000000 | 0x0255)
+#define NT_STATUS_REGISTRY_QUOTA_LIMIT (0xC0000000 | 0x0256)
+#define NT_STATUS_PATH_NOT_COVERED (0xC0000000 | 0x0257)
+#define NT_STATUS_NO_CALLBACK_ACTIVE (0xC0000000 | 0x0258)
+#define NT_STATUS_LICENSE_QUOTA_EXCEEDED (0xC0000000 | 0x0259)
+#define NT_STATUS_PWD_TOO_SHORT (0xC0000000 | 0x025a)
+#define NT_STATUS_PWD_TOO_RECENT (0xC0000000 | 0x025b)
+#define NT_STATUS_PWD_HISTORY_CONFLICT (0xC0000000 | 0x025c)
+#define NT_STATUS_PLUGPLAY_NO_DEVICE (0xC0000000 | 0x025e)
+#define NT_STATUS_UNSUPPORTED_COMPRESSION (0xC0000000 | 0x025f)
+#define NT_STATUS_INVALID_HW_PROFILE (0xC0000000 | 0x0260)
+#define NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH (0xC0000000 | 0x0261)
+#define NT_STATUS_DRIVER_ORDINAL_NOT_FOUND (0xC0000000 | 0x0262)
+#define NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND (0xC0000000 | 0x0263)
+#define NT_STATUS_RESOURCE_NOT_OWNED (0xC0000000 | 0x0264)
+#define NT_STATUS_TOO_MANY_LINKS (0xC0000000 | 0x0265)
+#define NT_STATUS_QUOTA_LIST_INCONSISTENT (0xC0000000 | 0x0266)
+#define NT_STATUS_FILE_IS_OFFLINE (0xC0000000 | 0x0267)
+#define NT_STATUS_NOT_A_REPARSE_POINT (0xC0000000 | 0x0275)
+#define NT_STATUS_NETWORK_SESSION_EXPIRED (0xC0000000 | 0x035c)
+#define NT_STATUS_NO_SUCH_JOB (0xC0000000 | 0xEDE) /* scheduler */
+#define NT_STATUS_NO_PREAUTH_INTEGRITY_HASH_OVERLAP (0xC0000000 | 0x5D0000)
#endif /* _NTERR_H */
diff --git a/fs/smb/common/fscc.h b/fs/smb/common/fscc.h
index 35dbacdbb902..0123f34db1e8 100644
--- a/fs/smb/common/fscc.h
+++ b/fs/smb/common/fscc.h
@@ -145,6 +145,62 @@ typedef struct {
} __packed FILE_SYSTEM_DEVICE_INFO; /* device info level 0x104 */
/*
+ * File Attributes
+ * See MS-FSCC 2.6
+ */
+#define FILE_ATTRIBUTE_READONLY 0x00000001
+#define FILE_ATTRIBUTE_HIDDEN 0x00000002
+#define FILE_ATTRIBUTE_SYSTEM 0x00000004
+#define FILE_ATTRIBUTE_DIRECTORY 0x00000010
+#define FILE_ATTRIBUTE_ARCHIVE 0x00000020
+#define FILE_ATTRIBUTE_NORMAL 0x00000080
+#define FILE_ATTRIBUTE_TEMPORARY 0x00000100
+#define FILE_ATTRIBUTE_SPARSE_FILE 0x00000200
+#define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400
+#define FILE_ATTRIBUTE_COMPRESSED 0x00000800
+#define FILE_ATTRIBUTE_OFFLINE 0x00001000
+#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000
+#define FILE_ATTRIBUTE_ENCRYPTED 0x00004000
+#define FILE_ATTRIBUTE_INTEGRITY_STREAM 0x00008000
+#define FILE_ATTRIBUTE_NO_SCRUB_DATA 0x00020000
+#define FILE_ATTRIBUTE_MASK (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | \
+ FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY | \
+ FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_NORMAL | \
+ FILE_ATTRIBUTE_TEMPORARY | FILE_ATTRIBUTE_SPARSE_FILE | \
+ FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_COMPRESSED | \
+ FILE_ATTRIBUTE_OFFLINE | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | \
+ FILE_ATTRIBUTE_ENCRYPTED | FILE_ATTRIBUTE_INTEGRITY_STREAM | \
+ FILE_ATTRIBUTE_NO_SCRUB_DATA)
+
+#define FILE_ATTRIBUTE_READONLY_LE cpu_to_le32(FILE_ATTRIBUTE_READONLY)
+#define FILE_ATTRIBUTE_HIDDEN_LE cpu_to_le32(FILE_ATTRIBUTE_HIDDEN)
+#define FILE_ATTRIBUTE_SYSTEM_LE cpu_to_le32(FILE_ATTRIBUTE_SYSTEM)
+#define FILE_ATTRIBUTE_DIRECTORY_LE cpu_to_le32(FILE_ATTRIBUTE_DIRECTORY)
+#define FILE_ATTRIBUTE_ARCHIVE_LE cpu_to_le32(FILE_ATTRIBUTE_ARCHIVE)
+#define FILE_ATTRIBUTE_NORMAL_LE cpu_to_le32(FILE_ATTRIBUTE_NORMAL)
+#define FILE_ATTRIBUTE_TEMPORARY_LE cpu_to_le32(FILE_ATTRIBUTE_TEMPORARY)
+#define FILE_ATTRIBUTE_SPARSE_FILE_LE cpu_to_le32(FILE_ATTRIBUTE_SPARSE_FILE)
+#define FILE_ATTRIBUTE_REPARSE_POINT_LE cpu_to_le32(FILE_ATTRIBUTE_REPARSE_POINT)
+#define FILE_ATTRIBUTE_COMPRESSED_LE cpu_to_le32(FILE_ATTRIBUTE_COMPRESSED)
+#define FILE_ATTRIBUTE_OFFLINE_LE cpu_to_le32(FILE_ATTRIBUTE_OFFLINE)
+#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED_LE cpu_to_le32(FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
+#define FILE_ATTRIBUTE_ENCRYPTED_LE cpu_to_le32(FILE_ATTRIBUTE_ENCRYPTED)
+#define FILE_ATTRIBUTE_INTEGRITY_STREAM_LE cpu_to_le32(FILE_ATTRIBUTE_INTEGRITY_STREAM)
+#define FILE_ATTRIBUTE_NO_SCRUB_DATA_LE cpu_to_le32(FILE_ATTRIBUTE_NO_SCRUB_DATA)
+#define FILE_ATTRIBUTE_MASK_LE cpu_to_le32(FILE_ATTRIBUTE_MASK)
+
+/*
+ * Response contains array of the following structures
+ * See MS-FSCC 2.7.1
+ */
+struct file_notify_information {
+ __le32 NextEntryOffset;
+ __le32 Action;
+ __le32 FileNameLength;
+ __u8 FileName[];
+} __packed;
+
+/*
* See POSIX Extensions to MS-FSCC 2.3.2.1
* Link: https://gitlab.com/samba-team/smb3-posix-spec/-/blob/master/fscc_posix_extensions.md
*/
diff --git a/fs/smb/common/smb2pdu.h b/fs/smb/common/smb2pdu.h
index 945a8e0cf36c..3c8d8a4e7439 100644
--- a/fs/smb/common/smb2pdu.h
+++ b/fs/smb/common/smb2pdu.h
@@ -991,6 +991,7 @@ struct smb2_set_info_rsp {
/* notify completion filter flags. See MS-FSCC 2.6 and MS-SMB2 2.2.35 */
#define FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001
#define FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002
+#define FILE_NOTIFY_CHANGE_NAME 0x00000003
#define FILE_NOTIFY_CHANGE_ATTRIBUTES 0x00000004
#define FILE_NOTIFY_CHANGE_SIZE 0x00000008
#define FILE_NOTIFY_CHANGE_LAST_WRITE 0x00000010
@@ -1002,7 +1003,10 @@ struct smb2_set_info_rsp {
#define FILE_NOTIFY_CHANGE_STREAM_SIZE 0x00000400
#define FILE_NOTIFY_CHANGE_STREAM_WRITE 0x00000800
-/* SMB2 Notify Action Flags */
+/*
+ * SMB2 Notify Action Flags
+ * See MS-FSCC 2.7.1
+ */
#define FILE_ACTION_ADDED 0x00000001
#define FILE_ACTION_REMOVED 0x00000002
#define FILE_ACTION_MODIFIED 0x00000003
@@ -1012,7 +1016,10 @@ struct smb2_set_info_rsp {
#define FILE_ACTION_REMOVED_STREAM 0x00000007
#define FILE_ACTION_MODIFIED_STREAM 0x00000008
#define FILE_ACTION_REMOVED_BY_DELETE 0x00000009
+#define FILE_ACTION_ID_NOT_TUNNELLED 0x0000000A
+#define FILE_ACTION_TUNNELLED_ID_COLLISION 0x0000000B
+/* See MS-SMB2 2.2.35 */
struct smb2_change_notify_req {
struct smb2_hdr hdr;
__le16 StructureSize;
@@ -1024,6 +1031,7 @@ struct smb2_change_notify_req {
__u32 Reserved;
} __packed;
+/* See MS-SMB2 2.2.36 */
struct smb2_change_notify_rsp {
struct smb2_hdr hdr;
__le16 StructureSize; /* Must be 9 */
@@ -1064,41 +1072,6 @@ struct smb2_server_client_notification {
#define IL_IMPERSONATION cpu_to_le32(0x00000002)
#define IL_DELEGATE cpu_to_le32(0x00000003)
-/* File Attributes */
-#define FILE_ATTRIBUTE_READONLY 0x00000001
-#define FILE_ATTRIBUTE_HIDDEN 0x00000002
-#define FILE_ATTRIBUTE_SYSTEM 0x00000004
-#define FILE_ATTRIBUTE_DIRECTORY 0x00000010
-#define FILE_ATTRIBUTE_ARCHIVE 0x00000020
-#define FILE_ATTRIBUTE_NORMAL 0x00000080
-#define FILE_ATTRIBUTE_TEMPORARY 0x00000100
-#define FILE_ATTRIBUTE_SPARSE_FILE 0x00000200
-#define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400
-#define FILE_ATTRIBUTE_COMPRESSED 0x00000800
-#define FILE_ATTRIBUTE_OFFLINE 0x00001000
-#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000
-#define FILE_ATTRIBUTE_ENCRYPTED 0x00004000
-#define FILE_ATTRIBUTE_INTEGRITY_STREAM 0x00008000
-#define FILE_ATTRIBUTE_NO_SCRUB_DATA 0x00020000
-#define FILE_ATTRIBUTE__MASK 0x00007FB7
-
-#define FILE_ATTRIBUTE_READONLY_LE cpu_to_le32(0x00000001)
-#define FILE_ATTRIBUTE_HIDDEN_LE cpu_to_le32(0x00000002)
-#define FILE_ATTRIBUTE_SYSTEM_LE cpu_to_le32(0x00000004)
-#define FILE_ATTRIBUTE_DIRECTORY_LE cpu_to_le32(0x00000010)
-#define FILE_ATTRIBUTE_ARCHIVE_LE cpu_to_le32(0x00000020)
-#define FILE_ATTRIBUTE_NORMAL_LE cpu_to_le32(0x00000080)
-#define FILE_ATTRIBUTE_TEMPORARY_LE cpu_to_le32(0x00000100)
-#define FILE_ATTRIBUTE_SPARSE_FILE_LE cpu_to_le32(0x00000200)
-#define FILE_ATTRIBUTE_REPARSE_POINT_LE cpu_to_le32(0x00000400)
-#define FILE_ATTRIBUTE_COMPRESSED_LE cpu_to_le32(0x00000800)
-#define FILE_ATTRIBUTE_OFFLINE_LE cpu_to_le32(0x00001000)
-#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED_LE cpu_to_le32(0x00002000)
-#define FILE_ATTRIBUTE_ENCRYPTED_LE cpu_to_le32(0x00004000)
-#define FILE_ATTRIBUTE_INTEGRITY_STREAM_LE cpu_to_le32(0x00008000)
-#define FILE_ATTRIBUTE_NO_SCRUB_DATA_LE cpu_to_le32(0x00020000)
-#define FILE_ATTRIBUTE_MASK_LE cpu_to_le32(0x00007FB7)
-
/* Desired Access Flags */
#define FILE_READ_DATA_LE cpu_to_le32(0x00000001)
#define FILE_LIST_DIRECTORY_LE cpu_to_le32(0x00000001)
@@ -1537,9 +1510,10 @@ struct duplicate_extents_to_file {
__le64 ByteCount; /* Bytes to be copied */
} __packed;
-/* See MS-FSCC 2.3.8 */
+/* See MS-FSCC 2.3.9 */
#define DUPLICATE_EXTENTS_DATA_EX_SOURCE_ATOMIC 0x00000001
struct duplicate_extents_to_file_ex {
+ __le64 StructureSize; /* MUST be set to 0x30 */
__u64 PersistentFileHandle; /* source file handle, opaque endianness */
__u64 VolatileFileHandle;
__le64 SourceFileOffset;
diff --git a/fs/smb/server/nterr.h b/fs/smb/server/nterr.h
deleted file mode 100644
index 2f358f88a018..000000000000
--- a/fs/smb/server/nterr.h
+++ /dev/null
@@ -1,543 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Unix SMB/Netbios implementation.
- * Version 1.9.
- * NT error code constants
- * Copyright (C) Andrew Tridgell 1992-2000
- * Copyright (C) John H Terpstra 1996-2000
- * Copyright (C) Luke Kenneth Casson Leighton 1996-2000
- * Copyright (C) Paul Ashton 1998-2000
- */
-
-#ifndef _NTERR_H
-#define _NTERR_H
-
-/* Win32 Status codes. */
-#define NT_STATUS_MORE_ENTRIES 0x0105
-#define NT_ERROR_INVALID_PARAMETER 0x0057
-#define NT_ERROR_INSUFFICIENT_BUFFER 0x007a
-#define NT_STATUS_1804 0x070c
-#define NT_STATUS_NOTIFY_ENUM_DIR 0x010c
-#define NT_STATUS_INVALID_LOCK_RANGE (0xC0000000 | 0x01a1)
-/*
- * Win32 Error codes extracted using a loop in smbclient then printing a netmon
- * sniff to a file.
- */
-
-#define NT_STATUS_OK 0x0000
-#define NT_STATUS_SOME_UNMAPPED 0x0107
-#define NT_STATUS_BUFFER_OVERFLOW 0x80000005
-#define NT_STATUS_NO_MORE_ENTRIES 0x8000001a
-#define NT_STATUS_MEDIA_CHANGED 0x8000001c
-#define NT_STATUS_END_OF_MEDIA 0x8000001e
-#define NT_STATUS_MEDIA_CHECK 0x80000020
-#define NT_STATUS_NO_DATA_DETECTED 0x8000001c
-#define NT_STATUS_STOPPED_ON_SYMLINK 0x8000002d
-#define NT_STATUS_DEVICE_REQUIRES_CLEANING 0x80000288
-#define NT_STATUS_DEVICE_DOOR_OPEN 0x80000288
-#define NT_STATUS_UNSUCCESSFUL (0xC0000000 | 0x0001)
-#define NT_STATUS_NOT_IMPLEMENTED (0xC0000000 | 0x0002)
-#define NT_STATUS_INVALID_INFO_CLASS (0xC0000000 | 0x0003)
-#define NT_STATUS_INFO_LENGTH_MISMATCH (0xC0000000 | 0x0004)
-#define NT_STATUS_ACCESS_VIOLATION (0xC0000000 | 0x0005)
-#define NT_STATUS_IN_PAGE_ERROR (0xC0000000 | 0x0006)
-#define NT_STATUS_PAGEFILE_QUOTA (0xC0000000 | 0x0007)
-#define NT_STATUS_INVALID_HANDLE (0xC0000000 | 0x0008)
-#define NT_STATUS_BAD_INITIAL_STACK (0xC0000000 | 0x0009)
-#define NT_STATUS_BAD_INITIAL_PC (0xC0000000 | 0x000a)
-#define NT_STATUS_INVALID_CID (0xC0000000 | 0x000b)
-#define NT_STATUS_TIMER_NOT_CANCELED (0xC0000000 | 0x000c)
-#define NT_STATUS_INVALID_PARAMETER (0xC0000000 | 0x000d)
-#define NT_STATUS_NO_SUCH_DEVICE (0xC0000000 | 0x000e)
-#define NT_STATUS_NO_SUCH_FILE (0xC0000000 | 0x000f)
-#define NT_STATUS_INVALID_DEVICE_REQUEST (0xC0000000 | 0x0010)
-#define NT_STATUS_END_OF_FILE (0xC0000000 | 0x0011)
-#define NT_STATUS_WRONG_VOLUME (0xC0000000 | 0x0012)
-#define NT_STATUS_NO_MEDIA_IN_DEVICE (0xC0000000 | 0x0013)
-#define NT_STATUS_UNRECOGNIZED_MEDIA (0xC0000000 | 0x0014)
-#define NT_STATUS_NONEXISTENT_SECTOR (0xC0000000 | 0x0015)
-#define NT_STATUS_MORE_PROCESSING_REQUIRED (0xC0000000 | 0x0016)
-#define NT_STATUS_NO_MEMORY (0xC0000000 | 0x0017)
-#define NT_STATUS_CONFLICTING_ADDRESSES (0xC0000000 | 0x0018)
-#define NT_STATUS_NOT_MAPPED_VIEW (0xC0000000 | 0x0019)
-#define NT_STATUS_UNABLE_TO_FREE_VM (0x80000000 | 0x001a)
-#define NT_STATUS_UNABLE_TO_DELETE_SECTION (0xC0000000 | 0x001b)
-#define NT_STATUS_INVALID_SYSTEM_SERVICE (0xC0000000 | 0x001c)
-#define NT_STATUS_ILLEGAL_INSTRUCTION (0xC0000000 | 0x001d)
-#define NT_STATUS_INVALID_LOCK_SEQUENCE (0xC0000000 | 0x001e)
-#define NT_STATUS_INVALID_VIEW_SIZE (0xC0000000 | 0x001f)
-#define NT_STATUS_INVALID_FILE_FOR_SECTION (0xC0000000 | 0x0020)
-#define NT_STATUS_ALREADY_COMMITTED (0xC0000000 | 0x0021)
-#define NT_STATUS_ACCESS_DENIED (0xC0000000 | 0x0022)
-#define NT_STATUS_BUFFER_TOO_SMALL (0xC0000000 | 0x0023)
-#define NT_STATUS_OBJECT_TYPE_MISMATCH (0xC0000000 | 0x0024)
-#define NT_STATUS_NONCONTINUABLE_EXCEPTION (0xC0000000 | 0x0025)
-#define NT_STATUS_INVALID_DISPOSITION (0xC0000000 | 0x0026)
-#define NT_STATUS_UNWIND (0xC0000000 | 0x0027)
-#define NT_STATUS_BAD_STACK (0xC0000000 | 0x0028)
-#define NT_STATUS_INVALID_UNWIND_TARGET (0xC0000000 | 0x0029)
-#define NT_STATUS_NOT_LOCKED (0xC0000000 | 0x002a)
-#define NT_STATUS_PARITY_ERROR (0xC0000000 | 0x002b)
-#define NT_STATUS_UNABLE_TO_DECOMMIT_VM (0xC0000000 | 0x002c)
-#define NT_STATUS_NOT_COMMITTED (0xC0000000 | 0x002d)
-#define NT_STATUS_INVALID_PORT_ATTRIBUTES (0xC0000000 | 0x002e)
-#define NT_STATUS_PORT_MESSAGE_TOO_LONG (0xC0000000 | 0x002f)
-#define NT_STATUS_INVALID_PARAMETER_MIX (0xC0000000 | 0x0030)
-#define NT_STATUS_INVALID_QUOTA_LOWER (0xC0000000 | 0x0031)
-#define NT_STATUS_DISK_CORRUPT_ERROR (0xC0000000 | 0x0032)
-#define NT_STATUS_OBJECT_NAME_INVALID (0xC0000000 | 0x0033)
-#define NT_STATUS_OBJECT_NAME_NOT_FOUND (0xC0000000 | 0x0034)
-#define NT_STATUS_OBJECT_NAME_COLLISION (0xC0000000 | 0x0035)
-#define NT_STATUS_HANDLE_NOT_WAITABLE (0xC0000000 | 0x0036)
-#define NT_STATUS_PORT_DISCONNECTED (0xC0000000 | 0x0037)
-#define NT_STATUS_DEVICE_ALREADY_ATTACHED (0xC0000000 | 0x0038)
-#define NT_STATUS_OBJECT_PATH_INVALID (0xC0000000 | 0x0039)
-#define NT_STATUS_OBJECT_PATH_NOT_FOUND (0xC0000000 | 0x003a)
-#define NT_STATUS_OBJECT_PATH_SYNTAX_BAD (0xC0000000 | 0x003b)
-#define NT_STATUS_DATA_OVERRUN (0xC0000000 | 0x003c)
-#define NT_STATUS_DATA_LATE_ERROR (0xC0000000 | 0x003d)
-#define NT_STATUS_DATA_ERROR (0xC0000000 | 0x003e)
-#define NT_STATUS_CRC_ERROR (0xC0000000 | 0x003f)
-#define NT_STATUS_SECTION_TOO_BIG (0xC0000000 | 0x0040)
-#define NT_STATUS_PORT_CONNECTION_REFUSED (0xC0000000 | 0x0041)
-#define NT_STATUS_INVALID_PORT_HANDLE (0xC0000000 | 0x0042)
-#define NT_STATUS_SHARING_VIOLATION (0xC0000000 | 0x0043)
-#define NT_STATUS_QUOTA_EXCEEDED (0xC0000000 | 0x0044)
-#define NT_STATUS_INVALID_PAGE_PROTECTION (0xC0000000 | 0x0045)
-#define NT_STATUS_MUTANT_NOT_OWNED (0xC0000000 | 0x0046)
-#define NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED (0xC0000000 | 0x0047)
-#define NT_STATUS_PORT_ALREADY_SET (0xC0000000 | 0x0048)
-#define NT_STATUS_SECTION_NOT_IMAGE (0xC0000000 | 0x0049)
-#define NT_STATUS_SUSPEND_COUNT_EXCEEDED (0xC0000000 | 0x004a)
-#define NT_STATUS_THREAD_IS_TERMINATING (0xC0000000 | 0x004b)
-#define NT_STATUS_BAD_WORKING_SET_LIMIT (0xC0000000 | 0x004c)
-#define NT_STATUS_INCOMPATIBLE_FILE_MAP (0xC0000000 | 0x004d)
-#define NT_STATUS_SECTION_PROTECTION (0xC0000000 | 0x004e)
-#define NT_STATUS_EAS_NOT_SUPPORTED (0xC0000000 | 0x004f)
-#define NT_STATUS_EA_TOO_LARGE (0xC0000000 | 0x0050)
-#define NT_STATUS_NONEXISTENT_EA_ENTRY (0xC0000000 | 0x0051)
-#define NT_STATUS_NO_EAS_ON_FILE (0xC0000000 | 0x0052)
-#define NT_STATUS_EA_CORRUPT_ERROR (0xC0000000 | 0x0053)
-#define NT_STATUS_FILE_LOCK_CONFLICT (0xC0000000 | 0x0054)
-#define NT_STATUS_LOCK_NOT_GRANTED (0xC0000000 | 0x0055)
-#define NT_STATUS_DELETE_PENDING (0xC0000000 | 0x0056)
-#define NT_STATUS_CTL_FILE_NOT_SUPPORTED (0xC0000000 | 0x0057)
-#define NT_STATUS_UNKNOWN_REVISION (0xC0000000 | 0x0058)
-#define NT_STATUS_REVISION_MISMATCH (0xC0000000 | 0x0059)
-#define NT_STATUS_INVALID_OWNER (0xC0000000 | 0x005a)
-#define NT_STATUS_INVALID_PRIMARY_GROUP (0xC0000000 | 0x005b)
-#define NT_STATUS_NO_IMPERSONATION_TOKEN (0xC0000000 | 0x005c)
-#define NT_STATUS_CANT_DISABLE_MANDATORY (0xC0000000 | 0x005d)
-#define NT_STATUS_NO_LOGON_SERVERS (0xC0000000 | 0x005e)
-#define NT_STATUS_NO_SUCH_LOGON_SESSION (0xC0000000 | 0x005f)
-#define NT_STATUS_NO_SUCH_PRIVILEGE (0xC0000000 | 0x0060)
-#define NT_STATUS_PRIVILEGE_NOT_HELD (0xC0000000 | 0x0061)
-#define NT_STATUS_INVALID_ACCOUNT_NAME (0xC0000000 | 0x0062)
-#define NT_STATUS_USER_EXISTS (0xC0000000 | 0x0063)
-#define NT_STATUS_NO_SUCH_USER (0xC0000000 | 0x0064)
-#define NT_STATUS_GROUP_EXISTS (0xC0000000 | 0x0065)
-#define NT_STATUS_NO_SUCH_GROUP (0xC0000000 | 0x0066)
-#define NT_STATUS_MEMBER_IN_GROUP (0xC0000000 | 0x0067)
-#define NT_STATUS_MEMBER_NOT_IN_GROUP (0xC0000000 | 0x0068)
-#define NT_STATUS_LAST_ADMIN (0xC0000000 | 0x0069)
-#define NT_STATUS_WRONG_PASSWORD (0xC0000000 | 0x006a)
-#define NT_STATUS_ILL_FORMED_PASSWORD (0xC0000000 | 0x006b)
-#define NT_STATUS_PASSWORD_RESTRICTION (0xC0000000 | 0x006c)
-#define NT_STATUS_LOGON_FAILURE (0xC0000000 | 0x006d)
-#define NT_STATUS_ACCOUNT_RESTRICTION (0xC0000000 | 0x006e)
-#define NT_STATUS_INVALID_LOGON_HOURS (0xC0000000 | 0x006f)
-#define NT_STATUS_INVALID_WORKSTATION (0xC0000000 | 0x0070)
-#define NT_STATUS_PASSWORD_EXPIRED (0xC0000000 | 0x0071)
-#define NT_STATUS_ACCOUNT_DISABLED (0xC0000000 | 0x0072)
-#define NT_STATUS_NONE_MAPPED (0xC0000000 | 0x0073)
-#define NT_STATUS_TOO_MANY_LUIDS_REQUESTED (0xC0000000 | 0x0074)
-#define NT_STATUS_LUIDS_EXHAUSTED (0xC0000000 | 0x0075)
-#define NT_STATUS_INVALID_SUB_AUTHORITY (0xC0000000 | 0x0076)
-#define NT_STATUS_INVALID_ACL (0xC0000000 | 0x0077)
-#define NT_STATUS_INVALID_SID (0xC0000000 | 0x0078)
-#define NT_STATUS_INVALID_SECURITY_DESCR (0xC0000000 | 0x0079)
-#define NT_STATUS_PROCEDURE_NOT_FOUND (0xC0000000 | 0x007a)
-#define NT_STATUS_INVALID_IMAGE_FORMAT (0xC0000000 | 0x007b)
-#define NT_STATUS_NO_TOKEN (0xC0000000 | 0x007c)
-#define NT_STATUS_BAD_INHERITANCE_ACL (0xC0000000 | 0x007d)
-#define NT_STATUS_RANGE_NOT_LOCKED (0xC0000000 | 0x007e)
-#define NT_STATUS_DISK_FULL (0xC0000000 | 0x007f)
-#define NT_STATUS_SERVER_DISABLED (0xC0000000 | 0x0080)
-#define NT_STATUS_SERVER_NOT_DISABLED (0xC0000000 | 0x0081)
-#define NT_STATUS_TOO_MANY_GUIDS_REQUESTED (0xC0000000 | 0x0082)
-#define NT_STATUS_GUIDS_EXHAUSTED (0xC0000000 | 0x0083)
-#define NT_STATUS_INVALID_ID_AUTHORITY (0xC0000000 | 0x0084)
-#define NT_STATUS_AGENTS_EXHAUSTED (0xC0000000 | 0x0085)
-#define NT_STATUS_INVALID_VOLUME_LABEL (0xC0000000 | 0x0086)
-#define NT_STATUS_SECTION_NOT_EXTENDED (0xC0000000 | 0x0087)
-#define NT_STATUS_NOT_MAPPED_DATA (0xC0000000 | 0x0088)
-#define NT_STATUS_RESOURCE_DATA_NOT_FOUND (0xC0000000 | 0x0089)
-#define NT_STATUS_RESOURCE_TYPE_NOT_FOUND (0xC0000000 | 0x008a)
-#define NT_STATUS_RESOURCE_NAME_NOT_FOUND (0xC0000000 | 0x008b)
-#define NT_STATUS_ARRAY_BOUNDS_EXCEEDED (0xC0000000 | 0x008c)
-#define NT_STATUS_FLOAT_DENORMAL_OPERAND (0xC0000000 | 0x008d)
-#define NT_STATUS_FLOAT_DIVIDE_BY_ZERO (0xC0000000 | 0x008e)
-#define NT_STATUS_FLOAT_INEXACT_RESULT (0xC0000000 | 0x008f)
-#define NT_STATUS_FLOAT_INVALID_OPERATION (0xC0000000 | 0x0090)
-#define NT_STATUS_FLOAT_OVERFLOW (0xC0000000 | 0x0091)
-#define NT_STATUS_FLOAT_STACK_CHECK (0xC0000000 | 0x0092)
-#define NT_STATUS_FLOAT_UNDERFLOW (0xC0000000 | 0x0093)
-#define NT_STATUS_INTEGER_DIVIDE_BY_ZERO (0xC0000000 | 0x0094)
-#define NT_STATUS_INTEGER_OVERFLOW (0xC0000000 | 0x0095)
-#define NT_STATUS_PRIVILEGED_INSTRUCTION (0xC0000000 | 0x0096)
-#define NT_STATUS_TOO_MANY_PAGING_FILES (0xC0000000 | 0x0097)
-#define NT_STATUS_FILE_INVALID (0xC0000000 | 0x0098)
-#define NT_STATUS_ALLOTTED_SPACE_EXCEEDED (0xC0000000 | 0x0099)
-#define NT_STATUS_INSUFFICIENT_RESOURCES (0xC0000000 | 0x009a)
-#define NT_STATUS_DFS_EXIT_PATH_FOUND (0xC0000000 | 0x009b)
-#define NT_STATUS_DEVICE_DATA_ERROR (0xC0000000 | 0x009c)
-#define NT_STATUS_DEVICE_NOT_CONNECTED (0xC0000000 | 0x009d)
-#define NT_STATUS_DEVICE_POWER_FAILURE (0xC0000000 | 0x009e)
-#define NT_STATUS_FREE_VM_NOT_AT_BASE (0xC0000000 | 0x009f)
-#define NT_STATUS_MEMORY_NOT_ALLOCATED (0xC0000000 | 0x00a0)
-#define NT_STATUS_WORKING_SET_QUOTA (0xC0000000 | 0x00a1)
-#define NT_STATUS_MEDIA_WRITE_PROTECTED (0xC0000000 | 0x00a2)
-#define NT_STATUS_DEVICE_NOT_READY (0xC0000000 | 0x00a3)
-#define NT_STATUS_INVALID_GROUP_ATTRIBUTES (0xC0000000 | 0x00a4)
-#define NT_STATUS_BAD_IMPERSONATION_LEVEL (0xC0000000 | 0x00a5)
-#define NT_STATUS_CANT_OPEN_ANONYMOUS (0xC0000000 | 0x00a6)
-#define NT_STATUS_BAD_VALIDATION_CLASS (0xC0000000 | 0x00a7)
-#define NT_STATUS_BAD_TOKEN_TYPE (0xC0000000 | 0x00a8)
-#define NT_STATUS_BAD_MASTER_BOOT_RECORD (0xC0000000 | 0x00a9)
-#define NT_STATUS_INSTRUCTION_MISALIGNMENT (0xC0000000 | 0x00aa)
-#define NT_STATUS_INSTANCE_NOT_AVAILABLE (0xC0000000 | 0x00ab)
-#define NT_STATUS_PIPE_NOT_AVAILABLE (0xC0000000 | 0x00ac)
-#define NT_STATUS_INVALID_PIPE_STATE (0xC0000000 | 0x00ad)
-#define NT_STATUS_PIPE_BUSY (0xC0000000 | 0x00ae)
-#define NT_STATUS_ILLEGAL_FUNCTION (0xC0000000 | 0x00af)
-#define NT_STATUS_PIPE_DISCONNECTED (0xC0000000 | 0x00b0)
-#define NT_STATUS_PIPE_CLOSING (0xC0000000 | 0x00b1)
-#define NT_STATUS_PIPE_CONNECTED (0xC0000000 | 0x00b2)
-#define NT_STATUS_PIPE_LISTENING (0xC0000000 | 0x00b3)
-#define NT_STATUS_INVALID_READ_MODE (0xC0000000 | 0x00b4)
-#define NT_STATUS_IO_TIMEOUT (0xC0000000 | 0x00b5)
-#define NT_STATUS_FILE_FORCED_CLOSED (0xC0000000 | 0x00b6)
-#define NT_STATUS_PROFILING_NOT_STARTED (0xC0000000 | 0x00b7)
-#define NT_STATUS_PROFILING_NOT_STOPPED (0xC0000000 | 0x00b8)
-#define NT_STATUS_COULD_NOT_INTERPRET (0xC0000000 | 0x00b9)
-#define NT_STATUS_FILE_IS_A_DIRECTORY (0xC0000000 | 0x00ba)
-#define NT_STATUS_NOT_SUPPORTED (0xC0000000 | 0x00bb)
-#define NT_STATUS_REMOTE_NOT_LISTENING (0xC0000000 | 0x00bc)
-#define NT_STATUS_DUPLICATE_NAME (0xC0000000 | 0x00bd)
-#define NT_STATUS_BAD_NETWORK_PATH (0xC0000000 | 0x00be)
-#define NT_STATUS_NETWORK_BUSY (0xC0000000 | 0x00bf)
-#define NT_STATUS_DEVICE_DOES_NOT_EXIST (0xC0000000 | 0x00c0)
-#define NT_STATUS_TOO_MANY_COMMANDS (0xC0000000 | 0x00c1)
-#define NT_STATUS_ADAPTER_HARDWARE_ERROR (0xC0000000 | 0x00c2)
-#define NT_STATUS_INVALID_NETWORK_RESPONSE (0xC0000000 | 0x00c3)
-#define NT_STATUS_UNEXPECTED_NETWORK_ERROR (0xC0000000 | 0x00c4)
-#define NT_STATUS_BAD_REMOTE_ADAPTER (0xC0000000 | 0x00c5)
-#define NT_STATUS_PRINT_QUEUE_FULL (0xC0000000 | 0x00c6)
-#define NT_STATUS_NO_SPOOL_SPACE (0xC0000000 | 0x00c7)
-#define NT_STATUS_PRINT_CANCELLED (0xC0000000 | 0x00c8)
-#define NT_STATUS_NETWORK_NAME_DELETED (0xC0000000 | 0x00c9)
-#define NT_STATUS_NETWORK_ACCESS_DENIED (0xC0000000 | 0x00ca)
-#define NT_STATUS_BAD_DEVICE_TYPE (0xC0000000 | 0x00cb)
-#define NT_STATUS_BAD_NETWORK_NAME (0xC0000000 | 0x00cc)
-#define NT_STATUS_TOO_MANY_NAMES (0xC0000000 | 0x00cd)
-#define NT_STATUS_TOO_MANY_SESSIONS (0xC0000000 | 0x00ce)
-#define NT_STATUS_SHARING_PAUSED (0xC0000000 | 0x00cf)
-#define NT_STATUS_REQUEST_NOT_ACCEPTED (0xC0000000 | 0x00d0)
-#define NT_STATUS_REDIRECTOR_PAUSED (0xC0000000 | 0x00d1)
-#define NT_STATUS_NET_WRITE_FAULT (0xC0000000 | 0x00d2)
-#define NT_STATUS_PROFILING_AT_LIMIT (0xC0000000 | 0x00d3)
-#define NT_STATUS_NOT_SAME_DEVICE (0xC0000000 | 0x00d4)
-#define NT_STATUS_FILE_RENAMED (0xC0000000 | 0x00d5)
-#define NT_STATUS_VIRTUAL_CIRCUIT_CLOSED (0xC0000000 | 0x00d6)
-#define NT_STATUS_NO_SECURITY_ON_OBJECT (0xC0000000 | 0x00d7)
-#define NT_STATUS_CANT_WAIT (0xC0000000 | 0x00d8)
-#define NT_STATUS_PIPE_EMPTY (0xC0000000 | 0x00d9)
-#define NT_STATUS_CANT_ACCESS_DOMAIN_INFO (0xC0000000 | 0x00da)
-#define NT_STATUS_CANT_TERMINATE_SELF (0xC0000000 | 0x00db)
-#define NT_STATUS_INVALID_SERVER_STATE (0xC0000000 | 0x00dc)
-#define NT_STATUS_INVALID_DOMAIN_STATE (0xC0000000 | 0x00dd)
-#define NT_STATUS_INVALID_DOMAIN_ROLE (0xC0000000 | 0x00de)
-#define NT_STATUS_NO_SUCH_DOMAIN (0xC0000000 | 0x00df)
-#define NT_STATUS_DOMAIN_EXISTS (0xC0000000 | 0x00e0)
-#define NT_STATUS_DOMAIN_LIMIT_EXCEEDED (0xC0000000 | 0x00e1)
-#define NT_STATUS_OPLOCK_NOT_GRANTED (0xC0000000 | 0x00e2)
-#define NT_STATUS_INVALID_OPLOCK_PROTOCOL (0xC0000000 | 0x00e3)
-#define NT_STATUS_INTERNAL_DB_CORRUPTION (0xC0000000 | 0x00e4)
-#define NT_STATUS_INTERNAL_ERROR (0xC0000000 | 0x00e5)
-#define NT_STATUS_GENERIC_NOT_MAPPED (0xC0000000 | 0x00e6)
-#define NT_STATUS_BAD_DESCRIPTOR_FORMAT (0xC0000000 | 0x00e7)
-#define NT_STATUS_INVALID_USER_BUFFER (0xC0000000 | 0x00e8)
-#define NT_STATUS_UNEXPECTED_IO_ERROR (0xC0000000 | 0x00e9)
-#define NT_STATUS_UNEXPECTED_MM_CREATE_ERR (0xC0000000 | 0x00ea)
-#define NT_STATUS_UNEXPECTED_MM_MAP_ERROR (0xC0000000 | 0x00eb)
-#define NT_STATUS_UNEXPECTED_MM_EXTEND_ERR (0xC0000000 | 0x00ec)
-#define NT_STATUS_NOT_LOGON_PROCESS (0xC0000000 | 0x00ed)
-#define NT_STATUS_LOGON_SESSION_EXISTS (0xC0000000 | 0x00ee)
-#define NT_STATUS_INVALID_PARAMETER_1 (0xC0000000 | 0x00ef)
-#define NT_STATUS_INVALID_PARAMETER_2 (0xC0000000 | 0x00f0)
-#define NT_STATUS_INVALID_PARAMETER_3 (0xC0000000 | 0x00f1)
-#define NT_STATUS_INVALID_PARAMETER_4 (0xC0000000 | 0x00f2)
-#define NT_STATUS_INVALID_PARAMETER_5 (0xC0000000 | 0x00f3)
-#define NT_STATUS_INVALID_PARAMETER_6 (0xC0000000 | 0x00f4)
-#define NT_STATUS_INVALID_PARAMETER_7 (0xC0000000 | 0x00f5)
-#define NT_STATUS_INVALID_PARAMETER_8 (0xC0000000 | 0x00f6)
-#define NT_STATUS_INVALID_PARAMETER_9 (0xC0000000 | 0x00f7)
-#define NT_STATUS_INVALID_PARAMETER_10 (0xC0000000 | 0x00f8)
-#define NT_STATUS_INVALID_PARAMETER_11 (0xC0000000 | 0x00f9)
-#define NT_STATUS_INVALID_PARAMETER_12 (0xC0000000 | 0x00fa)
-#define NT_STATUS_REDIRECTOR_NOT_STARTED (0xC0000000 | 0x00fb)
-#define NT_STATUS_REDIRECTOR_STARTED (0xC0000000 | 0x00fc)
-#define NT_STATUS_STACK_OVERFLOW (0xC0000000 | 0x00fd)
-#define NT_STATUS_NO_SUCH_PACKAGE (0xC0000000 | 0x00fe)
-#define NT_STATUS_BAD_FUNCTION_TABLE (0xC0000000 | 0x00ff)
-#define NT_STATUS_DIRECTORY_NOT_EMPTY (0xC0000000 | 0x0101)
-#define NT_STATUS_FILE_CORRUPT_ERROR (0xC0000000 | 0x0102)
-#define NT_STATUS_NOT_A_DIRECTORY (0xC0000000 | 0x0103)
-#define NT_STATUS_BAD_LOGON_SESSION_STATE (0xC0000000 | 0x0104)
-#define NT_STATUS_LOGON_SESSION_COLLISION (0xC0000000 | 0x0105)
-#define NT_STATUS_NAME_TOO_LONG (0xC0000000 | 0x0106)
-#define NT_STATUS_FILES_OPEN (0xC0000000 | 0x0107)
-#define NT_STATUS_CONNECTION_IN_USE (0xC0000000 | 0x0108)
-#define NT_STATUS_MESSAGE_NOT_FOUND (0xC0000000 | 0x0109)
-#define NT_STATUS_PROCESS_IS_TERMINATING (0xC0000000 | 0x010a)
-#define NT_STATUS_INVALID_LOGON_TYPE (0xC0000000 | 0x010b)
-#define NT_STATUS_NO_GUID_TRANSLATION (0xC0000000 | 0x010c)
-#define NT_STATUS_CANNOT_IMPERSONATE (0xC0000000 | 0x010d)
-#define NT_STATUS_IMAGE_ALREADY_LOADED (0xC0000000 | 0x010e)
-#define NT_STATUS_ABIOS_NOT_PRESENT (0xC0000000 | 0x010f)
-#define NT_STATUS_ABIOS_LID_NOT_EXIST (0xC0000000 | 0x0110)
-#define NT_STATUS_ABIOS_LID_ALREADY_OWNED (0xC0000000 | 0x0111)
-#define NT_STATUS_ABIOS_NOT_LID_OWNER (0xC0000000 | 0x0112)
-#define NT_STATUS_ABIOS_INVALID_COMMAND (0xC0000000 | 0x0113)
-#define NT_STATUS_ABIOS_INVALID_LID (0xC0000000 | 0x0114)
-#define NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE (0xC0000000 | 0x0115)
-#define NT_STATUS_ABIOS_INVALID_SELECTOR (0xC0000000 | 0x0116)
-#define NT_STATUS_NO_LDT (0xC0000000 | 0x0117)
-#define NT_STATUS_INVALID_LDT_SIZE (0xC0000000 | 0x0118)
-#define NT_STATUS_INVALID_LDT_OFFSET (0xC0000000 | 0x0119)
-#define NT_STATUS_INVALID_LDT_DESCRIPTOR (0xC0000000 | 0x011a)
-#define NT_STATUS_INVALID_IMAGE_NE_FORMAT (0xC0000000 | 0x011b)
-#define NT_STATUS_RXACT_INVALID_STATE (0xC0000000 | 0x011c)
-#define NT_STATUS_RXACT_COMMIT_FAILURE (0xC0000000 | 0x011d)
-#define NT_STATUS_MAPPED_FILE_SIZE_ZERO (0xC0000000 | 0x011e)
-#define NT_STATUS_TOO_MANY_OPENED_FILES (0xC0000000 | 0x011f)
-#define NT_STATUS_CANCELLED (0xC0000000 | 0x0120)
-#define NT_STATUS_CANNOT_DELETE (0xC0000000 | 0x0121)
-#define NT_STATUS_INVALID_COMPUTER_NAME (0xC0000000 | 0x0122)
-#define NT_STATUS_FILE_DELETED (0xC0000000 | 0x0123)
-#define NT_STATUS_SPECIAL_ACCOUNT (0xC0000000 | 0x0124)
-#define NT_STATUS_SPECIAL_GROUP (0xC0000000 | 0x0125)
-#define NT_STATUS_SPECIAL_USER (0xC0000000 | 0x0126)
-#define NT_STATUS_MEMBERS_PRIMARY_GROUP (0xC0000000 | 0x0127)
-#define NT_STATUS_FILE_CLOSED (0xC0000000 | 0x0128)
-#define NT_STATUS_TOO_MANY_THREADS (0xC0000000 | 0x0129)
-#define NT_STATUS_THREAD_NOT_IN_PROCESS (0xC0000000 | 0x012a)
-#define NT_STATUS_TOKEN_ALREADY_IN_USE (0xC0000000 | 0x012b)
-#define NT_STATUS_PAGEFILE_QUOTA_EXCEEDED (0xC0000000 | 0x012c)
-#define NT_STATUS_COMMITMENT_LIMIT (0xC0000000 | 0x012d)
-#define NT_STATUS_INVALID_IMAGE_LE_FORMAT (0xC0000000 | 0x012e)
-#define NT_STATUS_INVALID_IMAGE_NOT_MZ (0xC0000000 | 0x012f)
-#define NT_STATUS_INVALID_IMAGE_PROTECT (0xC0000000 | 0x0130)
-#define NT_STATUS_INVALID_IMAGE_WIN_16 (0xC0000000 | 0x0131)
-#define NT_STATUS_LOGON_SERVER_CONFLICT (0xC0000000 | 0x0132)
-#define NT_STATUS_TIME_DIFFERENCE_AT_DC (0xC0000000 | 0x0133)
-#define NT_STATUS_SYNCHRONIZATION_REQUIRED (0xC0000000 | 0x0134)
-#define NT_STATUS_DLL_NOT_FOUND (0xC0000000 | 0x0135)
-#define NT_STATUS_OPEN_FAILED (0xC0000000 | 0x0136)
-#define NT_STATUS_IO_PRIVILEGE_FAILED (0xC0000000 | 0x0137)
-#define NT_STATUS_ORDINAL_NOT_FOUND (0xC0000000 | 0x0138)
-#define NT_STATUS_ENTRYPOINT_NOT_FOUND (0xC0000000 | 0x0139)
-#define NT_STATUS_CONTROL_C_EXIT (0xC0000000 | 0x013a)
-#define NT_STATUS_LOCAL_DISCONNECT (0xC0000000 | 0x013b)
-#define NT_STATUS_REMOTE_DISCONNECT (0xC0000000 | 0x013c)
-#define NT_STATUS_REMOTE_RESOURCES (0xC0000000 | 0x013d)
-#define NT_STATUS_LINK_FAILED (0xC0000000 | 0x013e)
-#define NT_STATUS_LINK_TIMEOUT (0xC0000000 | 0x013f)
-#define NT_STATUS_INVALID_CONNECTION (0xC0000000 | 0x0140)
-#define NT_STATUS_INVALID_ADDRESS (0xC0000000 | 0x0141)
-#define NT_STATUS_DLL_INIT_FAILED (0xC0000000 | 0x0142)
-#define NT_STATUS_MISSING_SYSTEMFILE (0xC0000000 | 0x0143)
-#define NT_STATUS_UNHANDLED_EXCEPTION (0xC0000000 | 0x0144)
-#define NT_STATUS_APP_INIT_FAILURE (0xC0000000 | 0x0145)
-#define NT_STATUS_PAGEFILE_CREATE_FAILED (0xC0000000 | 0x0146)
-#define NT_STATUS_NO_PAGEFILE (0xC0000000 | 0x0147)
-#define NT_STATUS_INVALID_LEVEL (0xC0000000 | 0x0148)
-#define NT_STATUS_WRONG_PASSWORD_CORE (0xC0000000 | 0x0149)
-#define NT_STATUS_ILLEGAL_FLOAT_CONTEXT (0xC0000000 | 0x014a)
-#define NT_STATUS_PIPE_BROKEN (0xC0000000 | 0x014b)
-#define NT_STATUS_REGISTRY_CORRUPT (0xC0000000 | 0x014c)
-#define NT_STATUS_REGISTRY_IO_FAILED (0xC0000000 | 0x014d)
-#define NT_STATUS_NO_EVENT_PAIR (0xC0000000 | 0x014e)
-#define NT_STATUS_UNRECOGNIZED_VOLUME (0xC0000000 | 0x014f)
-#define NT_STATUS_SERIAL_NO_DEVICE_INITED (0xC0000000 | 0x0150)
-#define NT_STATUS_NO_SUCH_ALIAS (0xC0000000 | 0x0151)
-#define NT_STATUS_MEMBER_NOT_IN_ALIAS (0xC0000000 | 0x0152)
-#define NT_STATUS_MEMBER_IN_ALIAS (0xC0000000 | 0x0153)
-#define NT_STATUS_ALIAS_EXISTS (0xC0000000 | 0x0154)
-#define NT_STATUS_LOGON_NOT_GRANTED (0xC0000000 | 0x0155)
-#define NT_STATUS_TOO_MANY_SECRETS (0xC0000000 | 0x0156)
-#define NT_STATUS_SECRET_TOO_LONG (0xC0000000 | 0x0157)
-#define NT_STATUS_INTERNAL_DB_ERROR (0xC0000000 | 0x0158)
-#define NT_STATUS_FULLSCREEN_MODE (0xC0000000 | 0x0159)
-#define NT_STATUS_TOO_MANY_CONTEXT_IDS (0xC0000000 | 0x015a)
-#define NT_STATUS_LOGON_TYPE_NOT_GRANTED (0xC0000000 | 0x015b)
-#define NT_STATUS_NOT_REGISTRY_FILE (0xC0000000 | 0x015c)
-#define NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED (0xC0000000 | 0x015d)
-#define NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR (0xC0000000 | 0x015e)
-#define NT_STATUS_FT_MISSING_MEMBER (0xC0000000 | 0x015f)
-#define NT_STATUS_ILL_FORMED_SERVICE_ENTRY (0xC0000000 | 0x0160)
-#define NT_STATUS_ILLEGAL_CHARACTER (0xC0000000 | 0x0161)
-#define NT_STATUS_UNMAPPABLE_CHARACTER (0xC0000000 | 0x0162)
-#define NT_STATUS_UNDEFINED_CHARACTER (0xC0000000 | 0x0163)
-#define NT_STATUS_FLOPPY_VOLUME (0xC0000000 | 0x0164)
-#define NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND (0xC0000000 | 0x0165)
-#define NT_STATUS_FLOPPY_WRONG_CYLINDER (0xC0000000 | 0x0166)
-#define NT_STATUS_FLOPPY_UNKNOWN_ERROR (0xC0000000 | 0x0167)
-#define NT_STATUS_FLOPPY_BAD_REGISTERS (0xC0000000 | 0x0168)
-#define NT_STATUS_DISK_RECALIBRATE_FAILED (0xC0000000 | 0x0169)
-#define NT_STATUS_DISK_OPERATION_FAILED (0xC0000000 | 0x016a)
-#define NT_STATUS_DISK_RESET_FAILED (0xC0000000 | 0x016b)
-#define NT_STATUS_SHARED_IRQ_BUSY (0xC0000000 | 0x016c)
-#define NT_STATUS_FT_ORPHANING (0xC0000000 | 0x016d)
-#define NT_STATUS_PARTITION_FAILURE (0xC0000000 | 0x0172)
-#define NT_STATUS_INVALID_BLOCK_LENGTH (0xC0000000 | 0x0173)
-#define NT_STATUS_DEVICE_NOT_PARTITIONED (0xC0000000 | 0x0174)
-#define NT_STATUS_UNABLE_TO_LOCK_MEDIA (0xC0000000 | 0x0175)
-#define NT_STATUS_UNABLE_TO_UNLOAD_MEDIA (0xC0000000 | 0x0176)
-#define NT_STATUS_EOM_OVERFLOW (0xC0000000 | 0x0177)
-#define NT_STATUS_NO_MEDIA (0xC0000000 | 0x0178)
-#define NT_STATUS_NO_SUCH_MEMBER (0xC0000000 | 0x017a)
-#define NT_STATUS_INVALID_MEMBER (0xC0000000 | 0x017b)
-#define NT_STATUS_KEY_DELETED (0xC0000000 | 0x017c)
-#define NT_STATUS_NO_LOG_SPACE (0xC0000000 | 0x017d)
-#define NT_STATUS_TOO_MANY_SIDS (0xC0000000 | 0x017e)
-#define NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED (0xC0000000 | 0x017f)
-#define NT_STATUS_KEY_HAS_CHILDREN (0xC0000000 | 0x0180)
-#define NT_STATUS_CHILD_MUST_BE_VOLATILE (0xC0000000 | 0x0181)
-#define NT_STATUS_DEVICE_CONFIGURATION_ERROR (0xC0000000 | 0x0182)
-#define NT_STATUS_DRIVER_INTERNAL_ERROR (0xC0000000 | 0x0183)
-#define NT_STATUS_INVALID_DEVICE_STATE (0xC0000000 | 0x0184)
-#define NT_STATUS_IO_DEVICE_ERROR (0xC0000000 | 0x0185)
-#define NT_STATUS_DEVICE_PROTOCOL_ERROR (0xC0000000 | 0x0186)
-#define NT_STATUS_BACKUP_CONTROLLER (0xC0000000 | 0x0187)
-#define NT_STATUS_LOG_FILE_FULL (0xC0000000 | 0x0188)
-#define NT_STATUS_TOO_LATE (0xC0000000 | 0x0189)
-#define NT_STATUS_NO_TRUST_LSA_SECRET (0xC0000000 | 0x018a)
-#define NT_STATUS_NO_TRUST_SAM_ACCOUNT (0xC0000000 | 0x018b)
-#define NT_STATUS_TRUSTED_DOMAIN_FAILURE (0xC0000000 | 0x018c)
-#define NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE (0xC0000000 | 0x018d)
-#define NT_STATUS_EVENTLOG_FILE_CORRUPT (0xC0000000 | 0x018e)
-#define NT_STATUS_EVENTLOG_CANT_START (0xC0000000 | 0x018f)
-#define NT_STATUS_TRUST_FAILURE (0xC0000000 | 0x0190)
-#define NT_STATUS_MUTANT_LIMIT_EXCEEDED (0xC0000000 | 0x0191)
-#define NT_STATUS_NETLOGON_NOT_STARTED (0xC0000000 | 0x0192)
-#define NT_STATUS_ACCOUNT_EXPIRED (0xC0000000 | 0x0193)
-#define NT_STATUS_POSSIBLE_DEADLOCK (0xC0000000 | 0x0194)
-#define NT_STATUS_NETWORK_CREDENTIAL_CONFLICT (0xC0000000 | 0x0195)
-#define NT_STATUS_REMOTE_SESSION_LIMIT (0xC0000000 | 0x0196)
-#define NT_STATUS_EVENTLOG_FILE_CHANGED (0xC0000000 | 0x0197)
-#define NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT (0xC0000000 | 0x0198)
-#define NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT (0xC0000000 | 0x0199)
-#define NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT (0xC0000000 | 0x019a)
-#define NT_STATUS_DOMAIN_TRUST_INCONSISTENT (0xC0000000 | 0x019b)
-#define NT_STATUS_FS_DRIVER_REQUIRED (0xC0000000 | 0x019c)
-#define NT_STATUS_NO_USER_SESSION_KEY (0xC0000000 | 0x0202)
-#define NT_STATUS_USER_SESSION_DELETED (0xC0000000 | 0x0203)
-#define NT_STATUS_RESOURCE_LANG_NOT_FOUND (0xC0000000 | 0x0204)
-#define NT_STATUS_INSUFF_SERVER_RESOURCES (0xC0000000 | 0x0205)
-#define NT_STATUS_INVALID_BUFFER_SIZE (0xC0000000 | 0x0206)
-#define NT_STATUS_INVALID_ADDRESS_COMPONENT (0xC0000000 | 0x0207)
-#define NT_STATUS_INVALID_ADDRESS_WILDCARD (0xC0000000 | 0x0208)
-#define NT_STATUS_TOO_MANY_ADDRESSES (0xC0000000 | 0x0209)
-#define NT_STATUS_ADDRESS_ALREADY_EXISTS (0xC0000000 | 0x020a)
-#define NT_STATUS_ADDRESS_CLOSED (0xC0000000 | 0x020b)
-#define NT_STATUS_CONNECTION_DISCONNECTED (0xC0000000 | 0x020c)
-#define NT_STATUS_CONNECTION_RESET (0xC0000000 | 0x020d)
-#define NT_STATUS_TOO_MANY_NODES (0xC0000000 | 0x020e)
-#define NT_STATUS_TRANSACTION_ABORTED (0xC0000000 | 0x020f)
-#define NT_STATUS_TRANSACTION_TIMED_OUT (0xC0000000 | 0x0210)
-#define NT_STATUS_TRANSACTION_NO_RELEASE (0xC0000000 | 0x0211)
-#define NT_STATUS_TRANSACTION_NO_MATCH (0xC0000000 | 0x0212)
-#define NT_STATUS_TRANSACTION_RESPONDED (0xC0000000 | 0x0213)
-#define NT_STATUS_TRANSACTION_INVALID_ID (0xC0000000 | 0x0214)
-#define NT_STATUS_TRANSACTION_INVALID_TYPE (0xC0000000 | 0x0215)
-#define NT_STATUS_NOT_SERVER_SESSION (0xC0000000 | 0x0216)
-#define NT_STATUS_NOT_CLIENT_SESSION (0xC0000000 | 0x0217)
-#define NT_STATUS_CANNOT_LOAD_REGISTRY_FILE (0xC0000000 | 0x0218)
-#define NT_STATUS_DEBUG_ATTACH_FAILED (0xC0000000 | 0x0219)
-#define NT_STATUS_SYSTEM_PROCESS_TERMINATED (0xC0000000 | 0x021a)
-#define NT_STATUS_DATA_NOT_ACCEPTED (0xC0000000 | 0x021b)
-#define NT_STATUS_NO_BROWSER_SERVERS_FOUND (0xC0000000 | 0x021c)
-#define NT_STATUS_VDM_HARD_ERROR (0xC0000000 | 0x021d)
-#define NT_STATUS_DRIVER_CANCEL_TIMEOUT (0xC0000000 | 0x021e)
-#define NT_STATUS_REPLY_MESSAGE_MISMATCH (0xC0000000 | 0x021f)
-#define NT_STATUS_MAPPED_ALIGNMENT (0xC0000000 | 0x0220)
-#define NT_STATUS_IMAGE_CHECKSUM_MISMATCH (0xC0000000 | 0x0221)
-#define NT_STATUS_LOST_WRITEBEHIND_DATA (0xC0000000 | 0x0222)
-#define NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID (0xC0000000 | 0x0223)
-#define NT_STATUS_PASSWORD_MUST_CHANGE (0xC0000000 | 0x0224)
-#define NT_STATUS_NOT_FOUND (0xC0000000 | 0x0225)
-#define NT_STATUS_NOT_TINY_STREAM (0xC0000000 | 0x0226)
-#define NT_STATUS_RECOVERY_FAILURE (0xC0000000 | 0x0227)
-#define NT_STATUS_STACK_OVERFLOW_READ (0xC0000000 | 0x0228)
-#define NT_STATUS_FAIL_CHECK (0xC0000000 | 0x0229)
-#define NT_STATUS_DUPLICATE_OBJECTID (0xC0000000 | 0x022a)
-#define NT_STATUS_OBJECTID_EXISTS (0xC0000000 | 0x022b)
-#define NT_STATUS_CONVERT_TO_LARGE (0xC0000000 | 0x022c)
-#define NT_STATUS_RETRY (0xC0000000 | 0x022d)
-#define NT_STATUS_FOUND_OUT_OF_SCOPE (0xC0000000 | 0x022e)
-#define NT_STATUS_ALLOCATE_BUCKET (0xC0000000 | 0x022f)
-#define NT_STATUS_PROPSET_NOT_FOUND (0xC0000000 | 0x0230)
-#define NT_STATUS_MARSHALL_OVERFLOW (0xC0000000 | 0x0231)
-#define NT_STATUS_INVALID_VARIANT (0xC0000000 | 0x0232)
-#define NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND (0xC0000000 | 0x0233)
-#define NT_STATUS_ACCOUNT_LOCKED_OUT (0xC0000000 | 0x0234)
-#define NT_STATUS_HANDLE_NOT_CLOSABLE (0xC0000000 | 0x0235)
-#define NT_STATUS_CONNECTION_REFUSED (0xC0000000 | 0x0236)
-#define NT_STATUS_GRACEFUL_DISCONNECT (0xC0000000 | 0x0237)
-#define NT_STATUS_ADDRESS_ALREADY_ASSOCIATED (0xC0000000 | 0x0238)
-#define NT_STATUS_ADDRESS_NOT_ASSOCIATED (0xC0000000 | 0x0239)
-#define NT_STATUS_CONNECTION_INVALID (0xC0000000 | 0x023a)
-#define NT_STATUS_CONNECTION_ACTIVE (0xC0000000 | 0x023b)
-#define NT_STATUS_NETWORK_UNREACHABLE (0xC0000000 | 0x023c)
-#define NT_STATUS_HOST_UNREACHABLE (0xC0000000 | 0x023d)
-#define NT_STATUS_PROTOCOL_UNREACHABLE (0xC0000000 | 0x023e)
-#define NT_STATUS_PORT_UNREACHABLE (0xC0000000 | 0x023f)
-#define NT_STATUS_REQUEST_ABORTED (0xC0000000 | 0x0240)
-#define NT_STATUS_CONNECTION_ABORTED (0xC0000000 | 0x0241)
-#define NT_STATUS_BAD_COMPRESSION_BUFFER (0xC0000000 | 0x0242)
-#define NT_STATUS_USER_MAPPED_FILE (0xC0000000 | 0x0243)
-#define NT_STATUS_AUDIT_FAILED (0xC0000000 | 0x0244)
-#define NT_STATUS_TIMER_RESOLUTION_NOT_SET (0xC0000000 | 0x0245)
-#define NT_STATUS_CONNECTION_COUNT_LIMIT (0xC0000000 | 0x0246)
-#define NT_STATUS_LOGIN_TIME_RESTRICTION (0xC0000000 | 0x0247)
-#define NT_STATUS_LOGIN_WKSTA_RESTRICTION (0xC0000000 | 0x0248)
-#define NT_STATUS_IMAGE_MP_UP_MISMATCH (0xC0000000 | 0x0249)
-#define NT_STATUS_INSUFFICIENT_LOGON_INFO (0xC0000000 | 0x0250)
-#define NT_STATUS_BAD_DLL_ENTRYPOINT (0xC0000000 | 0x0251)
-#define NT_STATUS_BAD_SERVICE_ENTRYPOINT (0xC0000000 | 0x0252)
-#define NT_STATUS_LPC_REPLY_LOST (0xC0000000 | 0x0253)
-#define NT_STATUS_IP_ADDRESS_CONFLICT1 (0xC0000000 | 0x0254)
-#define NT_STATUS_IP_ADDRESS_CONFLICT2 (0xC0000000 | 0x0255)
-#define NT_STATUS_REGISTRY_QUOTA_LIMIT (0xC0000000 | 0x0256)
-#define NT_STATUS_PATH_NOT_COVERED (0xC0000000 | 0x0257)
-#define NT_STATUS_NO_CALLBACK_ACTIVE (0xC0000000 | 0x0258)
-#define NT_STATUS_LICENSE_QUOTA_EXCEEDED (0xC0000000 | 0x0259)
-#define NT_STATUS_PWD_TOO_SHORT (0xC0000000 | 0x025a)
-#define NT_STATUS_PWD_TOO_RECENT (0xC0000000 | 0x025b)
-#define NT_STATUS_PWD_HISTORY_CONFLICT (0xC0000000 | 0x025c)
-#define NT_STATUS_PLUGPLAY_NO_DEVICE (0xC0000000 | 0x025e)
-#define NT_STATUS_UNSUPPORTED_COMPRESSION (0xC0000000 | 0x025f)
-#define NT_STATUS_INVALID_HW_PROFILE (0xC0000000 | 0x0260)
-#define NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH (0xC0000000 | 0x0261)
-#define NT_STATUS_DRIVER_ORDINAL_NOT_FOUND (0xC0000000 | 0x0262)
-#define NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND (0xC0000000 | 0x0263)
-#define NT_STATUS_RESOURCE_NOT_OWNED (0xC0000000 | 0x0264)
-#define NT_STATUS_TOO_MANY_LINKS (0xC0000000 | 0x0265)
-#define NT_STATUS_QUOTA_LIST_INCONSISTENT (0xC0000000 | 0x0266)
-#define NT_STATUS_FILE_IS_OFFLINE (0xC0000000 | 0x0267)
-#define NT_STATUS_NETWORK_SESSION_EXPIRED (0xC0000000 | 0x035c)
-#define NT_STATUS_NO_SUCH_JOB (0xC0000000 | 0xEDE) /* scheduler */
-#define NT_STATUS_NO_PREAUTH_INTEGRITY_HASH_OVERLAP (0xC0000000 | 0x5D0000)
-#define NT_STATUS_PENDING 0x00000103
-#endif /* _NTERR_H */
diff --git a/fs/smb/server/smb2misc.c b/fs/smb/server/smb2misc.c
index 67a2d7a793f6..a1ddca21c47b 100644
--- a/fs/smb/server/smb2misc.c
+++ b/fs/smb/server/smb2misc.c
@@ -5,7 +5,6 @@
*/
#include "glob.h"
-#include "nterr.h"
#include "smb_common.h"
#include "../common/smb2status.h"
#include "mgmt/user_session.h"
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index f3184b217575..27f87a13f20a 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -5497,6 +5497,13 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
info->Attributes |= cpu_to_le32(FILE_NAMED_STREAMS);
info->MaxPathNameComponentLength = cpu_to_le32(stfs.f_namelen);
+ /*
+ * some application(potableapp) can not run on ksmbd share
+ * because only NTFS handle security setting on windows.
+ * So Although local fs(EXT4 or F2fs, etc) is not NTFS,
+ * ksmbd should show share as NTFS. Later, If needed, we can add
+ * fs type(s) parameter to change fs type user wanted.
+ */
len = smbConvertToUTF16((__le16 *)info->FileSystemName,
"NTFS", PATH_MAX, conn->local_nls, 0);
len = len * 2;
diff --git a/fs/smb/server/smb_common.h b/fs/smb/server/smb_common.h
index 2baf4aa330eb..067b45048c73 100644
--- a/fs/smb/server/smb_common.h
+++ b/fs/smb/server/smb_common.h
@@ -3,13 +3,12 @@
* Copyright (C) 2018 Samsung Electronics Co., Ltd.
*/
-#ifndef __SMB_COMMON_H__
-#define __SMB_COMMON_H__
+#ifndef __SMB_SERVER_COMMON_H__
+#define __SMB_SERVER_COMMON_H__
#include <linux/kernel.h>
#include "glob.h"
-#include "nterr.h"
#include "../common/smbglob.h"
#include "../common/smb2pdu.h"
#include "../common/fscc.h"
@@ -203,4 +202,4 @@ unsigned int ksmbd_server_side_copy_max_chunk_size(void);
unsigned int ksmbd_server_side_copy_max_total_size(void);
bool is_asterisk(char *p);
__le32 smb_map_generic_desired_access(__le32 daccess);
-#endif /* __SMB_COMMON_H__ */
+#endif /* __SMB_SERVER_COMMON_H__ */
diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index 2ceda49c609f..aa36a0d1d9df 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -90,7 +90,7 @@
*/
#define DMA_MAPPING_ERROR (~(dma_addr_t)0)
-#define DMA_BIT_MASK(n) GENMASK_ULL(n - 1, 0)
+#define DMA_BIT_MASK(n) GENMASK_ULL((n) - 1, 0)
struct dma_iova_state {
dma_addr_t addr;
diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h
index 2fd850f4678b..58d01ed4cce7 100644
--- a/include/linux/i3c/master.h
+++ b/include/linux/i3c/master.h
@@ -417,12 +417,8 @@ struct i3c_bus {
* all CCC commands are supported.
* @send_ccc_cmd: send a CCC command
* This method is mandatory.
- * @priv_xfers: do one or several private I3C SDR transfers
- * This method is mandatory when i3c_xfers is not implemented. It
- * is deprecated.
- * @i3c_xfers: do one or several I3C SDR or HDR transfers
- * This method is mandatory when priv_xfers is not implemented but
- * should be implemented instead of priv_xfers.
+ * @i3c_xfers: do one or several I3C SDR or HDR transfers.
+ * This method is mandatory.
* @attach_i2c_dev: called every time an I2C device is attached to the bus.
* This is a good place to attach master controller specific
* data to I2C devices.
@@ -478,10 +474,6 @@ struct i3c_master_controller_ops {
const struct i3c_ccc_cmd *cmd);
int (*send_ccc_cmd)(struct i3c_master_controller *master,
struct i3c_ccc_cmd *cmd);
- /* Deprecated, please use i3c_xfers() */
- int (*priv_xfers)(struct i3c_dev_desc *dev,
- struct i3c_priv_xfer *xfers,
- int nxfers);
int (*i3c_xfers)(struct i3c_dev_desc *dev,
struct i3c_xfer *xfers,
int nxfers, enum i3c_xfer_mode mode);
diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h
index 37e0b5b5600a..17902861de76 100644
--- a/include/linux/irqdesc.h
+++ b/include/linux/irqdesc.h
@@ -182,9 +182,9 @@ int generic_handle_irq_safe(unsigned int irq);
* and handle the result interrupt number. Return -EINVAL if
* conversion failed.
*/
-int generic_handle_domain_irq(struct irq_domain *domain, unsigned int hwirq);
-int generic_handle_domain_irq_safe(struct irq_domain *domain, unsigned int hwirq);
-int generic_handle_domain_nmi(struct irq_domain *domain, unsigned int hwirq);
+int generic_handle_domain_irq(struct irq_domain *domain, irq_hw_number_t hwirq);
+int generic_handle_domain_irq_safe(struct irq_domain *domain, irq_hw_number_t hwirq);
+int generic_handle_domain_nmi(struct irq_domain *domain, irq_hw_number_t hwirq);
#endif
/* Test to see if a driver has successfully requested an irq */
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index c585939b6cd6..a6624edb7226 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -344,6 +344,7 @@ struct nfs4_copy_state {
#define NFS_INO_LAYOUTCOMMITTING (10) /* layoutcommit inflight */
#define NFS_INO_LAYOUTSTATS (11) /* layoutstats inflight */
#define NFS_INO_ODIRECT (12) /* I/O setting is O_DIRECT */
+#define NFS_INO_REQ_DIR_DELEG (13) /* Request a directory delegation */
static inline struct nfs_inode *NFS_I(const struct inode *inode)
{
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index d30c0245031c..c58b870f31ee 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -172,6 +172,11 @@ struct nfs_server {
#define NFS_MOUNT_FORCE_RDIRPLUS 0x20000000
#define NFS_MOUNT_NETUNREACH_FATAL 0x40000000
+ unsigned int automount_inherit; /* Properties inherited by automount */
+#define NFS_AUTOMOUNT_INHERIT_BSIZE 0x0001
+#define NFS_AUTOMOUNT_INHERIT_RSIZE 0x0002
+#define NFS_AUTOMOUNT_INHERIT_WSIZE 0x0004
+
unsigned int caps; /* server capabilities */
__u64 fattr_valid; /* Valid attributes */
unsigned int rsize; /* read size */
@@ -305,6 +310,7 @@ struct nfs_server {
#define NFS_CAP_REBOOT_LAYOUTRETURN (1U << 8)
#define NFS_CAP_OFFLOAD_STATUS (1U << 9)
#define NFS_CAP_ZERO_RANGE (1U << 10)
+#define NFS_CAP_DIR_DELEG (1U << 11)
#define NFS_CAP_OPEN_XOR (1U << 12)
#define NFS_CAP_DELEGTIME (1U << 13)
#define NFS_CAP_POSIX_LOCK (1U << 14)
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 31463286402f..79fe2dfb470f 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1092,12 +1092,19 @@ struct nfs4_getattr_arg {
struct nfs4_sequence_args seq_args;
const struct nfs_fh * fh;
const u32 * bitmask;
+ bool get_dir_deleg;
+};
+
+struct nfs4_gdd_res {
+ u32 status;
+ nfs4_stateid deleg;
};
struct nfs4_getattr_res {
struct nfs4_sequence_res seq_res;
const struct nfs_server * server;
struct nfs_fattr * fattr;
+ struct nfs4_gdd_res * gdd_res;
};
struct nfs4_link_arg {
@@ -1801,7 +1808,8 @@ struct nfs_rpc_ops {
int (*unlink_done) (struct rpc_task *, struct inode *);
void (*rename_setup) (struct rpc_message *msg,
struct dentry *old_dentry,
- struct dentry *new_dentry);
+ struct dentry *new_dentry,
+ struct inode *same_parent);
void (*rename_rpc_prepare)(struct rpc_task *task, struct nfs_renamedata *);
int (*rename_done) (struct rpc_task *task, struct inode *old_dir, struct inode *new_dir);
int (*link) (struct inode *, struct inode *, const struct qstr *);
diff --git a/include/linux/of.h b/include/linux/of.h
index 01bb3affcd49..9bbdcf25a2b4 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -316,6 +316,9 @@ extern struct property *of_find_property(const struct device_node *np,
extern bool of_property_read_bool(const struct device_node *np, const char *propname);
extern int of_property_count_elems_of_size(const struct device_node *np,
const char *propname, int elem_size);
+extern int of_property_read_u8_index(const struct device_node *np,
+ const char *propname,
+ u32 index, u8 *out_value);
extern int of_property_read_u16_index(const struct device_node *np,
const char *propname,
u32 index, u16 *out_value);
@@ -648,6 +651,12 @@ static inline int of_property_count_elems_of_size(const struct device_node *np,
return -ENOSYS;
}
+static inline int of_property_read_u8_index(const struct device_node *np,
+ const char *propname, u32 index, u8 *out_value)
+{
+ return -ENOSYS;
+}
+
static inline int of_property_read_u16_index(const struct device_node *np,
const char *propname, u32 index, u16 *out_value)
{
diff --git a/include/linux/platform_data/x86/asus-wmi-leds-ids.h b/include/linux/platform_data/x86/asus-wmi-leds-ids.h
new file mode 100644
index 000000000000..034a039c4e37
--- /dev/null
+++ b/include/linux/platform_data/x86/asus-wmi-leds-ids.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __PLATFORM_DATA_X86_ASUS_WMI_LEDS_IDS_H
+#define __PLATFORM_DATA_X86_ASUS_WMI_LEDS_IDS_H
+
+#include <linux/dmi.h>
+#include <linux/types.h>
+
+/* To be used by both hid-asus and asus-wmi to determine which controls kbd_brightness */
+#if IS_REACHABLE(CONFIG_ASUS_WMI) || IS_REACHABLE(CONFIG_HID_ASUS)
+static const struct dmi_system_id asus_use_hid_led_dmi_ids[] = {
+ {
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_FAMILY, "ROG Zephyrus"),
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_FAMILY, "ROG Strix"),
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_FAMILY, "ROG Flow"),
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_FAMILY, "ProArt P16"),
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "GA403U"),
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "GU605M"),
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "RC71L"),
+ },
+ },
+ { },
+};
+#endif
+
+#endif /* __PLATFORM_DATA_X86_ASUS_WMI_LEDS_IDS_H */
diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
index 8a515179113d..419491d4abca 100644
--- a/include/linux/platform_data/x86/asus-wmi.h
+++ b/include/linux/platform_data/x86/asus-wmi.h
@@ -4,7 +4,9 @@
#include <linux/errno.h>
#include <linux/types.h>
-#include <linux/dmi.h>
+
+#define ASUS_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66"
+#define ASUS_ACPI_UID_ASUSWMI "ASUSWMI"
/* WMI Methods */
#define ASUS_WMI_METHODID_SPEC 0x43455053 /* BIOS SPECification */
@@ -73,12 +75,14 @@
#define ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO 0x00110019
/* Misc */
+#define ASUS_WMI_DEVID_PANEL_HD 0x0005001C
#define ASUS_WMI_DEVID_PANEL_OD 0x00050019
#define ASUS_WMI_DEVID_CAMERA 0x00060013
#define ASUS_WMI_DEVID_LID_FLIP 0x00060062
#define ASUS_WMI_DEVID_LID_FLIP_ROG 0x00060077
#define ASUS_WMI_DEVID_MINI_LED_MODE 0x0005001E
#define ASUS_WMI_DEVID_MINI_LED_MODE2 0x0005002E
+#define ASUS_WMI_DEVID_SCREEN_AUTO_BRIGHTNESS 0x0005002A
/* Storage */
#define ASUS_WMI_DEVID_CARDREADER 0x00080013
@@ -103,7 +107,7 @@
#define ASUS_WMI_DEVID_PPT_PL1_SPL 0x001200A3
#define ASUS_WMI_DEVID_PPT_APU_SPPT 0x001200B0
#define ASUS_WMI_DEVID_PPT_PLAT_SPPT 0x001200B1
-#define ASUS_WMI_DEVID_PPT_FPPT 0x001200C1
+#define ASUS_WMI_DEVID_PPT_PL3_FPPT 0x001200C1
#define ASUS_WMI_DEVID_NV_DYN_BOOST 0x001200C0
#define ASUS_WMI_DEVID_NV_THERM_TARGET 0x001200C2
@@ -133,6 +137,11 @@
/* dgpu on/off */
#define ASUS_WMI_DEVID_DGPU 0x00090020
+#define ASUS_WMI_DEVID_APU_MEM 0x000600C1
+
+#define ASUS_WMI_DEVID_DGPU_BASE_TGP 0x00120099
+#define ASUS_WMI_DEVID_DGPU_SET_TGP 0x00120098
+
/* gpu mux switch, 0 = dGPU, 1 = Optimus */
#define ASUS_WMI_DEVID_GPU_MUX 0x00090016
#define ASUS_WMI_DEVID_GPU_MUX_VIVO 0x00090026
@@ -166,6 +175,7 @@ enum asus_ally_mcu_hack {
#if IS_REACHABLE(CONFIG_ASUS_WMI)
void set_ally_mcu_hack(enum asus_ally_mcu_hack status);
void set_ally_mcu_powersave(bool enabled);
+int asus_wmi_get_devstate_dsts(u32 dev_id, u32 *retval);
int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, u32 *retval);
int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, u32 *retval);
#else
@@ -179,6 +189,10 @@ static inline int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, u32 *retval)
{
return -ENODEV;
}
+static inline int asus_wmi_get_devstate_dsts(u32 dev_id, u32 *retval)
+{
+ return -ENODEV;
+}
static inline int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1,
u32 *retval)
{
@@ -186,44 +200,4 @@ static inline int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1,
}
#endif
-/* To be used by both hid-asus and asus-wmi to determine which controls kbd_brightness */
-static const struct dmi_system_id asus_use_hid_led_dmi_ids[] = {
- {
- .matches = {
- DMI_MATCH(DMI_PRODUCT_FAMILY, "ROG Zephyrus"),
- },
- },
- {
- .matches = {
- DMI_MATCH(DMI_PRODUCT_FAMILY, "ROG Strix"),
- },
- },
- {
- .matches = {
- DMI_MATCH(DMI_PRODUCT_FAMILY, "ROG Flow"),
- },
- },
- {
- .matches = {
- DMI_MATCH(DMI_PRODUCT_FAMILY, "ProArt P16"),
- },
- },
- {
- .matches = {
- DMI_MATCH(DMI_BOARD_NAME, "GA403U"),
- },
- },
- {
- .matches = {
- DMI_MATCH(DMI_BOARD_NAME, "GU605M"),
- },
- },
- {
- .matches = {
- DMI_MATCH(DMI_BOARD_NAME, "RC71L"),
- },
- },
- { },
-};
-
#endif /* __PLATFORM_DATA_X86_ASUS_WMI_H */
diff --git a/include/linux/platform_data/x86/intel_pmc_ipc.h b/include/linux/platform_data/x86/intel_pmc_ipc.h
index 1d34435b7001..85ea381e4a27 100644
--- a/include/linux/platform_data/x86/intel_pmc_ipc.h
+++ b/include/linux/platform_data/x86/intel_pmc_ipc.h
@@ -9,6 +9,7 @@
#ifndef INTEL_PMC_IPC_H
#define INTEL_PMC_IPC_H
#include <linux/acpi.h>
+#include <linux/cleanup.h>
#define IPC_SOC_REGISTER_ACCESS 0xAA
#define IPC_SOC_SUB_CMD_READ 0x00
@@ -48,7 +49,6 @@ static inline int intel_pmc_ipc(struct pmc_ipc_cmd *ipc_cmd, struct pmc_ipc_rbuf
{.type = ACPI_TYPE_INTEGER,},
};
struct acpi_object_list arg_list = { PMC_IPCS_PARAM_COUNT, params };
- union acpi_object *obj;
int status;
if (!ipc_cmd || !rbuf)
@@ -72,7 +72,7 @@ static inline int intel_pmc_ipc(struct pmc_ipc_cmd *ipc_cmd, struct pmc_ipc_rbuf
if (ACPI_FAILURE(status))
return -ENODEV;
- obj = buffer.pointer;
+ union acpi_object *obj __free(kfree) = buffer.pointer;
if (obj && obj->type == ACPI_TYPE_PACKAGE &&
obj->package.count == VALID_IPC_RESPONSE) {
diff --git a/include/linux/platform_profile.h b/include/linux/platform_profile.h
index a299225ab92e..855b28340e95 100644
--- a/include/linux/platform_profile.h
+++ b/include/linux/platform_profile.h
@@ -24,6 +24,7 @@ enum platform_profile_option {
PLATFORM_PROFILE_BALANCED,
PLATFORM_PROFILE_BALANCED_PERFORMANCE,
PLATFORM_PROFILE_PERFORMANCE,
+ PLATFORM_PROFILE_MAX_POWER,
PLATFORM_PROFILE_CUSTOM,
PLATFORM_PROFILE_LAST, /*must always be last */
};
diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h
index 911d7a4d32c1..41037c513f06 100644
--- a/include/linux/pm_runtime.h
+++ b/include/linux/pm_runtime.h
@@ -76,7 +76,7 @@ extern int pm_runtime_get_if_active(struct device *dev);
extern int pm_runtime_get_if_in_use(struct device *dev);
extern int pm_schedule_suspend(struct device *dev, unsigned int delay);
extern int __pm_runtime_set_status(struct device *dev, unsigned int status);
-extern int pm_runtime_barrier(struct device *dev);
+extern void pm_runtime_barrier(struct device *dev);
extern bool pm_runtime_block_if_disabled(struct device *dev);
extern void pm_runtime_unblock(struct device *dev);
extern void pm_runtime_enable(struct device *dev);
@@ -284,7 +284,7 @@ static inline int pm_runtime_get_if_active(struct device *dev)
}
static inline int __pm_runtime_set_status(struct device *dev,
unsigned int status) { return 0; }
-static inline int pm_runtime_barrier(struct device *dev) { return 0; }
+static inline void pm_runtime_barrier(struct device *dev) {}
static inline bool pm_runtime_block_if_disabled(struct device *dev) { return true; }
static inline void pm_runtime_unblock(struct device *dev) {}
static inline void pm_runtime_enable(struct device *dev) {}
diff --git a/include/linux/restart_block.h b/include/linux/restart_block.h
index 36ddfa1ec301..67d2bf579942 100644
--- a/include/linux/restart_block.h
+++ b/include/linux/restart_block.h
@@ -32,7 +32,7 @@ struct restart_block {
u32 val;
u32 flags;
u32 bitset;
- u64 time;
+ ktime_t time;
u32 __user *uaddr2;
} futex;
/* For nanosleep */
diff --git a/include/linux/rtc/ds1685.h b/include/linux/rtc/ds1685.h
index 01da4582db6d..8ec0ebfaef04 100644
--- a/include/linux/rtc/ds1685.h
+++ b/include/linux/rtc/ds1685.h
@@ -324,7 +324,6 @@ struct ds1685_rtc_platform_data {
#define RTC_SQW_2HZ 0x0f /* 0 1 1 1 1 */
#define RTC_SQW_0HZ 0x00 /* 0 0 0 0 0 */
#define RTC_SQW_32768HZ 32768 /* 1 - - - - */
-#define RTC_MAX_USER_FREQ 8192
/*
diff --git a/include/linux/slab.h b/include/linux/slab.h
index cf443f064a66..2482992248dc 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -1150,10 +1150,17 @@ static inline void kvfree_rcu_barrier(void)
rcu_barrier();
}
+static inline void kvfree_rcu_barrier_on_cache(struct kmem_cache *s)
+{
+ rcu_barrier();
+}
+
static inline void kfree_rcu_scheduler_running(void) { }
#else
void kvfree_rcu_barrier(void);
+void kvfree_rcu_barrier_on_cache(struct kmem_cache *s);
+
void kfree_rcu_scheduler_running(void);
#endif
diff --git a/include/linux/sunrpc/bc_xprt.h b/include/linux/sunrpc/bc_xprt.h
index f22bf915dcf6..98939cb664cf 100644
--- a/include/linux/sunrpc/bc_xprt.h
+++ b/include/linux/sunrpc/bc_xprt.h
@@ -25,12 +25,14 @@ void xprt_init_bc_request(struct rpc_rqst *req, struct rpc_task *task,
void xprt_free_bc_request(struct rpc_rqst *req);
int xprt_setup_backchannel(struct rpc_xprt *, unsigned int min_reqs);
void xprt_destroy_backchannel(struct rpc_xprt *, unsigned int max_reqs);
+void xprt_enqueue_bc_request(struct rpc_rqst *req);
/* Socket backchannel transport methods */
int xprt_setup_bc(struct rpc_xprt *xprt, unsigned int min_reqs);
void xprt_destroy_bc(struct rpc_xprt *xprt, unsigned int max_reqs);
void xprt_free_bc_rqst(struct rpc_rqst *req);
unsigned int xprt_bc_max_slots(struct rpc_xprt *xprt);
+void xprt_svc_destroy_nullify_bc(struct rpc_xprt *xprt, struct svc_serv **serv);
/*
* Determine if a shared backchannel is in use
@@ -68,5 +70,10 @@ static inline void set_bc_enabled(struct svc_serv *serv)
static inline void xprt_free_bc_request(struct rpc_rqst *req)
{
}
+
+static inline void xprt_svc_destroy_nullify_bc(struct rpc_xprt *xprt, struct svc_serv **serv)
+{
+ svc_destroy(serv);
+}
#endif /* CONFIG_SUNRPC_BACKCHANNEL */
#endif /* _LINUX_SUNRPC_BC_XPRT_H */
diff --git a/include/linux/wmi.h b/include/linux/wmi.h
index 10751c8e5e6a..665ea7dc8a92 100644
--- a/include/linux/wmi.h
+++ b/include/linux/wmi.h
@@ -36,13 +36,10 @@ struct wmi_device {
*/
#define to_wmi_device(device) container_of_const(device, struct wmi_device, dev)
-extern acpi_status wmidev_evaluate_method(struct wmi_device *wdev,
- u8 instance, u32 method_id,
- const struct acpi_buffer *in,
- struct acpi_buffer *out);
+acpi_status wmidev_evaluate_method(struct wmi_device *wdev, u8 instance, u32 method_id,
+ const struct acpi_buffer *in, struct acpi_buffer *out);
-extern union acpi_object *wmidev_block_query(struct wmi_device *wdev,
- u8 instance);
+union acpi_object *wmidev_block_query(struct wmi_device *wdev, u8 instance);
acpi_status wmidev_block_set(struct wmi_device *wdev, u8 instance, const struct acpi_buffer *in);
@@ -81,9 +78,9 @@ struct wmi_driver {
*/
#define to_wmi_driver(drv) container_of_const(drv, struct wmi_driver, driver)
-extern int __must_check __wmi_driver_register(struct wmi_driver *driver,
- struct module *owner);
-extern void wmi_driver_unregister(struct wmi_driver *driver);
+int __must_check __wmi_driver_register(struct wmi_driver *driver, struct module *owner);
+
+void wmi_driver_unregister(struct wmi_driver *driver);
/**
* wmi_driver_register() - Helper macro to register a WMI driver
diff --git a/include/sound/hda-sdw-bpt.h b/include/sound/hda-sdw-bpt.h
index f649549b75d5..9b654c31829a 100644
--- a/include/sound/hda-sdw-bpt.h
+++ b/include/sound/hda-sdw-bpt.h
@@ -30,6 +30,8 @@ int hda_sdw_bpt_wait(struct device *dev, struct hdac_ext_stream *bpt_tx_stream,
int hda_sdw_bpt_close(struct device *dev, struct hdac_ext_stream *bpt_tx_stream,
struct snd_dma_buffer *dmab_tx_bdl, struct hdac_ext_stream *bpt_rx_stream,
struct snd_dma_buffer *dmab_rx_bdl);
+
+unsigned int hda_sdw_bpt_get_buf_size_alignment(unsigned int dma_bandwidth);
#else
static inline int hda_sdw_bpt_open(struct device *dev, int link_id,
struct hdac_ext_stream **bpt_tx_stream,
@@ -64,6 +66,11 @@ static inline int hda_sdw_bpt_close(struct device *dev, struct hdac_ext_stream *
WARN_ONCE(1, "SoundWire BPT is disabled");
return -EOPNOTSUPP;
}
+
+static inline unsigned int hda_sdw_bpt_get_buf_size_alignment(unsigned int dma_bandwidth)
+{
+ return 0;
+}
#endif
#endif /* __HDA_SDW_BPT_H */
diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h
index 4e0c1d8af09f..f11bfc6b9f42 100644
--- a/include/sound/hdaudio.h
+++ b/include/sound/hdaudio.h
@@ -380,6 +380,9 @@ struct hdac_bus {
/* factor used to derive STRIPE control value */
unsigned int sdo_limit;
+
+ /* address offset between host and hadc */
+ dma_addr_t addr_offset;
};
int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev,
diff --git a/include/uapi/linux/i2c.h b/include/uapi/linux/i2c.h
index a2db2a56c8b0..2a226657d9f8 100644
--- a/include/uapi/linux/i2c.h
+++ b/include/uapi/linux/i2c.h
@@ -36,7 +36,7 @@
*
* Only if I2C_FUNC_NOSTART is set:
* %I2C_M_NOSTART: skip repeated start sequence
-
+ *
* Only if I2C_FUNC_PROTOCOL_MANGLING is set:
* %I2C_M_NO_RD_ACK: in a read message, master ACK/NACK bit is skipped
* %I2C_M_IGNORE_NAK: treat NACK from client as ACK
diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h
index 5a049eeaecce..d3ce75ba938a 100644
--- a/include/uapi/sound/asound.h
+++ b/include/uapi/sound/asound.h
@@ -60,7 +60,7 @@ struct snd_cea_861_aud_if {
unsigned char db2_sf_ss; /* sample frequency and size */
unsigned char db3; /* not used, all zeros */
unsigned char db4_ca; /* channel allocation code */
- unsigned char db5_dminh_lsv; /* downmix inhibit & level-shit values */
+ unsigned char db5_dminh_lsv; /* downmix inhibit & level-shift values */
};
/****************************************************************************
diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c
index 5d130c578435..6cb24cdf8e68 100644
--- a/io_uring/io_uring.c
+++ b/io_uring/io_uring.c
@@ -2536,6 +2536,9 @@ static enum hrtimer_restart io_cqring_min_timer_wakeup(struct hrtimer *timer)
goto out_wake;
}
+ /* any generated CQE posted past this time should wake us up */
+ iowq->cq_tail = iowq->cq_min_tail;
+
hrtimer_update_function(&iowq->t, io_cqring_timer_wakeup);
hrtimer_set_expires(timer, iowq->timeout);
return HRTIMER_RESTART;
diff --git a/kernel/dma/pool.c b/kernel/dma/pool.c
index ee45dee33d49..26392badc36b 100644
--- a/kernel/dma/pool.c
+++ b/kernel/dma/pool.c
@@ -93,7 +93,7 @@ static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size,
page = dma_alloc_from_contiguous(NULL, 1 << order,
order, false);
if (!page)
- page = alloc_pages(gfp, order);
+ page = alloc_pages(gfp | __GFP_NOWARN, order);
} while (!page && order-- > 0);
if (!page)
goto out;
diff --git a/kernel/futex/waitwake.c b/kernel/futex/waitwake.c
index e2bbe5509ec2..1c2dd03f11ec 100644
--- a/kernel/futex/waitwake.c
+++ b/kernel/futex/waitwake.c
@@ -738,12 +738,11 @@ int futex_wait(u32 __user *uaddr, unsigned int flags, u32 val, ktime_t *abs_time
static long futex_wait_restart(struct restart_block *restart)
{
u32 __user *uaddr = restart->futex.uaddr;
- ktime_t t, *tp = NULL;
+ ktime_t *tp = NULL;
+
+ if (restart->futex.flags & FLAGS_HAS_TIMEOUT)
+ tp = &restart->futex.time;
- if (restart->futex.flags & FLAGS_HAS_TIMEOUT) {
- t = restart->futex.time;
- tp = &t;
- }
restart->fn = do_no_restart_syscall;
return (long)futex_wait(uaddr, restart->futex.flags,
diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c
index 6acf268f005b..f8e4e13dbe33 100644
--- a/kernel/irq/irqdesc.c
+++ b/kernel/irq/irqdesc.c
@@ -720,7 +720,7 @@ EXPORT_SYMBOL_GPL(generic_handle_irq_safe);
* This function must be called from an IRQ context with irq regs
* initialized.
*/
-int generic_handle_domain_irq(struct irq_domain *domain, unsigned int hwirq)
+int generic_handle_domain_irq(struct irq_domain *domain, irq_hw_number_t hwirq)
{
return handle_irq_desc(irq_resolve_mapping(domain, hwirq));
}
@@ -738,7 +738,7 @@ EXPORT_SYMBOL_GPL(generic_handle_domain_irq);
* context). If the interrupt is marked as 'enforce IRQ-context only' then
* the function must be invoked from hard interrupt context.
*/
-int generic_handle_domain_irq_safe(struct irq_domain *domain, unsigned int hwirq)
+int generic_handle_domain_irq_safe(struct irq_domain *domain, irq_hw_number_t hwirq)
{
unsigned long flags;
int ret;
@@ -761,7 +761,7 @@ EXPORT_SYMBOL_GPL(generic_handle_domain_irq_safe);
* This function must be called from an NMI context with irq regs
* initialized.
**/
-int generic_handle_domain_nmi(struct irq_domain *domain, unsigned int hwirq)
+int generic_handle_domain_nmi(struct irq_domain *domain, irq_hw_number_t hwirq)
{
WARN_ON_ONCE(!in_nmi());
return handle_irq_desc(irq_resolve_mapping(domain, hwirq));
diff --git a/mm/slab.h b/mm/slab.h
index f730e012553c..e767aa7e91b0 100644
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -422,6 +422,7 @@ static inline bool is_kmalloc_normal(struct kmem_cache *s)
bool __kfree_rcu_sheaf(struct kmem_cache *s, void *obj);
void flush_all_rcu_sheaves(void);
+void flush_rcu_sheaves_on_cache(struct kmem_cache *s);
#define SLAB_CORE_FLAGS (SLAB_HWCACHE_ALIGN | SLAB_CACHE_DMA | \
SLAB_CACHE_DMA32 | SLAB_PANIC | \
diff --git a/mm/slab_common.c b/mm/slab_common.c
index b613533b29e7..eed7ea556cb1 100644
--- a/mm/slab_common.c
+++ b/mm/slab_common.c
@@ -492,7 +492,7 @@ void kmem_cache_destroy(struct kmem_cache *s)
return;
/* in-flight kfree_rcu()'s may include objects from our cache */
- kvfree_rcu_barrier();
+ kvfree_rcu_barrier_on_cache(s);
if (IS_ENABLED(CONFIG_SLUB_RCU_DEBUG) &&
(s->flags & SLAB_TYPESAFE_BY_RCU)) {
@@ -2038,25 +2038,13 @@ unlock_return:
}
EXPORT_SYMBOL_GPL(kvfree_call_rcu);
-/**
- * kvfree_rcu_barrier - Wait until all in-flight kvfree_rcu() complete.
- *
- * Note that a single argument of kvfree_rcu() call has a slow path that
- * triggers synchronize_rcu() following by freeing a pointer. It is done
- * before the return from the function. Therefore for any single-argument
- * call that will result in a kfree() to a cache that is to be destroyed
- * during module exit, it is developer's responsibility to ensure that all
- * such calls have returned before the call to kmem_cache_destroy().
- */
-void kvfree_rcu_barrier(void)
+static inline void __kvfree_rcu_barrier(void)
{
struct kfree_rcu_cpu_work *krwp;
struct kfree_rcu_cpu *krcp;
bool queued;
int i, cpu;
- flush_all_rcu_sheaves();
-
/*
* Firstly we detach objects and queue them over an RCU-batch
* for all CPUs. Finally queued works are flushed for each CPU.
@@ -2118,8 +2106,43 @@ void kvfree_rcu_barrier(void)
}
}
}
+
+/**
+ * kvfree_rcu_barrier - Wait until all in-flight kvfree_rcu() complete.
+ *
+ * Note that a single argument of kvfree_rcu() call has a slow path that
+ * triggers synchronize_rcu() following by freeing a pointer. It is done
+ * before the return from the function. Therefore for any single-argument
+ * call that will result in a kfree() to a cache that is to be destroyed
+ * during module exit, it is developer's responsibility to ensure that all
+ * such calls have returned before the call to kmem_cache_destroy().
+ */
+void kvfree_rcu_barrier(void)
+{
+ flush_all_rcu_sheaves();
+ __kvfree_rcu_barrier();
+}
EXPORT_SYMBOL_GPL(kvfree_rcu_barrier);
+/**
+ * kvfree_rcu_barrier_on_cache - Wait for in-flight kvfree_rcu() calls on a
+ * specific slab cache.
+ * @s: slab cache to wait for
+ *
+ * See the description of kvfree_rcu_barrier() for details.
+ */
+void kvfree_rcu_barrier_on_cache(struct kmem_cache *s)
+{
+ if (s->cpu_sheaves)
+ flush_rcu_sheaves_on_cache(s);
+ /*
+ * TODO: Introduce a version of __kvfree_rcu_barrier() that works
+ * on a specific slab cache.
+ */
+ __kvfree_rcu_barrier();
+}
+EXPORT_SYMBOL_GPL(kvfree_rcu_barrier_on_cache);
+
static unsigned long
kfree_rcu_shrink_count(struct shrinker *shrink, struct shrink_control *sc)
{
@@ -2215,4 +2238,3 @@ void __init kvfree_rcu_init(void)
}
#endif /* CONFIG_KVFREE_RCU_BATCHED */
-
diff --git a/mm/slub.c b/mm/slub.c
index e6a330e24145..f21b2f0c6f5a 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -4122,42 +4122,47 @@ static void flush_rcu_sheaf(struct work_struct *w)
/* needed for kvfree_rcu_barrier() */
-void flush_all_rcu_sheaves(void)
+void flush_rcu_sheaves_on_cache(struct kmem_cache *s)
{
struct slub_flush_work *sfw;
- struct kmem_cache *s;
unsigned int cpu;
- cpus_read_lock();
- mutex_lock(&slab_mutex);
+ mutex_lock(&flush_lock);
- list_for_each_entry(s, &slab_caches, list) {
- if (!s->cpu_sheaves)
- continue;
+ for_each_online_cpu(cpu) {
+ sfw = &per_cpu(slub_flush, cpu);
- mutex_lock(&flush_lock);
+ /*
+ * we don't check if rcu_free sheaf exists - racing
+ * __kfree_rcu_sheaf() might have just removed it.
+ * by executing flush_rcu_sheaf() on the cpu we make
+ * sure the __kfree_rcu_sheaf() finished its call_rcu()
+ */
- for_each_online_cpu(cpu) {
- sfw = &per_cpu(slub_flush, cpu);
+ INIT_WORK(&sfw->work, flush_rcu_sheaf);
+ sfw->s = s;
+ queue_work_on(cpu, flushwq, &sfw->work);
+ }
- /*
- * we don't check if rcu_free sheaf exists - racing
- * __kfree_rcu_sheaf() might have just removed it.
- * by executing flush_rcu_sheaf() on the cpu we make
- * sure the __kfree_rcu_sheaf() finished its call_rcu()
- */
+ for_each_online_cpu(cpu) {
+ sfw = &per_cpu(slub_flush, cpu);
+ flush_work(&sfw->work);
+ }
- INIT_WORK(&sfw->work, flush_rcu_sheaf);
- sfw->s = s;
- queue_work_on(cpu, flushwq, &sfw->work);
- }
+ mutex_unlock(&flush_lock);
+}
- for_each_online_cpu(cpu) {
- sfw = &per_cpu(slub_flush, cpu);
- flush_work(&sfw->work);
- }
+void flush_all_rcu_sheaves(void)
+{
+ struct kmem_cache *s;
+
+ cpus_read_lock();
+ mutex_lock(&slab_mutex);
- mutex_unlock(&flush_lock);
+ list_for_each_entry(s, &slab_caches, list) {
+ if (!s->cpu_sheaves)
+ continue;
+ flush_rcu_sheaves_on_cache(s);
}
mutex_unlock(&slab_mutex);
diff --git a/net/sunrpc/backchannel_rqst.c b/net/sunrpc/backchannel_rqst.c
index caa94cf57123..68b1fcdea8f0 100644
--- a/net/sunrpc/backchannel_rqst.c
+++ b/net/sunrpc/backchannel_rqst.c
@@ -25,6 +25,22 @@ unsigned int xprt_bc_max_slots(struct rpc_xprt *xprt)
}
/*
+ * Helper function to nullify backchannel server pointer in transport.
+ * We need to synchronize setting the pointer to NULL (done so after
+ * the backchannel server is shutdown) with the usage of that pointer
+ * by the backchannel request processing routines
+ * xprt_complete_bc_request() and rpcrdma_bc_receive_call().
+ */
+void xprt_svc_destroy_nullify_bc(struct rpc_xprt *xprt, struct svc_serv **serv)
+{
+ spin_lock(&xprt->bc_pa_lock);
+ svc_destroy(serv);
+ xprt->bc_serv = NULL;
+ spin_unlock(&xprt->bc_pa_lock);
+}
+EXPORT_SYMBOL_GPL(xprt_svc_destroy_nullify_bc);
+
+/*
* Helper routines that track the number of preallocation elements
* on the transport.
*/
@@ -354,7 +370,6 @@ found:
void xprt_complete_bc_request(struct rpc_rqst *req, uint32_t copied)
{
struct rpc_xprt *xprt = req->rq_xprt;
- struct svc_serv *bc_serv = xprt->bc_serv;
spin_lock(&xprt->bc_pa_lock);
list_del(&req->rq_bc_pa_list);
@@ -365,7 +380,21 @@ void xprt_complete_bc_request(struct rpc_rqst *req, uint32_t copied)
set_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state);
dprintk("RPC: add callback request to list\n");
+ xprt_enqueue_bc_request(req);
+}
+
+void xprt_enqueue_bc_request(struct rpc_rqst *req)
+{
+ struct rpc_xprt *xprt = req->rq_xprt;
+ struct svc_serv *bc_serv;
+
xprt_get(xprt);
- lwq_enqueue(&req->rq_bc_list, &bc_serv->sv_cb_list);
- svc_pool_wake_idle_thread(&bc_serv->sv_pools[0]);
+ spin_lock(&xprt->bc_pa_lock);
+ bc_serv = xprt->bc_serv;
+ if (bc_serv) {
+ lwq_enqueue(&req->rq_bc_list, &bc_serv->sv_cb_list);
+ svc_pool_wake_idle_thread(&bc_serv->sv_pools[0]);
+ }
+ spin_unlock(&xprt->bc_pa_lock);
}
+EXPORT_SYMBOL_GPL(xprt_enqueue_bc_request);
diff --git a/net/sunrpc/xprtrdma/backchannel.c b/net/sunrpc/xprtrdma/backchannel.c
index 8c817e755262..2f0f9618dd05 100644
--- a/net/sunrpc/xprtrdma/backchannel.c
+++ b/net/sunrpc/xprtrdma/backchannel.c
@@ -9,6 +9,7 @@
#include <linux/sunrpc/svc.h>
#include <linux/sunrpc/svc_xprt.h>
#include <linux/sunrpc/svc_rdma.h>
+#include <linux/sunrpc/bc_xprt.h>
#include "xprt_rdma.h"
#include <trace/events/rpcrdma.h>
@@ -220,7 +221,6 @@ void rpcrdma_bc_receive_call(struct rpcrdma_xprt *r_xprt,
struct rpcrdma_rep *rep)
{
struct rpc_xprt *xprt = &r_xprt->rx_xprt;
- struct svc_serv *bc_serv;
struct rpcrdma_req *req;
struct rpc_rqst *rqst;
struct xdr_buf *buf;
@@ -261,11 +261,7 @@ void rpcrdma_bc_receive_call(struct rpcrdma_xprt *r_xprt,
trace_xprtrdma_cb_call(r_xprt, rqst);
/* Queue rqst for ULP's callback service */
- bc_serv = xprt->bc_serv;
- xprt_get(xprt);
- lwq_enqueue(&rqst->rq_bc_list, &bc_serv->sv_cb_list);
-
- svc_pool_wake_idle_thread(&bc_serv->sv_pools[0]);
+ xprt_enqueue_bc_request(rqst);
r_xprt->rx_stats.bcall_count++;
return;
diff --git a/scripts/coccinelle/api/pm_runtime.cocci b/scripts/coccinelle/api/pm_runtime.cocci
index 2c931e748dda..bf128ccae921 100644
--- a/scripts/coccinelle/api/pm_runtime.cocci
+++ b/scripts/coccinelle/api/pm_runtime.cocci
@@ -37,7 +37,6 @@ ret@p = \(pm_runtime_idle\|
pm_runtime_put_sync_autosuspend\|
pm_runtime_set_active\|
pm_schedule_suspend\|
- pm_runtime_barrier\|
pm_generic_runtime_suspend\|
pm_generic_runtime_resume\)(...);
...
diff --git a/scripts/package/install-extmod-build b/scripts/package/install-extmod-build
index 054fdf45cc37..2576cf7902db 100755
--- a/scripts/package/install-extmod-build
+++ b/scripts/package/install-extmod-build
@@ -63,7 +63,7 @@ if [ "${CC}" != "${HOSTCC}" ]; then
# Clear VPATH and srcroot because the source files reside in the output
# directory.
# shellcheck disable=SC2016 # $(MAKE) and $(build) will be expanded by Make
- "${MAKE}" run-command KBUILD_RUN_COMMAND='+$(MAKE) HOSTCC='"${CC}"' VPATH= srcroot=. $(build)='"$(realpath --relative-to=. "${destdir}")"/scripts
+ "${MAKE}" run-command KBUILD_RUN_COMMAND='+$(MAKE) HOSTCC="'"${CC}"'" VPATH= srcroot=. $(build)='"$(realpath --relative-to=. "${destdir}")"/scripts
rm -f "${destdir}/scripts/Kbuild"
fi
diff --git a/scripts/tracepoint-update.c b/scripts/tracepoint-update.c
index 7f7d90df14ce..90046aedc97b 100644
--- a/scripts/tracepoint-update.c
+++ b/scripts/tracepoint-update.c
@@ -210,6 +210,9 @@ static int process_tracepoints(bool mod, void *addr, const char *fname)
}
if (!tracepoint_data_sec) {
+ /* A module may reference only exported tracepoints */
+ if (mod)
+ return 0;
fprintf(stderr, "no __tracepoint_strings in file: %s\n", fname);
return -1;
}
diff --git a/sound/core/Kconfig b/sound/core/Kconfig
index 48db44fa56fe..4e7bc370ffd7 100644
--- a/sound/core/Kconfig
+++ b/sound/core/Kconfig
@@ -155,7 +155,7 @@ config SND_MAX_CARDS
config SND_SUPPORT_OLD_API
bool "Support old ALSA API"
- default y
+ default n
help
Say Y here to support the obsolete ALSA PCM API (ver.0.9.0 rc3
or older).
diff --git a/sound/firewire/motu/motu-hwdep.c b/sound/firewire/motu/motu-hwdep.c
index 981c19430cb0..89dc436a0652 100644
--- a/sound/firewire/motu/motu-hwdep.c
+++ b/sound/firewire/motu/motu-hwdep.c
@@ -75,7 +75,7 @@ static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
while (consumed < count &&
snd_motu_register_dsp_message_parser_copy_event(motu, &ev)) {
ptr = (u32 __user *)(buf + consumed);
- if (put_user(ev, ptr))
+ if (consumed + sizeof(ev) > count || put_user(ev, ptr))
return -EFAULT;
consumed += sizeof(ev);
}
@@ -83,10 +83,11 @@ static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
event.motu_register_dsp_change.type = SNDRV_FIREWIRE_EVENT_MOTU_REGISTER_DSP_CHANGE;
event.motu_register_dsp_change.count =
(consumed - sizeof(event.motu_register_dsp_change)) / 4;
- if (copy_to_user(buf, &event, sizeof(event.motu_register_dsp_change)))
+ if (copy_to_user(buf, &event,
+ min_t(long, count, sizeof(event.motu_register_dsp_change))))
return -EFAULT;
- count = consumed;
+ count = min_t(long, count, consumed);
} else {
spin_unlock_irq(&motu->lock);
diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c
index d90a6c01f63b..171a71457ec3 100644
--- a/sound/hda/codecs/realtek/alc269.c
+++ b/sound/hda/codecs/realtek/alc269.c
@@ -6770,6 +6770,9 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8e60, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8e61, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8e62, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8e8a, "HP NexusX", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED),
+ SND_PCI_QUIRK(0x103c, 0x8e9d, "HP 17 Turbine OmniBook X UMA", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8e9e, "HP 17 Turbine OmniBook X UMA", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8eb6, "HP Abe A6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
SND_PCI_QUIRK(0x103c, 0x8eb7, "HP Abe A6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
SND_PCI_QUIRK(0x103c, 0x8eb8, "HP Abe A6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
@@ -6842,6 +6845,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A),
SND_PCI_QUIRK(0x1043, 0x1533, "ASUS GV302XA/XJ/XQ/XU/XV/XI", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x1573, "ASUS GZ301VV/VQ/VU/VJ/VA/VC/VE/VVC/VQC/VUC/VJC/VEC/VCC", ALC285_FIXUP_ASUS_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1043, 0x1584, "ASUS UM3406GA ", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x1652, "ASUS ROG Zephyrus Do 15 SE", ALC289_FIXUP_ASUS_ZEPHYRUS_DUAL_SPK),
SND_PCI_QUIRK(0x1043, 0x1662, "ASUS GV301QH", ALC294_FIXUP_ASUS_DUAL_SPK),
SND_PCI_QUIRK(0x1043, 0x1663, "ASUS GU603ZI/ZJ/ZQ/ZU/ZV", ALC285_FIXUP_ASUS_HEADSET_MIC),
diff --git a/sound/hda/codecs/side-codecs/cs35l41_hda.c b/sound/hda/codecs/side-codecs/cs35l41_hda.c
index c0f2a3ff77a1..21e00055c0c4 100644
--- a/sound/hda/codecs/side-codecs/cs35l41_hda.c
+++ b/sound/hda/codecs/side-codecs/cs35l41_hda.c
@@ -1901,6 +1901,8 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i
cs35l41->dacpi = adev;
physdev = get_device(acpi_get_first_physical_node(adev));
+ if (!physdev)
+ return -ENODEV;
sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev));
if (IS_ERR(sub))
diff --git a/sound/hda/controllers/Kconfig b/sound/hda/controllers/Kconfig
index 34721f50b055..72855f2df451 100644
--- a/sound/hda/controllers/Kconfig
+++ b/sound/hda/controllers/Kconfig
@@ -30,6 +30,20 @@ config SND_HDA_TEGRA
To compile this driver as a module, choose M here: the module
will be called snd-hda-tegra.
+config SND_HDA_CIX_IPBLOQ
+ tristate "CIX IPBLOQ HD Audio"
+ depends on ARCH_CIX || COMPILE_TEST
+ select SND_HDA
+ select SND_HDA_ALIGNED_MMIO
+ help
+ Say Y here to support the HDA controller present in CIX SoCs
+
+ This options enables support for the HD Audio controller
+ present in some CIX SoCs.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-hda-cix-ipbloq.
+
config SND_HDA_ACPI
tristate "HD Audio ACPI"
depends on ACPI
diff --git a/sound/hda/controllers/Makefile b/sound/hda/controllers/Makefile
index a4bcd055e9ae..8967b6771d90 100644
--- a/sound/hda/controllers/Makefile
+++ b/sound/hda/controllers/Makefile
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
snd-hda-intel-y := intel.o
snd-hda-tegra-y := tegra.o
+snd-hda-cix-ipbloq-y := cix-ipbloq.o
snd-hda-acpi-y := acpi.o
subdir-ccflags-y += -I$(src)/../common
@@ -10,4 +11,5 @@ CFLAGS_intel.o := -I$(src)
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o
obj-$(CONFIG_SND_HDA_TEGRA) += snd-hda-tegra.o
+obj-$(CONFIG_SND_HDA_CIX_IPBLOQ) += snd-hda-cix-ipbloq.o
obj-$(CONFIG_SND_HDA_ACPI) += snd-hda-acpi.o
diff --git a/sound/hda/controllers/cix-ipbloq.c b/sound/hda/controllers/cix-ipbloq.c
new file mode 100644
index 000000000000..99f9f48e91d4
--- /dev/null
+++ b/sound/hda/controllers/cix-ipbloq.c
@@ -0,0 +1,436 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright 2025 Cix Technology Group Co., Ltd.
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <linux/string.h>
+
+#include <sound/hda_codec.h>
+#include "hda_controller.h"
+
+#define CIX_IPBLOQ_JACKPOLL_DEFAULT_TIME_MS 1000
+#define CIX_IPBLOQ_POWER_SAVE_DEFAULT_TIME_MS 100
+
+#define CIX_IPBLOQ_SKY1_ADDR_HOST_TO_HDAC_OFFSET (-0x90000000ULL)
+
+struct cix_ipbloq_hda {
+ struct azx chip;
+ struct device *dev;
+ void __iomem *regs;
+
+ struct reset_control *reset;
+ struct clk_bulk_data clocks[2];
+ unsigned int nclocks;
+};
+
+static const struct hda_controller_ops cix_ipbloq_hda_ops;
+
+static int cix_ipbloq_hda_dev_disconnect(struct snd_device *device)
+{
+ struct azx *chip = device->device_data;
+
+ chip->bus.shutdown = 1;
+
+ return 0;
+}
+
+static int cix_ipbloq_hda_dev_free(struct snd_device *device)
+{
+ struct azx *chip = device->device_data;
+
+ if (azx_bus(chip)->chip_init) {
+ azx_stop_all_streams(chip);
+ azx_stop_chip(chip);
+ }
+
+ azx_free_stream_pages(chip);
+ azx_free_streams(chip);
+ snd_hdac_bus_exit(azx_bus(chip));
+
+ return 0;
+}
+
+static int cix_ipbloq_hda_probe_codec(struct cix_ipbloq_hda *hda)
+{
+ struct azx *chip = &hda->chip;
+ struct hdac_bus *bus = azx_bus(chip);
+ int err;
+
+ to_hda_bus(bus)->bus_probing = 1;
+
+ /* create codec instances */
+ err = azx_probe_codecs(chip, 8);
+ if (err < 0) {
+ dev_err(hda->dev, "probe codecs failed: %d\n", err);
+ return err;
+ }
+
+ err = azx_codec_configure(chip);
+ if (err < 0) {
+ dev_err(hda->dev, "codec configure failed: %d\n", err);
+ return err;
+ }
+
+ err = snd_card_register(chip->card);
+ if (err < 0) {
+ dev_err(hda->dev, "card register failed: %d\n", err);
+ return err;
+ }
+
+ chip->running = 1;
+
+ to_hda_bus(bus)->bus_probing = 0;
+
+ snd_hda_set_power_save(&chip->bus, CIX_IPBLOQ_POWER_SAVE_DEFAULT_TIME_MS);
+
+ return 0;
+}
+
+static int cix_ipbloq_hda_init(struct cix_ipbloq_hda *hda,
+ struct azx *chip,
+ struct platform_device *pdev)
+{
+ const char *sname = NULL, *drv_name = "cix-ipbloq-hda";
+ struct hdac_bus *bus = azx_bus(chip);
+ struct snd_card *card = chip->card;
+ struct resource *res;
+ unsigned short gcap;
+ int irq_id, err;
+
+ hda->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+ if (IS_ERR(hda->regs)) {
+ dev_err(hda->dev, "failed to get and ioremap resource\n");
+ return PTR_ERR(hda->regs);
+ }
+ bus->remap_addr = hda->regs;
+ bus->addr = res->start;
+
+ irq_id = platform_get_irq(pdev, 0);
+ if (irq_id < 0) {
+ dev_err(hda->dev, "failed to get the irq, err = %d\n", irq_id);
+ return irq_id;
+ }
+
+ err = devm_request_irq(hda->dev, irq_id, azx_interrupt,
+ 0, KBUILD_MODNAME, chip);
+ if (err < 0)
+ return dev_err_probe(hda->dev, err,
+ "unable to request IRQ %d : err = %d\n", irq_id, err);
+ bus->irq = irq_id;
+ card->sync_irq = bus->irq;
+
+ gcap = azx_readw(chip, GCAP);
+ chip->capture_streams = (gcap >> 8) & 0x0f;
+ chip->playback_streams = (gcap >> 12) & 0x0f;
+ chip->capture_index_offset = 0;
+ chip->playback_index_offset = chip->capture_streams;
+ chip->num_streams = chip->playback_streams + chip->capture_streams;
+
+ /* initialize streams */
+ err = azx_init_streams(chip);
+ if (err < 0) {
+ dev_err(hda->dev, "failed to initialize streams: %d\n", err);
+ return err;
+ }
+
+ err = azx_alloc_stream_pages(chip);
+ if (err < 0) {
+ dev_err(hda->dev, "failed to allocate stream pages: %d\n", err);
+ return err;
+ }
+
+ /* initialize chip */
+ azx_init_chip(chip, 1);
+
+ /* codec detection */
+ if (!bus->codec_mask) {
+ dev_err(hda->dev, "no codecs found\n");
+ return -ENODEV;
+ }
+ dev_dbg(card->dev, "codec detection mask = 0x%lx\n", bus->codec_mask);
+
+ /* driver name */
+ strscpy(card->driver, drv_name, sizeof(card->driver));
+
+ /* shortname for card */
+ sname = of_get_property(pdev->dev.of_node, "model", NULL);
+ if (!sname)
+ sname = drv_name;
+ if (strlen(sname) > sizeof(card->shortname))
+ dev_dbg(card->dev, "truncating shortname for card\n");
+ strscpy(card->shortname, sname, sizeof(card->shortname));
+
+ /* longname for card */
+ snprintf(card->longname, sizeof(card->longname),
+ "%s at 0x%lx irq %i",
+ card->shortname, bus->addr, bus->irq);
+
+ return 0;
+}
+
+static int cix_ipbloq_hda_create(struct cix_ipbloq_hda *hda,
+ struct snd_card *card,
+ unsigned int driver_caps)
+{
+ static const struct snd_device_ops ops = {
+ .dev_disconnect = cix_ipbloq_hda_dev_disconnect,
+ .dev_free = cix_ipbloq_hda_dev_free,
+ };
+ struct azx *chip;
+ int err;
+
+ chip = &hda->chip;
+ chip->card = card;
+ chip->ops = &cix_ipbloq_hda_ops;
+ chip->driver_caps = driver_caps;
+ chip->driver_type = driver_caps & 0xff;
+ chip->dev_index = 0;
+ chip->single_cmd = 0;
+ chip->codec_probe_mask = -1;
+ chip->align_buffer_size = 1;
+ chip->jackpoll_interval = msecs_to_jiffies(CIX_IPBLOQ_JACKPOLL_DEFAULT_TIME_MS);
+ mutex_init(&chip->open_mutex);
+ INIT_LIST_HEAD(&chip->pcm_list);
+
+ /*
+ * HD-audio controllers appear pretty inaccurate about the update-IRQ timing.
+ * The IRQ is issued before actually the data is processed. So use stream
+ * link position by default instead of dma position buffer.
+ */
+ chip->get_position[0] = chip->get_position[1] = azx_get_pos_lpib;
+
+ err = azx_bus_init(chip, NULL);
+ if (err < 0) {
+ dev_err(hda->dev, "failed to init bus, err = %d\n", err);
+ return err;
+ }
+
+ /* RIRBSTS.RINTFL cannot be cleared, cause interrupt storm */
+ chip->bus.core.polling_mode = 1;
+ chip->bus.core.not_use_interrupts = 1;
+
+ chip->bus.core.aligned_mmio = 1;
+ chip->bus.core.dma_stop_delay = 100;
+ chip->bus.core.addr_offset = (dma_addr_t)CIX_IPBLOQ_SKY1_ADDR_HOST_TO_HDAC_OFFSET;
+
+ chip->bus.jackpoll_in_suspend = 1;
+
+ err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+ if (err < 0) {
+ dev_err(card->dev, "failed to create device, err = %d\n", err);
+ return err;
+ }
+
+ return 0;
+}
+
+static int cix_ipbloq_hda_probe(struct platform_device *pdev)
+{
+ const unsigned int driver_flags = AZX_DCAPS_PM_RUNTIME;
+ struct cix_ipbloq_hda *hda;
+ struct snd_card *card;
+ struct azx *chip;
+ int err;
+
+ hda = devm_kzalloc(&pdev->dev, sizeof(*hda), GFP_KERNEL);
+ if (!hda)
+ return -ENOMEM;
+ hda->dev = &pdev->dev;
+
+ hda->reset = devm_reset_control_get(hda->dev, NULL);
+ if (IS_ERR(hda->reset))
+ return dev_err_probe(hda->dev, PTR_ERR(hda->reset),
+ "failed to get reset, err = %ld\n", PTR_ERR(hda->reset));
+
+ hda->clocks[hda->nclocks++].id = "ipg";
+ hda->clocks[hda->nclocks++].id = "per";
+ err = devm_clk_bulk_get(hda->dev, hda->nclocks, hda->clocks);
+ if (err < 0)
+ return dev_err_probe(hda->dev, err, "failed to get clk, err = %d\n", err);
+
+ dma_set_mask_and_coherent(hda->dev, DMA_BIT_MASK(32));
+
+ err = of_reserved_mem_device_init(hda->dev);
+ if (err < 0 && err != -ENODEV) {
+ dev_err(hda->dev,
+ "failed to init reserved mem for DMA, err = %d\n", err);
+ return err;
+ }
+
+ err = snd_card_new(hda->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+ THIS_MODULE, 0, &card);
+ if (err < 0)
+ return dev_err_probe(hda->dev, err, "failed to crate card, err = %d\n", err);
+
+ err = cix_ipbloq_hda_create(hda, card, driver_flags);
+ if (err < 0)
+ goto out_free_card;
+
+ chip = &hda->chip;
+ card->private_data = chip;
+ dev_set_drvdata(hda->dev, card);
+
+ pm_runtime_enable(hda->dev);
+ if (!azx_has_pm_runtime(chip))
+ pm_runtime_forbid(hda->dev);
+
+ err = pm_runtime_resume_and_get(hda->dev);
+ if (err < 0) {
+ dev_err(hda->dev, "runtime resume and get failed, err = %d\n", err);
+ goto out_free_device;
+ }
+
+ err = cix_ipbloq_hda_init(hda, chip, pdev);
+ if (err < 0)
+ goto out_free_device;
+
+ err = cix_ipbloq_hda_probe_codec(hda);
+ if (err < 0)
+ goto out_free_device;
+
+ pm_runtime_put(hda->dev);
+
+ return 0;
+
+out_free_device:
+ snd_device_free(card, chip);
+out_free_card:
+ snd_card_free(card);
+
+ return err;
+}
+
+static void cix_ipbloq_hda_remove(struct platform_device *pdev)
+{
+ struct snd_card *card = dev_get_drvdata(&pdev->dev);
+ struct azx *chip = card->private_data;
+
+ snd_device_free(card, chip);
+ snd_card_free(card);
+
+ pm_runtime_disable(&pdev->dev);
+}
+
+static void cix_ipbloq_hda_shutdown(struct platform_device *pdev)
+{
+ struct snd_card *card = dev_get_drvdata(&pdev->dev);
+ struct azx *chip;
+
+ if (!card)
+ return;
+
+ chip = card->private_data;
+ if (chip && chip->running)
+ azx_stop_chip(chip);
+}
+
+static int cix_ipbloq_hda_suspend(struct device *dev)
+{
+ struct snd_card *card = dev_get_drvdata(dev);
+ int rc;
+
+ rc = pm_runtime_force_suspend(dev);
+ if (rc < 0)
+ return rc;
+ snd_power_change_state(card, SNDRV_CTL_POWER_D3cold);
+
+ return 0;
+}
+
+static int cix_ipbloq_hda_resume(struct device *dev)
+{
+ struct snd_card *card = dev_get_drvdata(dev);
+ int rc;
+
+ rc = pm_runtime_force_resume(dev);
+ if (rc < 0)
+ return rc;
+ snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+
+ return 0;
+}
+
+static int cix_ipbloq_hda_runtime_suspend(struct device *dev)
+{
+ struct snd_card *card = dev_get_drvdata(dev);
+ struct azx *chip = card->private_data;
+ struct cix_ipbloq_hda *hda = container_of(chip, struct cix_ipbloq_hda, chip);
+
+ if (chip && chip->running) {
+ azx_stop_chip(chip);
+ azx_enter_link_reset(chip);
+ }
+
+ clk_bulk_disable_unprepare(hda->nclocks, hda->clocks);
+
+ return 0;
+}
+
+static int cix_ipbloq_hda_runtime_resume(struct device *dev)
+{
+ struct snd_card *card = dev_get_drvdata(dev);
+ struct azx *chip = card->private_data;
+ struct cix_ipbloq_hda *hda = container_of(chip, struct cix_ipbloq_hda, chip);
+ int rc;
+
+ rc = clk_bulk_prepare_enable(hda->nclocks, hda->clocks);
+ if (rc) {
+ dev_err(dev, "failed to enable clk bulk, rc: %d\n", rc);
+ return rc;
+ }
+
+ rc = reset_control_assert(hda->reset);
+ if (rc) {
+ dev_err(dev, "failed to assert reset, rc: %d\n", rc);
+ return rc;
+ }
+
+ rc = reset_control_deassert(hda->reset);
+ if (rc) {
+ dev_err(dev, "failed to deassert reset, rc: %d\n", rc);
+ return rc;
+ }
+
+ if (chip && chip->running)
+ azx_init_chip(chip, 1);
+
+ return 0;
+}
+
+static const struct dev_pm_ops cix_ipbloq_hda_pm = {
+ SYSTEM_SLEEP_PM_OPS(cix_ipbloq_hda_suspend,
+ cix_ipbloq_hda_resume)
+ RUNTIME_PM_OPS(cix_ipbloq_hda_runtime_suspend,
+ cix_ipbloq_hda_runtime_resume, NULL)
+};
+
+static const struct of_device_id cix_ipbloq_hda_match[] = {
+ { .compatible = "cix,sky1-ipbloq-hda" },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, cix_ipbloq_hda_match);
+
+static struct platform_driver cix_ipbloq_hda_driver = {
+ .driver = {
+ .name = "cix-ipbloq-hda",
+ .pm = pm_ptr(&cix_ipbloq_hda_pm),
+ .of_match_table = cix_ipbloq_hda_match,
+ },
+ .probe = cix_ipbloq_hda_probe,
+ .remove = cix_ipbloq_hda_remove,
+ .shutdown = cix_ipbloq_hda_shutdown,
+};
+module_platform_driver(cix_ipbloq_hda_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("CIX IPBLOQ HDA bus driver");
+MODULE_AUTHOR("Joakim Zhang <joakim.zhang@cixtech.com>");
diff --git a/sound/hda/core/bus.c b/sound/hda/core/bus.c
index 9b196c915f37..81498f1e413e 100644
--- a/sound/hda/core/bus.c
+++ b/sound/hda/core/bus.c
@@ -47,6 +47,7 @@ int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev,
INIT_LIST_HEAD(&bus->hlink_list);
init_waitqueue_head(&bus->rirb_wq);
bus->irq = -1;
+ bus->addr_offset = 0;
/*
* Default value of '8' is as per the HD audio specification (Rev 1.0a).
diff --git a/sound/hda/core/controller.c b/sound/hda/core/controller.c
index a7c00ad80117..69e11d62bbfa 100644
--- a/sound/hda/core/controller.c
+++ b/sound/hda/core/controller.c
@@ -48,8 +48,8 @@ void snd_hdac_bus_init_cmd_io(struct hdac_bus *bus)
/* CORB set up */
bus->corb.addr = bus->rb.addr;
bus->corb.buf = (__le32 *)bus->rb.area;
- snd_hdac_chip_writel(bus, CORBLBASE, (u32)bus->corb.addr);
- snd_hdac_chip_writel(bus, CORBUBASE, upper_32_bits(bus->corb.addr));
+ snd_hdac_chip_writel(bus, CORBLBASE, (u32)(bus->corb.addr + bus->addr_offset));
+ snd_hdac_chip_writel(bus, CORBUBASE, upper_32_bits(bus->corb.addr + bus->addr_offset));
/* set the corb size to 256 entries (ULI requires explicitly) */
snd_hdac_chip_writeb(bus, CORBSIZE, 0x02);
@@ -70,8 +70,8 @@ void snd_hdac_bus_init_cmd_io(struct hdac_bus *bus)
bus->rirb.buf = (__le32 *)(bus->rb.area + 2048);
bus->rirb.wp = bus->rirb.rp = 0;
memset(bus->rirb.cmds, 0, sizeof(bus->rirb.cmds));
- snd_hdac_chip_writel(bus, RIRBLBASE, (u32)bus->rirb.addr);
- snd_hdac_chip_writel(bus, RIRBUBASE, upper_32_bits(bus->rirb.addr));
+ snd_hdac_chip_writel(bus, RIRBLBASE, (u32)(bus->rirb.addr + bus->addr_offset));
+ snd_hdac_chip_writel(bus, RIRBUBASE, upper_32_bits(bus->rirb.addr + bus->addr_offset));
/* set the rirb size to 256 entries (ULI requires explicitly) */
snd_hdac_chip_writeb(bus, RIRBSIZE, 0x02);
@@ -625,8 +625,8 @@ bool snd_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset)
/* program the position buffer */
if (bus->use_posbuf && bus->posbuf.addr) {
- snd_hdac_chip_writel(bus, DPLBASE, (u32)bus->posbuf.addr);
- snd_hdac_chip_writel(bus, DPUBASE, upper_32_bits(bus->posbuf.addr));
+ snd_hdac_chip_writel(bus, DPLBASE, (u32)(bus->posbuf.addr + bus->addr_offset));
+ snd_hdac_chip_writel(bus, DPUBASE, upper_32_bits(bus->posbuf.addr + bus->addr_offset));
}
bus->chip_init = true;
diff --git a/sound/hda/core/intel-dsp-config.c b/sound/hda/core/intel-dsp-config.c
index c401c0658421..0c25e87408de 100644
--- a/sound/hda/core/intel-dsp-config.c
+++ b/sound/hda/core/intel-dsp-config.c
@@ -718,7 +718,8 @@ int snd_intel_dsp_driver_probe(struct pci_dev *pci)
/* find the configuration for the specific device */
cfg = snd_intel_dsp_find_config(pci, config_table, ARRAY_SIZE(config_table));
if (!cfg)
- return SND_INTEL_DSP_DRIVER_ANY;
+ return IS_ENABLED(CONFIG_SND_HDA_INTEL) ?
+ SND_INTEL_DSP_DRIVER_LEGACY : SND_INTEL_DSP_DRIVER_ANY;
if (cfg->flags & FLAG_SOF) {
if (cfg->flags & FLAG_SOF_ONLY_IF_SOUNDWIRE &&
diff --git a/sound/hda/core/stream.c b/sound/hda/core/stream.c
index 579ec544ef4a..b471a038b314 100644
--- a/sound/hda/core/stream.c
+++ b/sound/hda/core/stream.c
@@ -288,16 +288,16 @@ int snd_hdac_stream_setup(struct hdac_stream *azx_dev, bool code_loading)
/* program the BDL address */
/* lower BDL address */
- snd_hdac_stream_writel(azx_dev, SD_BDLPL, (u32)azx_dev->bdl.addr);
+ snd_hdac_stream_writel(azx_dev, SD_BDLPL, (u32)(azx_dev->bdl.addr + bus->addr_offset));
/* upper BDL address */
snd_hdac_stream_writel(azx_dev, SD_BDLPU,
- upper_32_bits(azx_dev->bdl.addr));
+ upper_32_bits(azx_dev->bdl.addr + bus->addr_offset));
/* enable the position buffer */
if (bus->use_posbuf && bus->posbuf.addr) {
if (!(snd_hdac_chip_readl(bus, DPLBASE) & AZX_DPLBASE_ENABLE))
snd_hdac_chip_writel(bus, DPLBASE,
- (u32)bus->posbuf.addr | AZX_DPLBASE_ENABLE);
+ (u32)(bus->posbuf.addr + bus->addr_offset) | AZX_DPLBASE_ENABLE);
}
/* set the interrupt enable bits in the descriptor control register */
@@ -464,8 +464,8 @@ static int setup_bdle(struct hdac_bus *bus,
addr = snd_sgbuf_get_addr(dmab, ofs);
/* program the address field of the BDL entry */
- bdl[0] = cpu_to_le32((u32)addr);
- bdl[1] = cpu_to_le32(upper_32_bits(addr));
+ bdl[0] = cpu_to_le32((u32)(addr + bus->addr_offset));
+ bdl[1] = cpu_to_le32(upper_32_bits(addr + bus->addr_offset));
/* program the size field of the BDL entry */
chunk = snd_sgbuf_get_chunk_size(dmab, ofs, size);
/* one BDLE cannot cross 4K boundary on CTHDA chips */
diff --git a/sound/soc/amd/acp/acp-i2s.c b/sound/soc/amd/acp/acp-i2s.c
index 4ba0a66981ea..283a674c7e2c 100644
--- a/sound/soc/amd/acp/acp-i2s.c
+++ b/sound/soc/amd/acp/acp-i2s.c
@@ -157,6 +157,8 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas
spin_lock_irq(&chip->acp_lock);
list_for_each_entry(stream, &chip->stream_list, list) {
+ if (dai->id != stream->dai_id)
+ continue;
switch (chip->acp_rev) {
case ACP_RN_PCI_ID:
case ACP_RMB_PCI_ID:
diff --git a/sound/soc/amd/acp/acp-legacy-common.c b/sound/soc/amd/acp/acp-legacy-common.c
index 3078f459e005..4e477c48d4bd 100644
--- a/sound/soc/amd/acp/acp-legacy-common.c
+++ b/sound/soc/amd/acp/acp-legacy-common.c
@@ -219,7 +219,10 @@ static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream,
SP_PB_FIFO_ADDR_OFFSET;
reg_fifo_addr = ACP_I2S_TX_FIFOADDR(chip);
reg_fifo_size = ACP_I2S_TX_FIFOSIZE(chip);
- phy_addr = I2S_SP_TX_MEM_WINDOW_START + stream->reg_offset;
+ if (chip->acp_rev >= ACP70_PCI_ID)
+ phy_addr = ACP7x_I2S_SP_TX_MEM_WINDOW_START;
+ else
+ phy_addr = I2S_SP_TX_MEM_WINDOW_START + stream->reg_offset;
writel(phy_addr, chip->base + ACP_I2S_TX_RINGBUFADDR(chip));
} else {
reg_dma_size = ACP_I2S_RX_DMA_SIZE(chip);
@@ -227,7 +230,10 @@ static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream,
SP_CAPT_FIFO_ADDR_OFFSET;
reg_fifo_addr = ACP_I2S_RX_FIFOADDR(chip);
reg_fifo_size = ACP_I2S_RX_FIFOSIZE(chip);
- phy_addr = I2S_SP_RX_MEM_WINDOW_START + stream->reg_offset;
+ if (chip->acp_rev >= ACP70_PCI_ID)
+ phy_addr = ACP7x_I2S_SP_RX_MEM_WINDOW_START;
+ else
+ phy_addr = I2S_SP_RX_MEM_WINDOW_START + stream->reg_offset;
writel(phy_addr, chip->base + ACP_I2S_RX_RINGBUFADDR(chip));
}
break;
@@ -238,7 +244,10 @@ static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream,
BT_PB_FIFO_ADDR_OFFSET;
reg_fifo_addr = ACP_BT_TX_FIFOADDR(chip);
reg_fifo_size = ACP_BT_TX_FIFOSIZE(chip);
- phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;
+ if (chip->acp_rev >= ACP70_PCI_ID)
+ phy_addr = ACP7x_I2S_BT_TX_MEM_WINDOW_START;
+ else
+ phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;
writel(phy_addr, chip->base + ACP_BT_TX_RINGBUFADDR(chip));
} else {
reg_dma_size = ACP_BT_RX_DMA_SIZE(chip);
@@ -246,7 +255,10 @@ static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream,
BT_CAPT_FIFO_ADDR_OFFSET;
reg_fifo_addr = ACP_BT_RX_FIFOADDR(chip);
reg_fifo_size = ACP_BT_RX_FIFOSIZE(chip);
- phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;
+ if (chip->acp_rev >= ACP70_PCI_ID)
+ phy_addr = ACP7x_I2S_BT_RX_MEM_WINDOW_START;
+ else
+ phy_addr = I2S_BT_RX_MEM_WINDOW_START + stream->reg_offset;
writel(phy_addr, chip->base + ACP_BT_RX_RINGBUFADDR(chip));
}
break;
@@ -257,7 +269,10 @@ static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream,
HS_PB_FIFO_ADDR_OFFSET;
reg_fifo_addr = ACP_HS_TX_FIFOADDR;
reg_fifo_size = ACP_HS_TX_FIFOSIZE;
- phy_addr = I2S_HS_TX_MEM_WINDOW_START + stream->reg_offset;
+ if (chip->acp_rev >= ACP70_PCI_ID)
+ phy_addr = ACP7x_I2S_HS_TX_MEM_WINDOW_START;
+ else
+ phy_addr = I2S_HS_TX_MEM_WINDOW_START + stream->reg_offset;
writel(phy_addr, chip->base + ACP_HS_TX_RINGBUFADDR);
} else {
reg_dma_size = ACP_HS_RX_DMA_SIZE;
@@ -265,7 +280,10 @@ static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream,
HS_CAPT_FIFO_ADDR_OFFSET;
reg_fifo_addr = ACP_HS_RX_FIFOADDR;
reg_fifo_size = ACP_HS_RX_FIFOSIZE;
- phy_addr = I2S_HS_RX_MEM_WINDOW_START + stream->reg_offset;
+ if (chip->acp_rev >= ACP70_PCI_ID)
+ phy_addr = ACP7x_I2S_HS_RX_MEM_WINDOW_START;
+ else
+ phy_addr = I2S_HS_RX_MEM_WINDOW_START + stream->reg_offset;
writel(phy_addr, chip->base + ACP_HS_RX_RINGBUFADDR);
}
break;
diff --git a/sound/soc/bcm/bcm63xx-pcm-whistler.c b/sound/soc/bcm/bcm63xx-pcm-whistler.c
index e3a4fcc63a56..efeb06ddabeb 100644
--- a/sound/soc/bcm/bcm63xx-pcm-whistler.c
+++ b/sound/soc/bcm/bcm63xx-pcm-whistler.c
@@ -358,7 +358,9 @@ static int bcm63xx_soc_pcm_new(struct snd_soc_component *component,
i2s_priv = dev_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0)->dev);
- of_dma_configure(pcm->card->dev, pcm->card->dev->of_node, 1);
+ ret = of_dma_configure(pcm->card->dev, pcm->card->dev->of_node, 1);
+ if (ret)
+ return ret;
ret = dma_coerce_mask_and_coherent(pcm->card->dev, DMA_BIT_MASK(32));
if (ret)
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 6087ebde9523..061791e61907 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -777,7 +777,6 @@ config SND_SOC_CQ0093VC
config SND_SOC_CROS_EC_CODEC
tristate "codec driver for ChromeOS EC"
depends on CROS_EC
- select CRYPTO
select CRYPTO_LIB_SHA256
help
If you say yes here you will get support for the
@@ -918,7 +917,7 @@ config SND_SOC_CS35L56_CAL_DEBUGFS
config SND_SOC_CS35L56_CAL_SET_CTRL
bool "CS35L56 ALSA control to restore factory calibration"
default N
- select SND_SOC_CS35L56_CAL_SYSFS_COMMON
+ select SND_SOC_CS35L56_CAL_DEBUGFS_COMMON
help
Allow restoring factory calibration data through an ALSA
control. This is only needed on platforms without UEFI or
diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c
index f0b465f9ded5..783d2ef21c11 100644
--- a/sound/soc/codecs/ak4458.c
+++ b/sound/soc/codecs/ak4458.c
@@ -671,7 +671,15 @@ static int ak4458_runtime_resume(struct device *dev)
regcache_cache_only(ak4458->regmap, false);
regcache_mark_dirty(ak4458->regmap);
- return regcache_sync(ak4458->regmap);
+ ret = regcache_sync(ak4458->regmap);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ regcache_cache_only(ak4458->regmap, true);
+ regulator_bulk_disable(ARRAY_SIZE(ak4458->supplies), ak4458->supplies);
+ return ret;
}
static const struct snd_soc_component_driver soc_codec_dev_ak4458 = {
diff --git a/sound/soc/codecs/ak5558.c b/sound/soc/codecs/ak5558.c
index 683f3e472f50..73684fc5beb1 100644
--- a/sound/soc/codecs/ak5558.c
+++ b/sound/soc/codecs/ak5558.c
@@ -372,7 +372,15 @@ static int ak5558_runtime_resume(struct device *dev)
regcache_cache_only(ak5558->regmap, false);
regcache_mark_dirty(ak5558->regmap);
- return regcache_sync(ak5558->regmap);
+ ret = regcache_sync(ak5558->regmap);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ regcache_cache_only(ak5558->regmap, true);
+ regulator_bulk_disable(ARRAY_SIZE(ak5558->supplies), ak5558->supplies);
+ return ret;
}
static const struct dev_pm_ops ak5558_pm = {
diff --git a/sound/soc/codecs/cs-amp-lib.c b/sound/soc/codecs/cs-amp-lib.c
index 8c9fd9980a7d..d8f8b0259cd1 100644
--- a/sound/soc/codecs/cs-amp-lib.c
+++ b/sound/soc/codecs/cs-amp-lib.c
@@ -7,7 +7,6 @@
#include <asm/byteorder.h>
#include <kunit/static_stub.h>
-#include <linux/cleanup.h>
#include <linux/debugfs.h>
#include <linux/dev_printk.h>
#include <linux/efi.h>
@@ -310,8 +309,9 @@ static struct cirrus_amp_efi_data *cs_amp_get_cal_efi_buffer(struct device *dev,
efi_guid_t **guid,
u32 *attr)
{
- struct cirrus_amp_efi_data *efi_data __free(kfree) = NULL;
+ struct cirrus_amp_efi_data *efi_data;
unsigned long data_size = 0;
+ u8 *data;
efi_status_t status;
int i, ret;
@@ -339,18 +339,19 @@ static struct cirrus_amp_efi_data *cs_amp_get_cal_efi_buffer(struct device *dev,
}
/* Get variable contents into buffer */
- efi_data = kmalloc(data_size, GFP_KERNEL);
- if (!efi_data)
+ data = kmalloc(data_size, GFP_KERNEL);
+ if (!data)
return ERR_PTR(-ENOMEM);
status = cs_amp_get_efi_variable(cs_amp_lib_cal_efivars[i].name,
cs_amp_lib_cal_efivars[i].guid,
- attr, &data_size, efi_data);
+ attr, &data_size, data);
if (status != EFI_SUCCESS) {
ret = -EINVAL;
goto err;
}
+ efi_data = (struct cirrus_amp_efi_data *)data;
dev_dbg(dev, "Calibration: Size=%d, Amp Count=%d\n", efi_data->size, efi_data->count);
if ((efi_data->count > 128) ||
@@ -364,9 +365,10 @@ static struct cirrus_amp_efi_data *cs_amp_get_cal_efi_buffer(struct device *dev,
if (efi_data->size == 0)
efi_data->size = data_size;
- return_ptr(efi_data);
+ return efi_data;
err:
+ kfree(data);
dev_err(dev, "Failed to read calibration data from EFI: %d\n", ret);
return ERR_PTR(ret);
@@ -389,9 +391,9 @@ static int cs_amp_set_cal_efi_buffer(struct device *dev,
static int _cs_amp_get_efi_calibration_data(struct device *dev, u64 target_uid, int amp_index,
struct cirrus_amp_cal_data *out_data)
{
- struct cirrus_amp_efi_data *efi_data __free(kfree) = NULL;
+ struct cirrus_amp_efi_data *efi_data;
struct cirrus_amp_cal_data *cal = NULL;
- int i;
+ int i, ret;
efi_data = cs_amp_get_cal_efi_buffer(dev, NULL, NULL, NULL);
if (IS_ERR(efi_data))
@@ -432,14 +434,17 @@ static int _cs_amp_get_efi_calibration_data(struct device *dev, u64 target_uid,
dev_warn(dev, "Calibration entry %d does not match silicon ID", amp_index);
}
- if (!cal) {
+ if (cal) {
+ memcpy(out_data, cal, sizeof(*out_data));
+ ret = 0;
+ } else {
dev_warn(dev, "No calibration for silicon ID %#llx\n", target_uid);
- return -ENOENT;
+ ret = -ENOENT;
}
- memcpy(out_data, cal, sizeof(*out_data));
+ kfree(efi_data);
- return 0;
+ return ret;
}
static int _cs_amp_set_efi_calibration_data(struct device *dev, int amp_index, int num_amps,
diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c
index 3a8a8dd065b7..ee56dfceedeb 100644
--- a/sound/soc/codecs/cs35l41.c
+++ b/sound/soc/codecs/cs35l41.c
@@ -1188,13 +1188,14 @@ static int cs35l41_get_system_name(struct cs35l41_private *cs35l41)
}
}
-err:
if (sub) {
cs35l41->dsp.system_name = sub;
dev_info(cs35l41->dev, "Subsystem ID: %s\n", cs35l41->dsp.system_name);
- } else
- dev_warn(cs35l41->dev, "Subsystem ID not found\n");
+ return 0;
+ }
+err:
+ dev_warn(cs35l41->dev, "Subsystem ID not found\n");
return ret;
}
diff --git a/sound/soc/codecs/nau8325.c b/sound/soc/codecs/nau8325.c
index 3bfdb448f8bd..e651263a9812 100644
--- a/sound/soc/codecs/nau8325.c
+++ b/sound/soc/codecs/nau8325.c
@@ -386,7 +386,8 @@ static int nau8325_clksrc_choose(struct nau8325 *nau8325,
const struct nau8325_srate_attr **srate_table,
int *n1_sel, int *mult_sel, int *n2_sel)
{
- int i, j, mclk, mclk_max, ratio, ratio_sel, n2_max;
+ int i, j, mclk, ratio;
+ int mclk_max = 0, ratio_sel = 0, n2_max = 0;
if (!nau8325->mclk || !nau8325->fs)
goto proc_err;
@@ -408,7 +409,6 @@ static int nau8325_clksrc_choose(struct nau8325 *nau8325,
}
/* Get MCLK_SRC through 1/N, Multiplier, and then 1/N2. */
- mclk_max = 0;
for (i = 0; i < ARRAY_SIZE(mclk_n1_div); i++) {
for (j = 0; j < ARRAY_SIZE(mclk_n3_mult); j++) {
mclk = nau8325->mclk << mclk_n3_mult[j].param;
diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c
index f1dced57a59b..f4dbcf04be49 100644
--- a/sound/soc/codecs/wcd937x.c
+++ b/sound/soc/codecs/wcd937x.c
@@ -2866,7 +2866,7 @@ static int wcd937x_add_slave_components(struct wcd937x_priv *wcd937x,
dev_err(dev, "Couldn't parse phandle to qcom,rx-device!\n");
return -ENODEV;
}
- of_node_get(wcd937x->rxnode);
+
component_match_add_release(dev, matchptr, component_release_of,
component_compare_of, wcd937x->rxnode);
@@ -2875,7 +2875,7 @@ static int wcd937x_add_slave_components(struct wcd937x_priv *wcd937x,
dev_err(dev, "Couldn't parse phandle to qcom,tx-device\n");
return -ENODEV;
}
- of_node_get(wcd937x->txnode);
+
component_match_add_release(dev, matchptr, component_release_of,
component_compare_of, wcd937x->txnode);
diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c
index f5b7de2bc896..cb0a0bfdb6e3 100644
--- a/sound/soc/codecs/wcd938x.c
+++ b/sound/soc/codecs/wcd938x.c
@@ -3464,7 +3464,6 @@ static int wcd938x_add_slave_components(struct wcd938x_priv *wcd938x,
return -ENODEV;
}
- of_node_get(wcd938x->rxnode);
component_match_add_release(dev, matchptr, component_release_of,
component_compare_of, wcd938x->rxnode);
@@ -3473,7 +3472,7 @@ static int wcd938x_add_slave_components(struct wcd938x_priv *wcd938x,
dev_err(dev, "%s: Tx-device node not defined\n", __func__);
return -ENODEV;
}
- of_node_get(wcd938x->txnode);
+
component_match_add_release(dev, matchptr, component_release_of,
component_compare_of, wcd938x->txnode);
return 0;
diff --git a/sound/soc/codecs/wcd939x.c b/sound/soc/codecs/wcd939x.c
index 7c5dd0484384..01f1a08f48e6 100644
--- a/sound/soc/codecs/wcd939x.c
+++ b/sound/soc/codecs/wcd939x.c
@@ -3526,7 +3526,6 @@ static int wcd939x_add_slave_components(struct wcd939x_priv *wcd939x,
return -ENODEV;
}
- of_node_get(wcd939x->rxnode);
component_match_add_release(dev, matchptr, component_release_of,
component_compare_of, wcd939x->rxnode);
@@ -3535,7 +3534,7 @@ static int wcd939x_add_slave_components(struct wcd939x_priv *wcd939x,
dev_err(dev, "%s: Tx-device node not defined\n", __func__);
return -ENODEV;
}
- of_node_get(wcd939x->txnode);
+
component_match_add_release(dev, matchptr, component_release_of,
component_compare_of, wcd939x->txnode);
return 0;
diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c
index 980851a12976..0b01fc9e13a7 100644
--- a/sound/soc/qcom/qdsp6/q6afe.c
+++ b/sound/soc/qcom/qdsp6/q6afe.c
@@ -947,7 +947,7 @@ static struct q6afe_port *q6afe_find_port(struct q6afe *afe, int token)
struct q6afe_port *p;
struct q6afe_port *ret = NULL;
- guard(spinlock)(&afe->port_list_lock);
+ guard(spinlock_irqsave)(&afe->port_list_lock);
list_for_each_entry(p, &afe->port_list, node)
if (p->token == token) {
ret = p;
@@ -1807,7 +1807,7 @@ struct q6afe_port *q6afe_port_get_from_id(struct device *dev, int id)
port->cfg_type = cfg_type;
kref_init(&port->refcount);
- guard(spinlock)(&afe->port_list_lock);
+ guard(spinlock_irqsave)(&afe->port_list_lock);
list_add_tail(&port->node, &afe->port_list);
return port;
diff --git a/sound/soc/rockchip/rockchip_pdm.c b/sound/soc/rockchip/rockchip_pdm.c
index c1ee470ec607..c69cdd6f2499 100644
--- a/sound/soc/rockchip/rockchip_pdm.c
+++ b/sound/soc/rockchip/rockchip_pdm.c
@@ -580,7 +580,7 @@ static int rockchip_pdm_probe(struct platform_device *pdev)
if (!pdm)
return -ENOMEM;
- pdm->version = (enum rk_pdm_version)device_get_match_data(&pdev->dev);
+ pdm->version = (unsigned long)device_get_match_data(&pdev->dev);
if (pdm->version == RK_PDM_RK3308) {
pdm->reset = devm_reset_control_get(&pdev->dev, "pdm-m");
if (IS_ERR(pdm->reset))
diff --git a/sound/soc/sof/intel/hda-sdw-bpt.c b/sound/soc/sof/intel/hda-sdw-bpt.c
index ff5abccf0d88..e45dd051ab8c 100644
--- a/sound/soc/sof/intel/hda-sdw-bpt.c
+++ b/sound/soc/sof/intel/hda-sdw-bpt.c
@@ -10,6 +10,7 @@
* Hardware interface for SoundWire BPT support with HDA DMA
*/
+#include <linux/lcm.h>
#include <sound/hdaudio_ext.h>
#include <sound/hda-mlink.h>
#include <sound/hda-sdw-bpt.h>
@@ -236,6 +237,18 @@ static int hda_sdw_bpt_dma_disable(struct device *dev, struct hdac_ext_stream *s
return ret;
}
+#define FIFO_ALIGNMENT 64
+
+unsigned int hda_sdw_bpt_get_buf_size_alignment(unsigned int dma_bandwidth)
+{
+ unsigned int num_channels = DIV_ROUND_UP(dma_bandwidth, BPT_FREQUENCY * 32);
+ unsigned int data_block = num_channels * 4;
+ unsigned int alignment = lcm(data_block, FIFO_ALIGNMENT);
+
+ return alignment;
+}
+EXPORT_SYMBOL_NS(hda_sdw_bpt_get_buf_size_alignment, "SND_SOC_SOF_INTEL_HDA_SDW_BPT");
+
int hda_sdw_bpt_open(struct device *dev, int link_id, struct hdac_ext_stream **bpt_tx_stream,
struct snd_dma_buffer *dmab_tx_bdl, u32 bpt_tx_num_bytes,
u32 tx_dma_bandwidth, struct hdac_ext_stream **bpt_rx_stream,
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index f7189990dd6a..f8eccb1c58da 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -2545,6 +2545,7 @@ static int snd_rme_get_status1(struct snd_kcontrol *kcontrol,
struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
struct snd_usb_audio *chip = list->mixer->chip;
+ *status1 = 0;
CLASS(snd_usb_lock, pm)(chip);
if (pm.err < 0)
return pm.err;
diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c
index 0ce251b8d466..558138eea75e 100644
--- a/tools/power/x86/intel-speed-select/isst-config.c
+++ b/tools/power/x86/intel-speed-select/isst-config.c
@@ -16,7 +16,7 @@ struct process_cmd_struct {
int arg;
};
-static const char *version_str = "v1.23";
+static const char *version_str = "v1.24";
static const int supported_api_ver = 3;
static struct isst_if_platform_info isst_platform_info;
diff --git a/tools/power/x86/intel-speed-select/isst-core-tpmi.c b/tools/power/x86/intel-speed-select/isst-core-tpmi.c
index 4f389e1c0525..ebaad0dc8ca6 100644
--- a/tools/power/x86/intel-speed-select/isst-core-tpmi.c
+++ b/tools/power/x86/intel-speed-select/isst-core-tpmi.c
@@ -452,13 +452,16 @@ static int tpmi_get_pbf_info(struct isst_id *id, int level,
return _pbf_get_coremask_info(id, level, pbf_info);
}
+#define FEATURE_ENABLE_WAIT_US 1000
+#define FEATURE_ENABLE_RETRIES 5
+
static int tpmi_set_pbf_fact_status(struct isst_id *id, int pbf, int enable)
{
struct isst_pkg_ctdp pkg_dev;
struct isst_pkg_ctdp_level_info ctdp_level;
int current_level;
struct isst_perf_feature_control info;
- int ret;
+ int ret, i;
ret = isst_get_ctdp_levels(id, &pkg_dev);
if (ret)
@@ -503,6 +506,30 @@ static int tpmi_set_pbf_fact_status(struct isst_id *id, int pbf, int enable)
if (ret == -1)
return ret;
+ for (i = 0; i < FEATURE_ENABLE_RETRIES; ++i) {
+
+ usleep(FEATURE_ENABLE_WAIT_US);
+
+ /* Check status */
+ ret = isst_get_ctdp_control(id, current_level, &ctdp_level);
+ if (ret)
+ return ret;
+
+ debug_printf("pbf_enabled:%d fact_enabled:%d\n",
+ ctdp_level.pbf_enabled, ctdp_level.fact_enabled);
+
+ if (pbf) {
+ if (ctdp_level.pbf_enabled == enable)
+ break;
+ } else {
+ if (ctdp_level.fact_enabled == enable)
+ break;
+ }
+ }
+
+ if (i == FEATURE_ENABLE_RETRIES)
+ return -1;
+
return 0;
}
@@ -513,6 +540,7 @@ static int tpmi_get_fact_info(struct isst_id *id, int level, int fact_bucket,
int i, j;
int ret;
+ memset(&info, 0, sizeof(info));
info.socket_id = id->pkg;
info.power_domain_id = id->punit;
info.level = level;
@@ -659,7 +687,8 @@ static int tpmi_pm_qos_config(struct isst_id *id, int enable_clos,
int priority_type)
{
struct isst_core_power info;
- int i, ret, saved_punit;
+ int cp_state = 0, cp_cap = 0;
+ int i, j, ret, saved_punit;
info.get_set = 1;
info.socket_id = id->pkg;
@@ -679,6 +708,19 @@ static int tpmi_pm_qos_config(struct isst_id *id, int enable_clos,
id->punit = saved_punit;
return ret;
}
+ /* Get status */
+ for (j = 0; j < FEATURE_ENABLE_RETRIES; ++j) {
+ usleep(FEATURE_ENABLE_WAIT_US);
+ ret = tpmi_read_pm_config(id, &cp_state, &cp_cap);
+ debug_printf("ret:%d cp_state:%d enable_clos:%d\n", ret,
+ cp_state, enable_clos);
+ if (ret || cp_state == enable_clos)
+ break;
+ }
+ if (j == FEATURE_ENABLE_RETRIES) {
+ id->punit = saved_punit;
+ return -1;
+ }
}
}
diff --git a/tools/testing/selftests/futex/functional/.gitignore b/tools/testing/selftests/futex/functional/.gitignore
index 776ad658f75e..23b9fea8d190 100644
--- a/tools/testing/selftests/futex/functional/.gitignore
+++ b/tools/testing/selftests/futex/functional/.gitignore
@@ -12,3 +12,4 @@ futex_wait_uninitialized_heap
futex_wait_wouldblock
futex_waitv
futex_numa
+robust_list
diff --git a/tools/testing/selftests/futex/functional/Makefile b/tools/testing/selftests/futex/functional/Makefile
index 490ace1f017e..af7ec309ea78 100644
--- a/tools/testing/selftests/futex/functional/Makefile
+++ b/tools/testing/selftests/futex/functional/Makefile
@@ -22,7 +22,8 @@ TEST_GEN_PROGS := \
futex_priv_hash \
futex_numa_mpol \
futex_waitv \
- futex_numa
+ futex_numa \
+ robust_list
TEST_PROGS := run.sh
diff --git a/tools/testing/selftests/futex/functional/futex_numa_mpol.c b/tools/testing/selftests/futex/functional/futex_numa_mpol.c
index ab8555752137..220ef219c823 100644
--- a/tools/testing/selftests/futex/functional/futex_numa_mpol.c
+++ b/tools/testing/selftests/futex/functional/futex_numa_mpol.c
@@ -131,11 +131,6 @@ static void test_futex(void *futex_ptr, int err_value)
__test_futex(futex_ptr, err_value, FUTEX2_SIZE_U32 | FUTEX_PRIVATE_FLAG | FUTEX2_NUMA);
}
-static void test_futex_mpol(void *futex_ptr, int err_value)
-{
- __test_futex(futex_ptr, err_value, FUTEX2_SIZE_U32 | FUTEX_PRIVATE_FLAG | FUTEX2_NUMA | FUTEX2_MPOL);
-}
-
TEST(futex_numa_mpol)
{
struct futex32_numa *futex_numa;
diff --git a/tools/testing/selftests/futex/functional/futex_wait.c b/tools/testing/selftests/futex/functional/futex_wait.c
index 0e69c53524c1..7b8879409007 100644
--- a/tools/testing/selftests/futex/functional/futex_wait.c
+++ b/tools/testing/selftests/futex/functional/futex_wait.c
@@ -71,6 +71,8 @@ TEST(anon_page)
/* Testing an anon page shared memory */
shm_id = shmget(IPC_PRIVATE, 4096, IPC_CREAT | 0666);
if (shm_id < 0) {
+ if (errno == ENOSYS)
+ ksft_exit_skip("shmget syscall not supported\n");
perror("shmget");
exit(1);
}
@@ -108,14 +110,14 @@ TEST(file_backed)
/* Testing a file backed shared memory */
fd = open(SHM_PATH, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
if (fd < 0)
- ksft_exit_fail_msg("open");
+ ksft_exit_fail_msg("open\n");
if (ftruncate(fd, sizeof(f_private)))
- ksft_exit_fail_msg("ftruncate");
+ ksft_exit_fail_msg("ftruncate\n");
shm = mmap(NULL, sizeof(f_private), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (shm == MAP_FAILED)
- ksft_exit_fail_msg("mmap");
+ ksft_exit_fail_msg("mmap\n");
memcpy(shm, &f_private, sizeof(f_private));
diff --git a/tools/testing/selftests/futex/functional/futex_waitv.c b/tools/testing/selftests/futex/functional/futex_waitv.c
index d60876164d4b..b5ada9fdb26f 100644
--- a/tools/testing/selftests/futex/functional/futex_waitv.c
+++ b/tools/testing/selftests/futex/functional/futex_waitv.c
@@ -86,6 +86,8 @@ TEST(shared_waitv)
int shm_id = shmget(IPC_PRIVATE, 4096, IPC_CREAT | 0666);
if (shm_id < 0) {
+ if (errno == ENOSYS)
+ ksft_exit_skip("shmget syscall not supported\n");
perror("shmget");
exit(1);
}
diff --git a/tools/testing/selftests/futex/functional/robust_list.c b/tools/testing/selftests/futex/functional/robust_list.c
new file mode 100644
index 000000000000..e7d1254e18ca
--- /dev/null
+++ b/tools/testing/selftests/futex/functional/robust_list.c
@@ -0,0 +1,552 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2025 Igalia S.L.
+ *
+ * Robust list test by André Almeida <andrealmeid@igalia.com>
+ *
+ * The robust list uAPI allows userspace to create "robust" locks, in the sense
+ * that if the lock holder thread dies, the remaining threads that are waiting
+ * for the lock won't block forever, waiting for a lock that will never be
+ * released.
+ *
+ * This is achieve by userspace setting a list where a thread can enter all the
+ * locks (futexes) that it is holding. The robust list is a linked list, and
+ * userspace register the start of the list with the syscall set_robust_list().
+ * If such thread eventually dies, the kernel will walk this list, waking up one
+ * thread waiting for each futex and marking the futex word with the flag
+ * FUTEX_OWNER_DIED.
+ *
+ * See also
+ * man set_robust_list
+ * Documententation/locking/robust-futex-ABI.rst
+ * Documententation/locking/robust-futexes.rst
+ */
+
+#define _GNU_SOURCE
+
+#include "futextest.h"
+#include "../../kselftest_harness.h"
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdatomic.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+
+#define STACK_SIZE (1024 * 1024)
+
+#define FUTEX_TIMEOUT 3
+
+#define SLEEP_US 100
+
+static pthread_barrier_t barrier, barrier2;
+
+static int set_robust_list(struct robust_list_head *head, size_t len)
+{
+ return syscall(SYS_set_robust_list, head, len);
+}
+
+static int get_robust_list(int pid, struct robust_list_head **head, size_t *len_ptr)
+{
+ return syscall(SYS_get_robust_list, pid, head, len_ptr);
+}
+
+/*
+ * Basic lock struct, contains just the futex word and the robust list element
+ * Real implementations have also a *prev to easily walk in the list
+ */
+struct lock_struct {
+ _Atomic(unsigned int) futex;
+ struct robust_list list;
+};
+
+/*
+ * Helper function to spawn a child thread. Returns -1 on error, pid on success
+ */
+static int create_child(int (*fn)(void *arg), void *arg)
+{
+ char *stack;
+ pid_t pid;
+
+ stack = mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
+ if (stack == MAP_FAILED)
+ return -1;
+
+ stack += STACK_SIZE;
+
+ pid = clone(fn, stack, CLONE_VM | SIGCHLD, arg);
+
+ if (pid == -1)
+ return -1;
+
+ return pid;
+}
+
+/*
+ * Helper function to prepare and register a robust list
+ */
+static int set_list(struct robust_list_head *head)
+{
+ int ret;
+
+ ret = set_robust_list(head, sizeof(*head));
+ if (ret)
+ return ret;
+
+ head->futex_offset = (size_t) offsetof(struct lock_struct, futex) -
+ (size_t) offsetof(struct lock_struct, list);
+ head->list.next = &head->list;
+ head->list_op_pending = NULL;
+
+ return 0;
+}
+
+/*
+ * A basic (and incomplete) mutex lock function with robustness
+ */
+static int mutex_lock(struct lock_struct *lock, struct robust_list_head *head, bool error_inject)
+{
+ _Atomic(unsigned int) *futex = &lock->futex;
+ unsigned int zero = 0;
+ pid_t tid = gettid();
+ int ret = -1;
+
+ /*
+ * Set list_op_pending before starting the lock, so the kernel can catch
+ * the case where the thread died during the lock operation
+ */
+ head->list_op_pending = &lock->list;
+
+ if (atomic_compare_exchange_strong(futex, &zero, tid)) {
+ /*
+ * We took the lock, insert it in the robust list
+ */
+ struct robust_list *list = &head->list;
+
+ /* Error injection to test list_op_pending */
+ if (error_inject)
+ return 0;
+
+ while (list->next != &head->list)
+ list = list->next;
+
+ list->next = &lock->list;
+ lock->list.next = &head->list;
+
+ ret = 0;
+ } else {
+ /*
+ * We didn't take the lock, wait until the owner wakes (or dies)
+ */
+ struct timespec to;
+
+ to.tv_sec = FUTEX_TIMEOUT;
+ to.tv_nsec = 0;
+
+ tid = atomic_load(futex);
+ /* Kernel ignores futexes without the waiters flag */
+ tid |= FUTEX_WAITERS;
+ atomic_store(futex, tid);
+
+ ret = futex_wait((futex_t *) futex, tid, &to, 0);
+
+ /*
+ * A real mutex_lock() implementation would loop here to finally
+ * take the lock. We don't care about that, so we stop here.
+ */
+ }
+
+ head->list_op_pending = NULL;
+
+ return ret;
+}
+
+/*
+ * This child thread will succeed taking the lock, and then will exit holding it
+ */
+static int child_fn_lock(void *arg)
+{
+ struct lock_struct *lock = arg;
+ struct robust_list_head head;
+ int ret;
+
+ ret = set_list(&head);
+ if (ret) {
+ ksft_test_result_fail("set_robust_list error\n");
+ return ret;
+ }
+
+ ret = mutex_lock(lock, &head, false);
+ if (ret) {
+ ksft_test_result_fail("mutex_lock error\n");
+ return ret;
+ }
+
+ pthread_barrier_wait(&barrier);
+
+ /*
+ * There's a race here: the parent thread needs to be inside
+ * futex_wait() before the child thread dies, otherwise it will miss the
+ * wakeup from handle_futex_death() that this child will emit. We wait a
+ * little bit just to make sure that this happens.
+ */
+ usleep(SLEEP_US);
+
+ return 0;
+}
+
+/*
+ * Spawns a child thread that will set a robust list, take the lock, register it
+ * in the robust list and die. The parent thread will wait on this futex, and
+ * should be waken up when the child exits.
+ */
+TEST(test_robustness)
+{
+ struct lock_struct lock = { .futex = 0 };
+ _Atomic(unsigned int) *futex = &lock.futex;
+ struct robust_list_head head;
+ int ret, pid, wstatus;
+
+ ret = set_list(&head);
+ ASSERT_EQ(ret, 0);
+
+ /*
+ * Lets use a barrier to ensure that the child thread takes the lock
+ * before the parent
+ */
+ ret = pthread_barrier_init(&barrier, NULL, 2);
+ ASSERT_EQ(ret, 0);
+
+ pid = create_child(&child_fn_lock, &lock);
+ ASSERT_NE(pid, -1);
+
+ pthread_barrier_wait(&barrier);
+ ret = mutex_lock(&lock, &head, false);
+
+ /*
+ * futex_wait() should return 0 and the futex word should be marked with
+ * FUTEX_OWNER_DIED
+ */
+ ASSERT_EQ(ret, 0);
+
+ ASSERT_TRUE(*futex & FUTEX_OWNER_DIED);
+
+ wait(&wstatus);
+ pthread_barrier_destroy(&barrier);
+
+ /* Pass only if the child hasn't return error */
+ if (!WEXITSTATUS(wstatus))
+ ksft_test_result_pass("%s\n", __func__);
+}
+
+/*
+ * The only valid value for len is sizeof(*head)
+ */
+TEST(test_set_robust_list_invalid_size)
+{
+ struct robust_list_head head;
+ size_t head_size = sizeof(head);
+ int ret;
+
+ ret = set_robust_list(&head, head_size);
+ ASSERT_EQ(ret, 0);
+
+ ret = set_robust_list(&head, head_size * 2);
+ ASSERT_EQ(ret, -1);
+ ASSERT_EQ(errno, EINVAL);
+
+ ret = set_robust_list(&head, head_size - 1);
+ ASSERT_EQ(ret, -1);
+ ASSERT_EQ(errno, EINVAL);
+
+ ret = set_robust_list(&head, 0);
+ ASSERT_EQ(ret, -1);
+ ASSERT_EQ(errno, EINVAL);
+
+ ksft_test_result_pass("%s\n", __func__);
+}
+
+/*
+ * Test get_robust_list with pid = 0, getting the list of the running thread
+ */
+TEST(test_get_robust_list_self)
+{
+ struct robust_list_head head, head2, *get_head;
+ size_t head_size = sizeof(head), len_ptr;
+ int ret;
+
+ ret = set_robust_list(&head, head_size);
+ ASSERT_EQ(ret, 0);
+
+ ret = get_robust_list(0, &get_head, &len_ptr);
+ ASSERT_EQ(ret, 0);
+ ASSERT_EQ(get_head, &head);
+ ASSERT_EQ(head_size, len_ptr);
+
+ ret = set_robust_list(&head2, head_size);
+ ASSERT_EQ(ret, 0);
+
+ ret = get_robust_list(0, &get_head, &len_ptr);
+ ASSERT_EQ(ret, 0);
+ ASSERT_EQ(get_head, &head2);
+ ASSERT_EQ(head_size, len_ptr);
+
+ ksft_test_result_pass("%s\n", __func__);
+}
+
+static int child_list(void *arg)
+{
+ struct robust_list_head *head = arg;
+ int ret;
+
+ ret = set_robust_list(head, sizeof(*head));
+ if (ret) {
+ ksft_test_result_fail("set_robust_list error\n");
+ return -1;
+ }
+
+ /*
+ * After setting the list head, wait until the main thread can call
+ * get_robust_list() for this thread before exiting.
+ */
+ pthread_barrier_wait(&barrier);
+ pthread_barrier_wait(&barrier2);
+
+ return 0;
+}
+
+/*
+ * Test get_robust_list from another thread. We use two barriers here to ensure
+ * that:
+ * 1) the child thread set the list before we try to get it from the
+ * parent
+ * 2) the child thread still alive when we try to get the list from it
+ */
+TEST(test_get_robust_list_child)
+{
+ struct robust_list_head head, *get_head;
+ int ret, wstatus;
+ size_t len_ptr;
+ pid_t tid;
+
+ ret = pthread_barrier_init(&barrier, NULL, 2);
+ ret = pthread_barrier_init(&barrier2, NULL, 2);
+ ASSERT_EQ(ret, 0);
+
+ tid = create_child(&child_list, &head);
+ ASSERT_NE(tid, -1);
+
+ pthread_barrier_wait(&barrier);
+
+ ret = get_robust_list(tid, &get_head, &len_ptr);
+ ASSERT_EQ(ret, 0);
+ ASSERT_EQ(&head, get_head);
+
+ pthread_barrier_wait(&barrier2);
+
+ wait(&wstatus);
+ pthread_barrier_destroy(&barrier);
+ pthread_barrier_destroy(&barrier2);
+
+ /* Pass only if the child hasn't return error */
+ if (!WEXITSTATUS(wstatus))
+ ksft_test_result_pass("%s\n", __func__);
+}
+
+static int child_fn_lock_with_error(void *arg)
+{
+ struct lock_struct *lock = arg;
+ struct robust_list_head head;
+ int ret;
+
+ ret = set_list(&head);
+ if (ret) {
+ ksft_test_result_fail("set_robust_list error\n");
+ return -1;
+ }
+
+ ret = mutex_lock(lock, &head, true);
+ if (ret) {
+ ksft_test_result_fail("mutex_lock error\n");
+ return -1;
+ }
+
+ pthread_barrier_wait(&barrier);
+
+ /* See comment at child_fn_lock() */
+ usleep(SLEEP_US);
+
+ return 0;
+}
+
+/*
+ * Same as robustness test, but inject an error where the mutex_lock() exits
+ * earlier, just after setting list_op_pending and taking the lock, to test the
+ * list_op_pending mechanism
+ */
+TEST(test_set_list_op_pending)
+{
+ struct lock_struct lock = { .futex = 0 };
+ _Atomic(unsigned int) *futex = &lock.futex;
+ struct robust_list_head head;
+ int ret, wstatus;
+
+ ret = set_list(&head);
+ ASSERT_EQ(ret, 0);
+
+ ret = pthread_barrier_init(&barrier, NULL, 2);
+ ASSERT_EQ(ret, 0);
+
+ ret = create_child(&child_fn_lock_with_error, &lock);
+ ASSERT_NE(ret, -1);
+
+ pthread_barrier_wait(&barrier);
+ ret = mutex_lock(&lock, &head, false);
+
+ ASSERT_EQ(ret, 0);
+
+ ASSERT_TRUE(*futex & FUTEX_OWNER_DIED);
+
+ wait(&wstatus);
+ pthread_barrier_destroy(&barrier);
+
+ /* Pass only if the child hasn't return error */
+ if (!WEXITSTATUS(wstatus))
+ ksft_test_result_pass("%s\n", __func__);
+ else
+ ksft_test_result_fail("%s\n", __func__);
+}
+
+#define CHILD_NR 10
+
+static int child_lock_holder(void *arg)
+{
+ struct lock_struct *locks = arg;
+ struct robust_list_head head;
+ int i;
+
+ set_list(&head);
+
+ for (i = 0; i < CHILD_NR; i++) {
+ locks[i].futex = 0;
+ mutex_lock(&locks[i], &head, false);
+ }
+
+ pthread_barrier_wait(&barrier);
+ pthread_barrier_wait(&barrier2);
+
+ /* See comment at child_fn_lock() */
+ usleep(SLEEP_US);
+
+ return 0;
+}
+
+static int child_wait_lock(void *arg)
+{
+ struct lock_struct *lock = arg;
+ struct robust_list_head head;
+ int ret;
+
+ pthread_barrier_wait(&barrier2);
+ ret = mutex_lock(lock, &head, false);
+
+ if (ret) {
+ ksft_test_result_fail("mutex_lock error\n");
+ return -1;
+ }
+
+ if (!(lock->futex & FUTEX_OWNER_DIED)) {
+ ksft_test_result_fail("futex not marked with FUTEX_OWNER_DIED\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Test a robust list of more than one element. All the waiters should wake when
+ * the holder dies
+ */
+TEST(test_robust_list_multiple_elements)
+{
+ struct lock_struct locks[CHILD_NR];
+ pid_t pids[CHILD_NR + 1];
+ int i, ret, wstatus;
+
+ ret = pthread_barrier_init(&barrier, NULL, 2);
+ ASSERT_EQ(ret, 0);
+ ret = pthread_barrier_init(&barrier2, NULL, CHILD_NR + 1);
+ ASSERT_EQ(ret, 0);
+
+ pids[0] = create_child(&child_lock_holder, &locks);
+
+ /* Wait until the locker thread takes the look */
+ pthread_barrier_wait(&barrier);
+
+ for (i = 0; i < CHILD_NR; i++)
+ pids[i+1] = create_child(&child_wait_lock, &locks[i]);
+
+ /* Wait for all children to return */
+ ret = 0;
+
+ for (i = 0; i < CHILD_NR; i++) {
+ waitpid(pids[i], &wstatus, 0);
+ if (WEXITSTATUS(wstatus))
+ ret = -1;
+ }
+
+ pthread_barrier_destroy(&barrier);
+ pthread_barrier_destroy(&barrier2);
+
+ /* Pass only if the child hasn't return error */
+ if (!ret)
+ ksft_test_result_pass("%s\n", __func__);
+}
+
+static int child_circular_list(void *arg)
+{
+ static struct robust_list_head head;
+ struct lock_struct a, b, c;
+ int ret;
+
+ ret = set_list(&head);
+ if (ret) {
+ ksft_test_result_fail("set_list error\n");
+ return -1;
+ }
+
+ head.list.next = &a.list;
+
+ /*
+ * The last element should point to head list, but we short circuit it
+ */
+ a.list.next = &b.list;
+ b.list.next = &c.list;
+ c.list.next = &a.list;
+
+ return 0;
+}
+
+/*
+ * Create a circular robust list. The kernel should be able to destroy the list
+ * while processing it so it won't be trapped in an infinite loop while handling
+ * a process exit
+ */
+TEST(test_circular_list)
+{
+ int wstatus;
+
+ create_child(child_circular_list, NULL);
+
+ wait(&wstatus);
+
+ /* Pass only if the child hasn't return error */
+ if (!WEXITSTATUS(wstatus))
+ ksft_test_result_pass("%s\n", __func__);
+}
+
+TEST_HARNESS_MAIN