summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.mailmap2
-rw-r--r--Documentation/ABI/testing/sysfs-bus-iio1
-rw-r--r--Documentation/ABI/testing/sysfs-bus-usb2
-rw-r--r--Documentation/accounting/delay-accounting.rst6
-rw-r--r--Documentation/admin-guide/laptops/thinkpad-acpi.rst24
-rw-r--r--Documentation/admin-guide/media/em28xx-cardlist.rst4
-rw-r--r--Documentation/admin-guide/mm/pagemap.rst13
-rw-r--r--Documentation/admin-guide/mm/userfaultfd.rst269
-rw-r--r--Documentation/admin-guide/sysctl/vm.rst3
-rw-r--r--Documentation/bpf/index.rst1
-rw-r--r--Documentation/bpf/signing.rst497
-rw-r--r--Documentation/core-api/mm-api.rst2
-rw-r--r--Documentation/core-api/workqueue.rst2
-rw-r--r--Documentation/devicetree/bindings/arm/qcom.yaml26
-rw-r--r--Documentation/devicetree/bindings/cache/qcom,llcc.yaml63
-rw-r--r--Documentation/devicetree/bindings/clock/qcom,rpmcc.yaml65
-rw-r--r--Documentation/devicetree/bindings/clock/qcom,shikra-gcc.yaml70
-rw-r--r--Documentation/devicetree/bindings/firmware/qcom,scm.yaml2
-rw-r--r--Documentation/devicetree/bindings/iio/adc/mediatek,mt6359-auxadc.yaml3
-rw-r--r--Documentation/devicetree/bindings/iio/adc/xlnx,versal-sysmon.yaml154
-rw-r--r--Documentation/devicetree/bindings/iio/chemical/sensirion,scd30.yaml1
-rw-r--r--Documentation/devicetree/bindings/iio/dac/adi,ad3530r.yaml16
-rw-r--r--Documentation/devicetree/bindings/leds/backlight/awinic,aw99706.yaml2
-rw-r--r--Documentation/devicetree/bindings/leds/backlight/silergy,sy7758.yaml52
-rw-r--r--Documentation/devicetree/bindings/mfd/mediatek,mt8195-scpsys.yaml1
-rw-r--r--Documentation/devicetree/bindings/pci/qcom,hawi-pcie.yaml7
-rw-r--r--Documentation/devicetree/bindings/serial/maxim,max310x.yaml92
-rw-r--r--Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml1
-rw-r--r--Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml1
-rw-r--r--Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml27
-rw-r--r--Documentation/devicetree/bindings/sound/dmic-codec.yaml4
-rw-r--r--Documentation/devicetree/bindings/sound/fsl,micfil.yaml4
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml1
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,lpass-tx-macro.yaml1
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml1
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml1
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,sm8250.yaml1
-rw-r--r--Documentation/devicetree/bindings/sound/wlf,wm8524.yaml4
-rw-r--r--Documentation/devicetree/bindings/sram/sram.yaml1
-rw-r--r--Documentation/devicetree/bindings/usb/qcom,snps-dwc3.yaml3
-rw-r--r--Documentation/devicetree/bindings/usb/renesas,usbhs.yaml1
-rw-r--r--Documentation/devicetree/bindings/vendor-prefixes.yaml2
-rw-r--r--Documentation/devicetree/bindings/watchdog/apple,wdt.yaml1
-rw-r--r--Documentation/driver-api/media/maintainer-entry-profile.rst4
-rw-r--r--Documentation/filesystems/proc.rst1
-rw-r--r--Documentation/gpu/intel-display/dp-link-capabilities.rst11
-rw-r--r--Documentation/gpu/intel-display/index.rst1
-rw-r--r--Documentation/leds/leds-st1202.rst9
-rw-r--r--Documentation/mm/page_owner.rst7
-rw-r--r--Documentation/sphinx-static/custom.css9
-rw-r--r--MAINTAINERS53
-rw-r--r--Makefile5
-rw-r--r--Next/SHA1s429
-rw-r--r--Next/Trees429
-rw-r--r--Next/merge.log7942
-rw-r--r--arch/arm/boot/dts/qcom/Makefile1
-rw-r--r--arch/arm/boot/dts/qcom/msm8226-motorola-titan.dts350
-rw-r--r--arch/arm/boot/dts/qcom/qcom-apq8064-pins.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/qcom-ipq8064.dtsi4
-rw-r--r--arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/qcom-msm8960-samsung-expressatt.dts54
-rw-r--r--arch/arm/boot/dts/qcom/qcom-msm8974.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/qcom-sdx65-mtp.dts2
-rw-r--r--arch/arm/mach-ux500/cpu-db8500.c6
-rw-r--r--arch/arm64/Kconfig1
-rw-r--r--arch/arm64/boot/dts/mediatek/mt6795.dtsi4
-rw-r--r--arch/arm64/boot/dts/mediatek/mt8183.dtsi22
-rw-r--r--arch/arm64/boot/dts/mediatek/mt8186.dtsi22
-rw-r--r--arch/arm64/boot/dts/mediatek/mt8188.dtsi33
-rw-r--r--arch/arm64/boot/dts/mediatek/mt8192.dtsi17
-rw-r--r--arch/arm64/boot/dts/mediatek/mt8195.dtsi37
-rw-r--r--arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtsi4
-rw-r--r--arch/arm64/boot/dts/qcom/Makefile9
-rw-r--r--arch/arm64/boot/dts/qcom/apq8016-sbc-usb-host.dtso2
-rw-r--r--arch/arm64/boot/dts/qcom/eliza-cqs-evk.dts14
-rw-r--r--arch/arm64/boot/dts/qcom/eliza-cqs-som.dtsi399
-rw-r--r--arch/arm64/boot/dts/qcom/eliza-evk.dtsi20
-rw-r--r--arch/arm64/boot/dts/qcom/eliza-mtp.dts5
-rw-r--r--arch/arm64/boot/dts/qcom/eliza.dtsi100
-rw-r--r--arch/arm64/boot/dts/qcom/glymur.dtsi28
-rw-r--r--arch/arm64/boot/dts/qcom/hamoa.dtsi19
-rw-r--r--arch/arm64/boot/dts/qcom/ipq5332-rdp441.dts16
-rw-r--r--arch/arm64/boot/dts/qcom/ipq5332.dtsi14
-rw-r--r--arch/arm64/boot/dts/qcom/ipq5424-rdp466.dts12
-rw-r--r--arch/arm64/boot/dts/qcom/ipq5424.dtsi24
-rw-r--r--arch/arm64/boot/dts/qcom/ipq9574.dtsi24
-rw-r--r--arch/arm64/boot/dts/qcom/kaanapali.dtsi539
-rw-r--r--arch/arm64/boot/dts/qcom/kodiak.dtsi21
-rw-r--r--arch/arm64/boot/dts/qcom/lemans-evk-camera.dtso2
-rw-r--r--arch/arm64/boot/dts/qcom/lemans-evk.dts75
-rw-r--r--arch/arm64/boot/dts/qcom/lemans-ride-common.dtsi4
-rw-r--r--arch/arm64/boot/dts/qcom/lemans.dtsi41
-rw-r--r--arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts20
-rw-r--r--arch/arm64/boot/dts/qcom/milos-nothing-asteroids.dts38
-rw-r--r--arch/arm64/boot/dts/qcom/milos.dtsi2
-rw-r--r--arch/arm64/boot/dts/qcom/monaco-arduino-monza.dts44
-rw-r--r--arch/arm64/boot/dts/qcom/monaco.dtsi40
-rw-r--r--arch/arm64/boot/dts/qcom/msm8996-xiaomi-gemini.dts2
-rw-r--r--arch/arm64/boot/dts/qcom/msm8996.dtsi41
-rw-r--r--arch/arm64/boot/dts/qcom/pm7550-eliza.dtsi61
-rw-r--r--arch/arm64/boot/dts/qcom/pm8550vs-d-eliza.dtsi63
-rw-r--r--arch/arm64/boot/dts/qcom/pm8550vs-g-eliza.dtsi63
-rw-r--r--arch/arm64/boot/dts/qcom/pmk8550-eliza.dtsi87
-rw-r--r--arch/arm64/boot/dts/qcom/pmr735d-eliza.dtsi63
-rw-r--r--arch/arm64/boot/dts/qcom/purwa.dtsi10
-rw-r--r--arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts61
-rw-r--r--arch/arm64/boot/dts/qcom/qcm6490-particle-tachyon.dts14
-rw-r--r--arch/arm64/boot/dts/qcom/qcm6490-shift-otter.dts4
-rw-r--r--arch/arm64/boot/dts/qcom/qcs615-ride.dts6
-rw-r--r--arch/arm64/boot/dts/qcom/qcs6490-radxa-dragon-q6a.dts16
-rw-r--r--arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts4
-rw-r--r--arch/arm64/boot/dts/qcom/qcs6490-thundercomm-minipc-g1iot.dts14
-rw-r--r--arch/arm64/boot/dts/qcom/qcs6490-thundercomm-rubikpi3.dts16
-rw-r--r--arch/arm64/boot/dts/qcom/qdu1000.dtsi2
-rw-r--r--arch/arm64/boot/dts/qcom/qrb2210-rb1-vision-mezzanine.dtso4
-rw-r--r--arch/arm64/boot/dts/qcom/qrb4210-rb2.dts6
-rw-r--r--arch/arm64/boot/dts/qcom/sar2130p.dtsi2
-rw-r--r--arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi5
-rw-r--r--arch/arm64/boot/dts/qcom/sc7180.dtsi2
-rw-r--r--arch/arm64/boot/dts/qcom/sc7280-herobrine.dtsi5
-rw-r--r--arch/arm64/boot/dts/qcom/sc7280-idp.dtsi5
-rw-r--r--arch/arm64/boot/dts/qcom/sc8180x-lenovo-flex-5g.dts57
-rw-r--r--arch/arm64/boot/dts/qcom/sc8180x-primus.dts56
-rw-r--r--arch/arm64/boot/dts/qcom/sc8180x.dtsi2
-rw-r--r--arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts10
-rw-r--r--arch/arm64/boot/dts/qcom/sc8280xp-microsoft-arcata.dts279
-rw-r--r--arch/arm64/boot/dts/qcom/sc8280xp.dtsi58
-rw-r--r--arch/arm64/boot/dts/qcom/sdm670-google-common.dtsi5
-rw-r--r--arch/arm64/boot/dts/qcom/sdm670.dtsi2
-rw-r--r--arch/arm64/boot/dts/qcom/sdm845-google-common.dtsi8
-rw-r--r--arch/arm64/boot/dts/qcom/sdm845.dtsi2
-rw-r--r--arch/arm64/boot/dts/qcom/sdx75.dtsi2
-rw-r--r--arch/arm64/boot/dts/qcom/shikra-cqm-evk.dts40
-rw-r--r--arch/arm64/boot/dts/qcom/shikra-cqm-som.dtsi156
-rw-r--r--arch/arm64/boot/dts/qcom/shikra-cqs-evk.dts40
-rw-r--r--arch/arm64/boot/dts/qcom/shikra-evk.dtsi14
-rw-r--r--arch/arm64/boot/dts/qcom/shikra-iqs-evk.dts40
-rw-r--r--arch/arm64/boot/dts/qcom/shikra-iqs-som.dtsi170
-rw-r--r--arch/arm64/boot/dts/qcom/shikra.dtsi842
-rw-r--r--arch/arm64/boot/dts/qcom/sm4450.dtsi2
-rw-r--r--arch/arm64/boot/dts/qcom/sm6115.dtsi65
-rw-r--r--arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo-common.dtsi8
-rw-r--r--arch/arm64/boot/dts/qcom/sm6125-xiaomi-laurel-sprout.dts2
-rw-r--r--arch/arm64/boot/dts/qcom/sm6350.dtsi2
-rw-r--r--arch/arm64/boot/dts/qcom/sm7325-xiaomi-taoyao.dts913
-rw-r--r--arch/arm64/boot/dts/qcom/sm8150.dtsi2
-rw-r--r--arch/arm64/boot/dts/qcom/sm8250.dtsi14
-rw-r--r--arch/arm64/boot/dts/qcom/sm8350.dtsi2
-rw-r--r--arch/arm64/boot/dts/qcom/sm8450.dtsi2
-rw-r--r--arch/arm64/boot/dts/qcom/sm8550.dtsi2
-rw-r--r--arch/arm64/boot/dts/qcom/sm8650.dtsi112
-rw-r--r--arch/arm64/boot/dts/qcom/sm8750.dtsi44
-rw-r--r--arch/arm64/boot/dts/qcom/talos-evk-som.dtsi8
-rw-r--r--arch/arm64/boot/dts/qcom/talos.dtsi79
-rw-r--r--arch/arm64/boot/dts/qcom/x1e80100-honor-magicbook-art-14.dts1341
-rw-r--r--arch/arm64/boot/dts/qcom/x1p42100-microsoft-sp12in.dts1194
-rw-r--r--arch/arm64/configs/defconfig1
-rw-r--r--arch/arm64/include/asm/pgtable-prot.h8
-rw-r--r--arch/arm64/include/asm/pgtable.h47
-rw-r--r--arch/loongarch/Kconfig1
-rw-r--r--arch/loongarch/include/asm/pgtable.h4
-rw-r--r--arch/m68k/coldfire/m523x.c2
-rw-r--r--arch/m68k/coldfire/m528x.c6
-rw-r--r--arch/m68k/configs/m5235evb_defconfig52
-rw-r--r--arch/m68k/configs/m5282evb_defconfig51
-rw-r--r--arch/powerpc/include/asm/book3s/64/pgtable.h8
-rw-r--r--arch/powerpc/platforms/Kconfig.cputype1
-rw-r--r--arch/riscv/Kconfig2
-rw-r--r--arch/riscv/Kconfig.socs6
-rw-r--r--arch/riscv/configs/defconfig1
-rw-r--r--arch/riscv/include/asm/acpi.h3
-rw-r--r--arch/riscv/include/asm/pgtable-bits.h12
-rw-r--r--arch/riscv/include/asm/pgtable.h59
-rw-r--r--arch/riscv/kernel/acpi.c5
-rw-r--r--arch/riscv/kernel/efi.c5
-rw-r--r--arch/riscv/kernel/reset.c7
-rw-r--r--arch/riscv/kernel/setup.c2
-rw-r--r--arch/s390/Kconfig6
-rw-r--r--arch/s390/configs/debug_defconfig2
-rw-r--r--arch/s390/configs/defconfig2
-rw-r--r--arch/s390/include/asm/hugetlb.h16
-rw-r--r--arch/s390/include/asm/pgtable.h4
-rw-r--r--arch/s390/include/asm/processor.h4
-rw-r--r--arch/s390/include/asm/thread_info.h1
-rw-r--r--arch/s390/kernel/diag/diag310.c7
-rw-r--r--arch/s390/kernel/idle.c1
-rw-r--r--arch/s390/kernel/irq.c4
-rw-r--r--arch/s390/kernel/smp.c1
-rw-r--r--arch/s390/kernel/traps.c41
-rw-r--r--arch/s390/kernel/vdso/note.S3
-rw-r--r--arch/s390/kvm/dat.c2
-rw-r--r--arch/s390/kvm/gmap.c7
-rw-r--r--arch/s390/kvm/kvm-s390.c6
-rw-r--r--arch/s390/kvm/pci.c11
-rw-r--r--arch/s390/mm/hugetlbpage.c10
-rw-r--r--arch/s390/mm/mmap.c2
-rw-r--r--arch/x86/Kconfig1
-rw-r--r--arch/x86/boot/compressed/head_64.S18
-rw-r--r--arch/x86/events/amd/core.c12
-rw-r--r--arch/x86/include/asm/kvm-x86-nested-ops.h36
-rw-r--r--arch/x86/include/asm/kvm_host.h206
-rw-r--r--arch/x86/include/asm/pgtable.h56
-rw-r--r--arch/x86/include/asm/pgtable_types.h16
-rw-r--r--arch/x86/kernel/vmlinux.lds.S6
-rw-r--r--arch/x86/kvm/cpuid.c12
-rw-r--r--arch/x86/kvm/emulate.c49
-rw-r--r--arch/x86/kvm/hyperv.c70
-rw-r--r--arch/x86/kvm/hyperv.h117
-rw-r--r--arch/x86/kvm/irq.c4
-rw-r--r--arch/x86/kvm/lapic.c18
-rw-r--r--arch/x86/kvm/lapic.h33
-rw-r--r--arch/x86/kvm/mmu.h11
-rw-r--r--arch/x86/kvm/mmu/mmu.c2
-rw-r--r--arch/x86/kvm/mmu/paging_tmpl.h2
-rw-r--r--arch/x86/kvm/msrs.h4
-rw-r--r--arch/x86/kvm/regs.h38
-rw-r--r--arch/x86/kvm/svm/avic.c84
-rw-r--r--arch/x86/kvm/svm/nested.c3
-rw-r--r--arch/x86/kvm/svm/sev.c17
-rw-r--r--arch/x86/kvm/svm/svm.c20
-rw-r--r--arch/x86/kvm/svm/svm.h4
-rw-r--r--arch/x86/kvm/tss.h7
-rw-r--r--arch/x86/kvm/vmx/main.c3
-rw-r--r--arch/x86/kvm/vmx/nested.c151
-rw-r--r--arch/x86/kvm/vmx/nested.h6
-rw-r--r--arch/x86/kvm/vmx/tdx.c7
-rw-r--r--arch/x86/kvm/vmx/vmx.c20
-rw-r--r--arch/x86/kvm/vmx/vmx.h7
-rw-r--r--arch/x86/kvm/x86.c75
-rw-r--r--arch/x86/kvm/x86.h8
-rw-r--r--arch/x86/kvm/xen.c43
-rw-r--r--arch/x86/platform/efi/quirks.c9
-rw-r--r--arch/x86/platform/olpc/olpc-xo15-sci.c5
-rw-r--r--arch/xtensa/platforms/iss/simdisk.c38
-rw-r--r--drivers/acpi/arm64/iort.c22
-rw-r--r--drivers/acpi/irq.c172
-rw-r--r--drivers/acpi/riscv/irq.c141
-rw-r--r--drivers/acpi/scan.c2
-rw-r--r--drivers/acpi/tables.c1
-rw-r--r--drivers/base/power/runtime.c6
-rw-r--r--drivers/block/xen-blkfront.c9
-rw-r--r--drivers/bluetooth/btintel_pcie.c180
-rw-r--r--drivers/bluetooth/btintel_pcie.h12
-rw-r--r--drivers/bus/mhi/ep/main.c15
-rw-r--r--drivers/bus/mhi/host/main.c6
-rw-r--r--drivers/bus/mhi/host/pm.c14
-rw-r--r--drivers/bus/qcom-ebi2.c10
-rw-r--r--drivers/char/sonypi.c2
-rw-r--r--drivers/clk/qcom/Kconfig10
-rw-r--r--drivers/clk/qcom/Makefile1
-rw-r--r--drivers/clk/qcom/clk-regmap-phy-mux.c52
-rw-r--r--drivers/clk/qcom/clk-smd-rpm.c5
-rw-r--r--drivers/clk/qcom/gcc-ipq5424.c11
-rw-r--r--drivers/clk/qcom/gcc-qcs8300.c8
-rw-r--r--drivers/clk/qcom/gcc-shikra.c4431
-rw-r--r--drivers/clk/qcom/gcc-sm6115.c1
-rw-r--r--drivers/clk/qcom/gdsc.c25
-rw-r--r--drivers/clk/ux500/clk-prcmu.c20
-rw-r--r--drivers/clk/ux500/u8500_of_clk.c2
-rw-r--r--drivers/cpufreq/cpufreq.c3
-rw-r--r--drivers/cpufreq/intel_pstate.c6
-rw-r--r--drivers/cpuidle/Kconfig5
-rw-r--r--drivers/cpuidle/Kconfig.s39011
-rw-r--r--drivers/cpuidle/Makefile4
-rw-r--r--drivers/cpuidle/cpuidle-s390.c115
-rw-r--r--drivers/cpuidle/cpuidle-ux500.c6
-rw-r--r--drivers/dibs/dibs_loopback.c5
-rw-r--r--drivers/extcon/extcon-adc-jack.c1
-rw-r--r--drivers/firmware/arm_scmi/Kconfig4
-rw-r--r--drivers/firmware/arm_scmi/clock.c11
-rw-r--r--drivers/firmware/arm_scmi/notify.c49
-rw-r--r--drivers/firmware/efi/runtime-wrappers.c68
-rw-r--r--drivers/firmware/qcom/Kconfig22
-rw-r--r--drivers/firmware/qcom/Makefile2
-rw-r--r--drivers/firmware/qcom/qcom_pas.c298
-rw-r--r--drivers/firmware/qcom/qcom_pas.h50
-rw-r--r--drivers/firmware/qcom/qcom_pas_tee.c479
-rw-r--r--drivers/firmware/qcom/qcom_scm.c335
-rw-r--r--drivers/gpio/gpio-mvebu.c1
-rw-r--r--drivers/gpu/buddy.c63
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v11.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12_1.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c8
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cik_sdma.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c9
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c31
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c9
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/si.c4
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_chardev.c5
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_debugfs.c113
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c6
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h2
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_events.c5
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_priv.h7
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_process.c7
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c43
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c28
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c92
-rw-r--r--drivers/gpu/drm/drm_gpusvm.c243
-rw-r--r--drivers/gpu/drm/drm_of.c44
-rw-r--r--drivers/gpu/drm/drm_panel.c44
-rw-r--r--drivers/gpu/drm/i915/.kunitconfig9
-rw-r--r--drivers/gpu/drm/i915/Kconfig.debug12
-rw-r--r--drivers/gpu/drm/i915/Makefile2
-rw-r--r--drivers/gpu/drm/i915/display/intel_audio.c55
-rw-r--r--drivers/gpu/drm/i915/display/intel_display.c9
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_core.h2
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp.c299
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp.h11
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_link_caps.c757
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_link_caps.h172
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_link_training.c225
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_link_training.h31
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_mst.c72
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_test.c107
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_test.h3
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_tunnel.c8
-rw-r--r--drivers/gpu/drm/i915/display/intel_vrr.c6
-rw-r--r--drivers/gpu/drm/i915/display/tests/Makefile7
-rw-r--r--drivers/gpu/drm/i915/display/tests/intel_dp_link_test.c1440
-rw-r--r--drivers/gpu/drm/imagination/pvr_context.c4
-rw-r--r--drivers/gpu/drm/imagination/pvr_fw_trace.c2
-rw-r--r--drivers/gpu/drm/panel/panel-anbernic-td4310.c3
-rw-r--r--drivers/gpu/drm/panel/panel-boe-th101mb31ig002-28a.c3
-rw-r--r--drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c3
-rw-r--r--drivers/gpu/drm/panel/panel-chipone-icna35xx.c3
-rw-r--r--drivers/gpu/drm/panel/panel-chipwealth-ch13726a.c3
-rw-r--r--drivers/gpu/drm/panel/panel-edp.c3
-rw-r--r--drivers/gpu/drm/panel/panel-elida-kd35t133.c3
-rw-r--r--drivers/gpu/drm/panel/panel-focaltech-ota7290b.c3
-rw-r--r--drivers/gpu/drm/panel/panel-himax-hx83102.c3
-rw-r--r--drivers/gpu/drm/panel/panel-himax-hx8394.c3
-rw-r--r--drivers/gpu/drm/panel/panel-ilitek-ili9488.c3
-rw-r--r--drivers/gpu/drm/panel/panel-ilitek-ili9806e-dsi.c3
-rw-r--r--drivers/gpu/drm/panel/panel-ilitek-ili9881c.c3
-rw-r--r--drivers/gpu/drm/panel/panel-ilitek-ili9882t.c3
-rw-r--r--drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c2
-rw-r--r--drivers/gpu/drm/panel/panel-lvds.c2
-rw-r--r--drivers/gpu/drm/panel/panel-novatek-nt36523.c3
-rw-r--r--drivers/gpu/drm/panel/panel-renesas-r63419.c3
-rw-r--r--drivers/gpu/drm/panel/panel-simple.c2
-rw-r--r--drivers/gpu/drm/panel/panel-sitronix-st7701.c3
-rw-r--r--drivers/gpu/drm/panel/panel-sitronix-st7703.c3
-rw-r--r--drivers/gpu/drm/panel/panel-sitronix-st7789v.c3
-rw-r--r--drivers/gpu/drm/panthor/panthor_sched.c1
-rw-r--r--drivers/gpu/drm/sysfb/simpledrm.c11
-rw-r--r--drivers/gpu/drm/v3d/v3d_submit.c125
-rw-r--r--drivers/gpu/drm/xe/.gitignore1
-rw-r--r--drivers/gpu/drm/xe/.kunitconfig-display11
-rw-r--r--drivers/gpu/drm/xe/Makefile3
-rw-r--r--drivers/gpu/drm/xe/abi/guc_actions_abi.h1
-rw-r--r--drivers/gpu/drm/xe/abi/guc_klvs_abi.h10
-rw-r--r--drivers/gpu/drm/xe/display/tests/Makefile13
-rw-r--r--drivers/gpu/drm/xe/xe_gt_types.h5
-rw-r--r--drivers/gpu/drm/xe/xe_guc.c10
-rw-r--r--drivers/gpu/drm/xe/xe_guc_ads.c9
-rw-r--r--drivers/gpu/drm/xe/xe_guc_ct.c43
-rw-r--r--drivers/gpu/drm/xe/xe_guc_engine_activity.c2
-rw-r--r--drivers/gpu/drm/xe/xe_guc_submit.c32
-rw-r--r--drivers/gpu/drm/xe/xe_guc_submit.h1
-rw-r--r--drivers/gpu/drm/xe/xe_pci.c15
-rw-r--r--drivers/gpu/drm/xe/xe_pci_types.h2
-rw-r--r--drivers/gpu/drm/xe/xe_pt.c7
-rw-r--r--drivers/gpu/drm/xe/xe_svm.c66
-rw-r--r--drivers/gpu/drm/xe/xe_svm.h14
-rw-r--r--drivers/gpu/drm/xe/xe_trace.h5
-rw-r--r--drivers/gpu/drm/xe/xe_uc_fw.c1
-rw-r--r--drivers/gpu/drm/xe/xe_userptr.c5
-rw-r--r--drivers/gpu/drm/xe/xe_vm_madvise.c2
-rw-r--r--drivers/gpu/drm/xe/xe_wa_oob.rules5
-rw-r--r--drivers/gpu/nova-core/fsp.rs17
-rw-r--r--drivers/gpu/nova-core/gsp/boot.rs2
-rw-r--r--drivers/gpu/nova-core/gsp/commands.rs76
-rw-r--r--drivers/hwmon/iio_hwmon.c1
-rw-r--r--drivers/hwmon/ntc_thermistor.c1
-rw-r--r--drivers/iio/accel/hid-sensor-accel-3d.c68
-rw-r--r--drivers/iio/adc/Kconfig46
-rw-r--r--drivers/iio/adc/Makefile4
-rw-r--r--drivers/iio/adc/ad7779.c6
-rw-r--r--drivers/iio/adc/ade9000.c2
-rw-r--r--drivers/iio/adc/envelope-detector.c1
-rw-r--r--drivers/iio/adc/max1241.c1
-rw-r--r--drivers/iio/adc/mt6323-auxadc.c314
-rw-r--r--drivers/iio/adc/ti-adc081c.c6
-rw-r--r--drivers/iio/adc/ti-adc084s021.c6
-rw-r--r--drivers/iio/adc/ti-ads1015.c44
-rw-r--r--drivers/iio/adc/versal-sysmon-core.c1052
-rw-r--r--drivers/iio/adc/versal-sysmon-i2c.c134
-rw-r--r--drivers/iio/adc/versal-sysmon.c92
-rw-r--r--drivers/iio/adc/versal-sysmon.h120
-rw-r--r--drivers/iio/afe/iio-rescale.c1
-rw-r--r--drivers/iio/buffer/industrialio-buffer-cb.c1
-rw-r--r--drivers/iio/buffer/industrialio-hw-consumer.c1
-rw-r--r--drivers/iio/chemical/scd30_core.c4
-rw-r--r--drivers/iio/chemical/scd30_i2c.c4
-rw-r--r--drivers/iio/chemical/scd30_serial.c4
-rw-r--r--drivers/iio/chemical/sps30_i2c.c4
-rw-r--r--drivers/iio/chemical/sps30_serial.c4
-rw-r--r--drivers/iio/common/hid-sensors/hid-sensor-attributes.c81
-rw-r--r--drivers/iio/common/hid-sensors/hid-sensor-trigger.c7
-rw-r--r--drivers/iio/common/hid-sensors/hid-sensor-trigger.h2
-rw-r--r--drivers/iio/dac/Kconfig18
-rw-r--r--drivers/iio/dac/Makefile1
-rw-r--r--drivers/iio/dac/ad3530r.c351
-rw-r--r--drivers/iio/dac/ad8460.c1
-rw-r--r--drivers/iio/dac/dpot-dac.c1
-rw-r--r--drivers/iio/dac/mcf54415_dac.c180
-rw-r--r--drivers/iio/gyro/hid-sensor-gyro-3d.c55
-rw-r--r--drivers/iio/humidity/hid-sensor-humidity.c35
-rw-r--r--drivers/iio/imu/adis16480.c4
-rw-r--r--drivers/iio/imu/adis16550.c89
-rw-r--r--drivers/iio/imu/bmi160/bmi160_core.c2
-rw-r--r--drivers/iio/imu/bmi270/bmi270_spi.c1
-rw-r--r--drivers/iio/imu/fxos8700_core.c2
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600.h10
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c22
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c45
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h3
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_core.c12
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c20
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c6
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c6
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c3
-rw-r--r--drivers/iio/imu/inv_icm45600/inv_icm45600.h2
-rw-r--r--drivers/iio/imu/inv_icm45600/inv_icm45600_buffer.c7
-rw-r--r--drivers/iio/imu/inv_icm45600/inv_icm45600_core.c2
-rw-r--r--drivers/iio/imu/inv_icm45600/inv_icm45600_i2c.c2
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c4
-rw-r--r--drivers/iio/industrialio-backend.c8
-rw-r--r--drivers/iio/industrialio-event.c5
-rw-r--r--drivers/iio/inkern.c54
-rw-r--r--drivers/iio/light/al3010.c2
-rw-r--r--drivers/iio/light/cm3605.c1
-rw-r--r--drivers/iio/light/gp2ap002.c1
-rw-r--r--drivers/iio/light/hid-sensor-als.c52
-rw-r--r--drivers/iio/light/hid-sensor-prox.c49
-rw-r--r--drivers/iio/magnetometer/hid-sensor-magn-3d.c73
-rw-r--r--drivers/iio/multiplexer/iio-mux.c1
-rw-r--r--drivers/iio/orientation/hid-sensor-incl-3d.c53
-rw-r--r--drivers/iio/orientation/hid-sensor-rotation.c46
-rw-r--r--drivers/iio/position/hid-sensor-custom-intel-hinge.c15
-rw-r--r--drivers/iio/potentiostat/lmp91000.c1
-rw-r--r--drivers/iio/pressure/hid-sensor-press.c55
-rw-r--r--drivers/iio/pressure/rohm-bm1390.c23
-rw-r--r--drivers/iio/resolver/ad2s1210.c30
-rw-r--r--drivers/iio/temperature/hid-sensor-temperature.c34
-rw-r--r--drivers/infiniband/hw/bng_re/bng_fw.c10
-rw-r--r--drivers/infiniband/hw/hfi1/device.c32
-rw-r--r--drivers/infiniband/hw/hfi1/device.h1
-rw-r--r--drivers/infiniband/hw/hfi1/file_ops.c2
-rw-r--r--drivers/infiniband/hw/ionic/ionic_ibdev.h1
-rw-r--r--drivers/infiniband/hw/irdma/i40iw_hw.c4
-rw-r--r--drivers/infiniband/hw/irdma/icrdma_hw.c2
-rw-r--r--drivers/infiniband/hw/irdma/icrdma_hw.h2
-rw-r--r--drivers/infiniband/hw/irdma/icrdma_if.c8
-rw-r--r--drivers/infiniband/hw/irdma/irdma.h2
-rw-r--r--drivers/infiniband/hw/irdma/utils.c6
-rw-r--r--drivers/infiniband/hw/irdma/verbs.c120
-rw-r--r--drivers/infiniband/hw/irdma/verbs.h3
-rw-r--r--drivers/infiniband/sw/rxe/rxe_mw.c20
-rw-r--r--drivers/input/joystick/adc-joystick.c1
-rw-r--r--drivers/input/keyboard/adc-keys.c1
-rw-r--r--drivers/input/touchscreen/colibri-vf50-ts.c1
-rw-r--r--drivers/input/touchscreen/resistive-adc-touch.c1
-rw-r--r--drivers/iommu/amd/init.c57
-rw-r--r--drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c9
-rw-r--r--drivers/iommu/intel/iommu.c15
-rw-r--r--drivers/iommu/msm_iommu.c2
-rw-r--r--drivers/iommu/mtk_iommu_v1.c2
-rw-r--r--drivers/iommu/riscv/iommu-pci.c6
-rw-r--r--drivers/irqchip/irq-gic-v3.c2
-rw-r--r--drivers/irqchip/irq-gic-v5-iwb.c4
-rw-r--r--drivers/irqchip/irq-gic-v5.c13
-rw-r--r--drivers/irqchip/irq-gic.c2
-rw-r--r--drivers/irqchip/irq-loongarch-cpu.c2
-rw-r--r--drivers/irqchip/irq-riscv-intc.c3
-rw-r--r--drivers/irqchip/qcom-pdc.c2
-rw-r--r--drivers/leds/leds-pca9532.c6
-rw-r--r--drivers/leds/leds-st1202.c102
-rw-r--r--drivers/leds/rgb/leds-lp5860-core.c3
-rw-r--r--drivers/leds/rgb/leds-lp5860-spi.c10
-rw-r--r--drivers/media/cec/core/cec-adap.c8
-rw-r--r--drivers/media/cec/core/cec-core.c92
-rw-r--r--drivers/media/cec/platform/seco/seco-cec.c5
-rw-r--r--drivers/media/cec/platform/tegra/tegra_cec.c1
-rw-r--r--drivers/media/common/v4l2-tpg/v4l2-tpg-core.c14
-rw-r--r--drivers/media/dvb-frontends/rtl2832_sdr.c21
-rw-r--r--drivers/media/i2c/Kconfig21
-rw-r--r--drivers/media/i2c/Makefile2
-rw-r--r--drivers/media/i2c/alvium-csi2.c2
-rw-r--r--drivers/media/i2c/cvs/core.c3
-rw-r--r--drivers/media/i2c/imx471.c957
-rw-r--r--drivers/media/i2c/imx678.c1447
-rw-r--r--drivers/media/i2c/ov02a10.c12
-rw-r--r--drivers/media/i2c/ov7740.c10
-rw-r--r--drivers/media/pci/ddbridge/ddbridge.h2
-rw-r--r--drivers/media/pci/hws/hws_v4l2_ioctl.h4
-rw-r--r--drivers/media/pci/intel/ipu-bridge.c42
-rw-r--r--drivers/media/platform/samsung/s3c-camif/camif-core.c10
-rw-r--r--drivers/media/usb/airspy/airspy.c17
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-audio.c5
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-video.c4
-rw-r--r--drivers/media/usb/em28xx/em28xx-cards.c29
-rw-r--r--drivers/media/usb/em28xx/em28xx-dvb.c2
-rw-r--r--drivers/media/usb/em28xx/em28xx-reg.h1
-rw-r--r--drivers/media/usb/em28xx/em28xx.h1
-rw-r--r--drivers/memory/tegra/mc.c48
-rw-r--r--drivers/memory/tegra/mc.h37
-rw-r--r--drivers/memory/tegra/tegra186-emc.c55
-rw-r--r--drivers/mfd/ab8500-core.c2
-rw-r--r--drivers/mfd/altera-a10sr.c2
-rw-r--r--drivers/mfd/arizona-spi.c12
-rw-r--r--drivers/mfd/cs40l50-spi.c4
-rw-r--r--drivers/mfd/da9052-spi.c12
-rw-r--r--drivers/mfd/db8500-prcmu.c6
-rw-r--r--drivers/mfd/intel-m10-bmc-spi.c6
-rw-r--r--drivers/mfd/madera-spi.c18
-rw-r--r--drivers/mfd/motorola-cpcap.c6
-rw-r--r--drivers/mfd/ocelot-spi.c2
-rw-r--r--drivers/mfd/rk8xx-spi.c2
-rw-r--r--drivers/mfd/rsmu_spi.c12
-rw-r--r--drivers/mfd/sprd-sc27xx-spi.c3
-rw-r--r--drivers/mfd/stmpe-spi.c12
-rw-r--r--drivers/mfd/tps65912-spi.c2
-rw-r--r--drivers/mfd/viperboard.c3
-rw-r--r--drivers/mfd/wm831x-spi.c16
-rw-r--r--drivers/net/bonding/bond_main.c6
-rw-r--r--drivers/net/ethernet/cadence/macb_main.c21
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_82575.h21
-rw-r--r--drivers/net/ethernet/intel/igb/igb.h3
-rw-r--r--drivers/net/ethernet/intel/igb/igb_ethtool.c85
-rw-r--r--drivers/net/ethernet/intel/igb/igb_main.c25
-rw-r--r--drivers/net/ethernet/intel/igc/igc.h3
-rw-r--r--drivers/net/ethernet/intel/igc/igc_base.c35
-rw-r--r--drivers/net/ethernet/intel/igc/igc_defines.h9
-rw-r--r--drivers/net/ethernet/intel/igc/igc_ethtool.c277
-rw-r--r--drivers/net/ethernet/intel/igc/igc_hw.h10
-rw-r--r--drivers/net/ethernet/intel/igc/igc_mac.c35
-rw-r--r--drivers/net/ethernet/intel/igc/igc_main.c10
-rw-r--r--drivers/net/ethernet/intel/igc/igc_phy.c65
-rw-r--r--drivers/net/ethernet/intel/igc/igc_phy.h1
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/port_tun.c3
-rw-r--r--drivers/net/ethernet/microsoft/Kconfig1
-rw-r--r--drivers/net/ethernet/microsoft/mana/gdma_main.c29
-rw-r--r--drivers/net/ethernet/microsoft/mana/mana_en.c236
-rw-r--r--drivers/net/ethernet/microsoft/mana/mana_ethtool.c167
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_dcbx.c2
-rw-r--r--drivers/net/macsec.c2
-rw-r--r--drivers/net/ppp/ppp_async.c2
-rw-r--r--drivers/net/ppp/ppp_synctty.c2
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_rx.c2
-rw-r--r--drivers/net/wireless/ath/ath11k/ahb.c1
-rw-r--r--drivers/net/wireless/ath/ath11k/dp_rx.c3
-rw-r--r--drivers/net/wireless/ath/ath11k/pci.c4
-rw-r--r--drivers/net/wireless/ath/ath12k/pci.c4
-rw-r--r--drivers/nvmem/core.c313
-rw-r--r--drivers/nvmem/internals.h13
-rw-r--r--drivers/pci/ats.c13
-rw-r--r--drivers/pci/controller/cadence/pcie-cadence-plat.c1
-rw-r--r--drivers/phy/motorola/phy-cpcap-usb.c1
-rw-r--r--drivers/pinctrl/intel/pinctrl-tigerlake.c32
-rw-r--r--drivers/pinctrl/pinctrl-upboard.c21
-rw-r--r--drivers/pinctrl/qcom/pinctrl-msm.c15
-rw-r--r--drivers/pinctrl/qcom/pinctrl-x1e80100.c4
-rw-r--r--drivers/platform/surface/surfacepro3_button.c8
-rw-r--r--drivers/platform/x86/Kconfig1
-rw-r--r--drivers/platform/x86/amd/pmc/pmc.c26
-rw-r--r--drivers/platform/x86/asus-armoury.c46
-rw-r--r--drivers/platform/x86/asus-armoury.h134
-rw-r--r--drivers/platform/x86/asus-laptop.c9
-rw-r--r--drivers/platform/x86/eeepc-laptop.c7
-rw-r--r--drivers/platform/x86/fujitsu-laptop.c18
-rw-r--r--drivers/platform/x86/fujitsu-tablet.c13
-rw-r--r--drivers/platform/x86/hp/hp-wmi.c64
-rw-r--r--drivers/platform/x86/huawei-wmi.c99
-rw-r--r--drivers/platform/x86/intel/int3472/discrete.c18
-rw-r--r--drivers/platform/x86/intel/ishtp_eclite.c5
-rw-r--r--drivers/platform/x86/lenovo/thinkpad_acpi.c127
-rw-r--r--drivers/platform/x86/lg-laptop.c644
-rw-r--r--drivers/platform/x86/panasonic-laptop.c4
-rw-r--r--drivers/platform/x86/sony-laptop.c5
-rw-r--r--drivers/platform/x86/topstar-laptop.c2
-rw-r--r--drivers/platform/x86/toshiba_acpi.c6
-rw-r--r--drivers/platform/x86/toshiba_haps.c4
-rw-r--r--drivers/platform/x86/xo15-ebook.c8
-rw-r--r--drivers/pmdomain/imx/imx8m-blk-ctrl.c46
-rw-r--r--drivers/pmdomain/imx/imx93-blk-ctrl.c60
-rw-r--r--drivers/pmdomain/qcom/rpmhpd.c24
-rw-r--r--drivers/power/supply/ab8500_btemp.c1
-rw-r--r--drivers/power/supply/ab8500_charger.c1
-rw-r--r--drivers/power/supply/ab8500_fg.c1
-rw-r--r--drivers/power/supply/axp20x_ac_power.c1
-rw-r--r--drivers/power/supply/axp20x_battery.c1
-rw-r--r--drivers/power/supply/axp20x_usb_power.c1
-rw-r--r--drivers/power/supply/axp288_fuel_gauge.c1
-rw-r--r--drivers/power/supply/cpcap-battery.c1
-rw-r--r--drivers/power/supply/cpcap-charger.c1
-rw-r--r--drivers/power/supply/da9150-charger.c1
-rw-r--r--drivers/power/supply/generic-adc-battery.c1
-rw-r--r--drivers/power/supply/ingenic-battery.c1
-rw-r--r--drivers/power/supply/intel_dc_ti_battery.c1
-rw-r--r--drivers/power/supply/lego_ev3_battery.c1
-rw-r--r--drivers/power/supply/lp8788-charger.c1
-rw-r--r--drivers/power/supply/max17040_battery.c1
-rw-r--r--drivers/power/supply/mp2629_charger.c1
-rw-r--r--drivers/power/supply/mt6370-charger.c1
-rw-r--r--drivers/power/supply/qcom_smbx.c1
-rw-r--r--drivers/power/supply/rn5t618_power.c1
-rw-r--r--drivers/power/supply/rx51_battery.c1
-rw-r--r--drivers/power/supply/sc27xx_fuel_gauge.c1
-rw-r--r--drivers/power/supply/twl4030_charger.c1
-rw-r--r--drivers/power/supply/twl4030_madc_battery.c1
-rw-r--r--drivers/power/supply/twl6030_charger.c1
-rw-r--r--drivers/pwm/Kconfig2
-rw-r--r--drivers/pwm/pwm-apple.c2
-rw-r--r--drivers/pwm/pwm-argon-fan-hat.c2
-rw-r--r--drivers/pwm/pwm-atmel-hlcdc.c15
-rw-r--r--drivers/pwm/pwm-atmel-tcb.c6
-rw-r--r--drivers/pwm/pwm-atmel.c3
-rw-r--r--drivers/pwm/pwm-bcm-iproc.c2
-rw-r--r--drivers/pwm/pwm-bcm-kona.c2
-rw-r--r--drivers/pwm/pwm-bcm2835.c2
-rw-r--r--drivers/pwm/pwm-berlin.c2
-rw-r--r--drivers/pwm/pwm-brcmstb.c2
-rw-r--r--drivers/pwm/pwm-clk.c2
-rw-r--r--drivers/pwm/pwm-clps711x.c2
-rw-r--r--drivers/pwm/pwm-cros-ec.c2
-rw-r--r--drivers/pwm/pwm-hibvt.c2
-rw-r--r--drivers/pwm/pwm-imx-tpm.c2
-rw-r--r--drivers/pwm/pwm-imx1.c2
-rw-r--r--drivers/pwm/pwm-imx27.c2
-rw-r--r--drivers/pwm/pwm-ipq.c4
-rw-r--r--drivers/pwm/pwm-jz4740.c2
-rw-r--r--drivers/pwm/pwm-loongson.c2
-rw-r--r--drivers/pwm/pwm-lp3943.c2
-rw-r--r--drivers/pwm/pwm-lpc18xx-sct.c2
-rw-r--r--drivers/pwm/pwm-lpc32xx.c2
-rw-r--r--drivers/pwm/pwm-lpss-pci.c2
-rw-r--r--drivers/pwm/pwm-lpss-platform.c10
-rw-r--r--drivers/pwm/pwm-mediatek.c2
-rw-r--r--drivers/pwm/pwm-meson.c9
-rw-r--r--drivers/pwm/pwm-mtk-disp.c8
-rw-r--r--drivers/pwm/pwm-mxs.c2
-rw-r--r--drivers/pwm/pwm-omap-dmtimer.c4
-rw-r--r--drivers/pwm/pwm-pca9685.c6
-rw-r--r--drivers/pwm/pwm-pxa.c18
-rw-r--r--drivers/pwm/pwm-raspberrypi-poe.c2
-rw-r--r--drivers/pwm/pwm-rcar.c4
-rw-r--r--drivers/pwm/pwm-renesas-tpu.c10
-rw-r--r--drivers/pwm/pwm-rockchip.c8
-rw-r--r--drivers/pwm/pwm-rzg2l-gpt.c2
-rw-r--r--drivers/pwm/pwm-samsung.c2
-rw-r--r--drivers/pwm/pwm-sifive.c2
-rw-r--r--drivers/pwm/pwm-sl28cpld.c2
-rw-r--r--drivers/pwm/pwm-sophgo-sg2042.c7
-rw-r--r--drivers/pwm/pwm-sprd.c4
-rw-r--r--drivers/pwm/pwm-sti.c2
-rw-r--r--drivers/pwm/pwm-stm32-lp.c4
-rw-r--r--drivers/pwm/pwm-stm32.c6
-rw-r--r--drivers/pwm/pwm-sun4i.c2
-rw-r--r--drivers/pwm/pwm-sunplus.c4
-rw-r--r--drivers/pwm/pwm-tiecap.c6
-rw-r--r--drivers/pwm/pwm-tiehrpwm.c2
-rw-r--r--drivers/pwm/pwm-twl-led.c2
-rw-r--r--drivers/pwm/pwm-twl.c2
-rw-r--r--drivers/pwm/pwm-visconti.c2
-rw-r--r--drivers/pwm/pwm-vt8500.c2
-rw-r--r--drivers/pwm/pwm-xilinx.c4
-rw-r--r--drivers/rapidio/rio-scan.c1
-rw-r--r--drivers/regulator/core.c4
-rw-r--r--drivers/regulator/db8500-prcmu.c12
-rw-r--r--drivers/regulator/mt6316-regulator.c1
-rw-r--r--drivers/regulator/mt6363-regulator.c1
-rw-r--r--drivers/remoteproc/Kconfig4
-rw-r--r--drivers/remoteproc/mtk_scp.c9
-rw-r--r--drivers/remoteproc/qcom_q6v5_mss.c5
-rw-r--r--drivers/remoteproc/qcom_q6v5_pas.c51
-rw-r--r--drivers/remoteproc/qcom_wcnss.c12
-rw-r--r--drivers/remoteproc/ti_k3_r5_remoteproc.c8
-rw-r--r--drivers/s390/crypto/zcrypt_cex2a.c0
-rw-r--r--drivers/s390/crypto/zcrypt_cex2a.h0
-rw-r--r--drivers/s390/crypto/zcrypt_cex2c.c0
-rw-r--r--drivers/s390/crypto/zcrypt_cex2c.h0
-rw-r--r--drivers/soc/qcom/llcc-qcom.c29
-rw-r--r--drivers/soc/qcom/mdt_loader.c12
-rw-r--r--drivers/soc/qcom/qcom_pd_mapper.c38
-rw-r--r--drivers/soc/qcom/qcom_stats.c2
-rw-r--r--drivers/soc/qcom/ubwc_config.c1
-rw-r--r--drivers/spi/spi-geni-qcom.c17
-rw-r--r--drivers/staging/axis-fifo/axis-fifo.c3
-rw-r--r--drivers/staging/iio/frequency/ad9832.c20
-rw-r--r--drivers/staging/iio/frequency/ad9834.c22
-rw-r--r--drivers/staging/iio/frequency/dds.h24
-rw-r--r--drivers/staging/media/ipu7/ipu7.c4
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_ap.c4
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_cmd.c196
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_mlme.c4
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_mlme_ext.c30
-rw-r--r--drivers/staging/rtl8723bs/include/rtw_cmd.h154
-rw-r--r--drivers/staging/rtl8723bs/include/rtw_event.h4
-rw-r--r--drivers/staging/rtl8723bs/include/rtw_mlme_ext.h54
-rw-r--r--drivers/staging/rtl8723bs/include/wifi.h34
-rw-r--r--drivers/staging/rtl8723bs/os_dep/sdio_intf.c5
-rw-r--r--drivers/thermal/db8500_thermal.c10
-rw-r--r--drivers/thermal/qcom/qcom-spmi-adc-tm5.c1
-rw-r--r--drivers/thermal/qcom/qcom-spmi-temp-alarm.c1
-rw-r--r--drivers/thermal/renesas/rzg3s_thermal.c1
-rw-r--r--drivers/thermal/thermal-generic-adc.c1
-rw-r--r--drivers/tty/amiserial.c14
-rw-r--r--drivers/tty/serial/8250/8250_exar.c30
-rw-r--r--drivers/tty/serial/max310x.c91
-rw-r--r--drivers/tty/serial/men_z135_uart.c7
-rw-r--r--drivers/tty/serial/pch_uart.c6
-rw-r--r--drivers/tty/serial/rp2.c2
-rw-r--r--drivers/tty/tty_jobctrl.c41
-rw-r--r--drivers/tty/vt/vc_screen.c6
-rw-r--r--drivers/usb/cdns3/cdns3-plat.c4
-rw-r--r--drivers/usb/core/devices.c7
-rw-r--r--drivers/usb/core/hub.c2
-rw-r--r--drivers/usb/dwc3/core.c103
-rw-r--r--drivers/usb/dwc3/core.h7
-rw-r--r--drivers/usb/dwc3/dwc3-am62.c13
-rw-r--r--drivers/usb/dwc3/dwc3-qcom.c2
-rw-r--r--drivers/usb/dwc3/dwc3-xilinx.c18
-rw-r--r--drivers/usb/dwc3/gadget.c58
-rw-r--r--drivers/usb/fotg210/fotg210-hcd.c6
-rw-r--r--drivers/usb/gadget/function/f_printer.c3
-rw-r--r--drivers/usb/gadget/function/rndis.c20
-rw-r--r--drivers/usb/gadget/udc/core.c29
-rw-r--r--drivers/usb/gadget/udc/r8a66597-udc.c1
-rw-r--r--drivers/usb/host/ehci-sched.c11
-rw-r--r--drivers/usb/host/ohci-dbg.c9
-rw-r--r--drivers/usb/host/sl811-hcd.c1
-rw-r--r--drivers/usb/host/xhci-sideband.c2
-rw-r--r--drivers/usb/host/xhci.c11
-rw-r--r--drivers/usb/misc/chaoskey.c1
-rw-r--r--drivers/usb/misc/usbio.c4
-rw-r--r--drivers/usb/misc/uss720.c5
-rw-r--r--drivers/usb/storage/ene_ub6250.c3
-rw-r--r--drivers/usb/typec/altmodes/displayport.c18
-rw-r--r--drivers/usb/typec/altmodes/thunderbolt.c4
-rw-r--r--drivers/usb/typec/anx7411.c4
-rw-r--r--drivers/usb/typec/class.c72
-rw-r--r--drivers/usb/typec/mux.c13
-rw-r--r--drivers/usb/typec/mux/ps883x.c6
-rw-r--r--drivers/usb/typec/mux/tusb1046.c1
-rw-r--r--drivers/usb/typec/tcpm/tcpci_rt1711h.c13
-rw-r--r--drivers/usb/typec/tcpm/tcpm.c15
-rw-r--r--drivers/usb/typec/tipd/core.c9
-rw-r--r--drivers/usb/typec/tipd/tps6598x.h10
-rw-r--r--drivers/usb/typec/ucsi/debugfs.c5
-rw-r--r--drivers/usb/typec/ucsi/displayport.c3
-rw-r--r--drivers/usb/typec/ucsi/ucsi.c26
-rw-r--r--drivers/usb/typec/ucsi/ucsi.h2
-rw-r--r--drivers/usb/typec/ucsi/ucsi_acpi.c10
-rw-r--r--drivers/usb/typec/ucsi/ucsi_huawei_gaokun.c12
-rw-r--r--drivers/usb/usbip/vudc.h1
-rw-r--r--drivers/usb/usbip/vudc_dev.c4
-rw-r--r--drivers/video/backlight/Kconfig8
-rw-r--r--drivers/video/backlight/Makefile1
-rw-r--r--drivers/video/backlight/sy7758.c259
-rw-r--r--drivers/watchdog/Kconfig19
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/db8500_wdt.c22
-rw-r--r--drivers/watchdog/pretimeout_dump.c45
-rw-r--r--drivers/watchdog/watchdog_pretimeout.c2
-rw-r--r--drivers/watchdog/watchdog_pretimeout.h4
-rw-r--r--fs/nfs/inode.c7
-rw-r--r--fs/notify/fanotify/fanotify.c1
-rw-r--r--fs/ocfs2/inode.c2
-rw-r--r--fs/pipe.c2
-rw-r--r--fs/proc/task_mmu.c143
-rw-r--r--fs/smb/client/cifsacl.c2
-rw-r--r--fs/smb/client/cifsglob.h1
-rw-r--r--fs/smb/client/cifsproto.h2
-rw-r--r--fs/smb/client/cifssmb.c36
-rw-r--r--fs/smb/client/connect.c2
-rw-r--r--fs/smb/client/dfs_cache.c12
-rw-r--r--fs/smb/client/file.c2
-rw-r--r--fs/smb/client/inode.c9
-rw-r--r--fs/smb/client/link.c17
-rw-r--r--fs/smb/client/misc.c14
-rw-r--r--fs/smb/client/readdir.c4
-rw-r--r--fs/smb/client/smb1ops.c28
-rw-r--r--fs/smb/client/smb2file.c19
-rw-r--r--fs/smb/client/smb2misc.c32
-rw-r--r--fs/smb/client/smb2ops.c19
-rw-r--r--fs/smb/client/smb2pdu.c26
-rw-r--r--fs/smb/client/smb2proto.h2
-rw-r--r--fs/udf/balloc.c12
-rw-r--r--fs/udf/inode.c26
-rw-r--r--fs/udf/partition.c2
-rw-r--r--fs/udf/super.c23
-rw-r--r--fs/udf/truncate.c2
-rw-r--r--fs/udf/udfdecl.h3
-rw-r--r--include/asm-generic/hugetlb.h18
-rw-r--r--include/asm-generic/pgtable_uffd.h32
-rw-r--r--include/drm/drm_gpusvm.h67
-rw-r--r--include/drm/drm_of.h11
-rw-r--r--include/drm/drm_panel.h8
-rw-r--r--include/dt-bindings/clock/qcom,shikra-gcc.h263
-rw-r--r--include/dt-bindings/iio/adc/mediatek,mt6323-auxadc.h24
-rw-r--r--include/dt-bindings/power/fsl,imx93-power.h1
-rw-r--r--include/linux/acpi.h13
-rw-r--r--include/linux/acpi_iort.h3
-rw-r--r--include/linux/bpf.h10
-rw-r--r--include/linux/bpf_verifier.h23
-rw-r--r--include/linux/damon.h2
-rw-r--r--include/linux/efi.h6
-rw-r--r--include/linux/firmware/qcom/qcom_pas.h43
-rw-r--r--include/linux/huge_mm.h7
-rw-r--r--include/linux/inetdevice.h5
-rw-r--r--include/linux/kvm_host.h7
-rw-r--r--include/linux/leafops.h4
-rw-r--r--include/linux/mdio.h1
-rw-r--r--include/linux/mfd/db8500-prcmu.h252
-rw-r--r--include/linux/mfd/dbx500-prcmu.h575
-rw-r--r--include/linux/mm.h83
-rw-r--r--include/linux/mm_inline.h4
-rw-r--r--include/linux/module.h4
-rw-r--r--include/linux/pgtable.h32
-rw-r--r--include/linux/soc/qcom/mdt_loader.h6
-rw-r--r--include/linux/swap.h76
-rw-r--r--include/linux/swapops.h4
-rw-r--r--include/linux/sysctl.h123
-rw-r--r--include/linux/tick.h3
-rw-r--r--include/linux/usb/typec.h1
-rw-r--r--include/linux/userfaultfd_k.h100
-rw-r--r--include/media/drv-intf/s3c_camif.h2
-rw-r--r--include/media/v4l2-ioctl.h4
-rw-r--r--include/net/addrconf.h5
-rw-r--r--include/net/ip_vs.h3
-rw-r--r--include/net/mana/gdma.h24
-rw-r--r--include/net/mana/mana.h62
-rw-r--r--include/net/netfilter/nf_flow_table.h7
-rw-r--r--include/trace/events/huge_memory.h2
-rw-r--r--include/trace/events/mmflags.h7
-rw-r--r--include/uapi/linux/fs.h1
-rw-r--r--include/uapi/linux/landlock.h8
-rw-r--r--include/uapi/linux/userfaultfd.h54
-rw-r--r--init/Kconfig8
-rw-r--r--io_uring/tw.c9
-rw-r--r--kernel/audit.c11
-rw-r--r--kernel/bpf/btf.c2
-rw-r--r--kernel/bpf/core.c9
-rw-r--r--kernel/bpf/fixups.c9
-rw-r--r--kernel/bpf/syscall.c85
-rw-r--r--kernel/bpf/task_iter.c36
-rw-r--r--kernel/bpf/verifier.c519
-rw-r--r--kernel/events/core.c2
-rw-r--r--kernel/module/dups.c2
-rw-r--r--kernel/module/main.c15
-rw-r--r--kernel/module/procfs.c2
-rw-r--r--kernel/module/stats.c2
-rw-r--r--kernel/panic.c14
-rw-r--r--kernel/params.c2
-rw-r--r--kernel/printk/printk.c11
-rw-r--r--kernel/sched/ext/cid.c55
-rw-r--r--kernel/sched/ext/cid.h2
-rw-r--r--kernel/sched/ext/ext.c208
-rw-r--r--kernel/sched/ext/internal.h23
-rw-r--r--kernel/sched/ext/sub.c6
-rw-r--r--kernel/sched/sched.h3
-rw-r--r--kernel/sysctl.c516
-rw-r--r--kernel/time/jiffies.c28
-rw-r--r--kernel/time/tick-sched.c7
-rw-r--r--kernel/time/timekeeping.c4
-rw-r--r--lib/bug.c2
-rw-r--r--lib/test_bitmap.c1
-rw-r--r--localversion-next1
-rw-r--r--mm/Kconfig13
-rw-r--r--mm/Makefile2
-rw-r--r--mm/compaction.c3
-rw-r--r--mm/damon/core.c37
-rw-r--r--mm/damon/lru_sort.c6
-rw-r--r--mm/damon/reclaim.c6
-rw-r--r--mm/damon/sysfs.c3
-rw-r--r--mm/debug_vm_pgtable.c4
-rw-r--r--mm/folio.c (renamed from mm/swap.c)46
-rw-r--r--mm/huge_memory.c177
-rw-r--r--mm/hugetlb.c177
-rw-r--r--mm/internal.h73
-rw-r--r--mm/khugepaged.c40
-rw-r--r--mm/memfd.c1
-rw-r--r--mm/memory.c199
-rw-r--r--mm/migrate.c20
-rw-r--r--mm/migrate_device.c8
-rw-r--r--mm/mprotect.c70
-rw-r--r--mm/mremap.c17
-rw-r--r--mm/nommu.c36
-rw-r--r--mm/page_alloc.c14
-rw-r--r--mm/page_table_check.c8
-rw-r--r--mm/percpu-km.c11
-rw-r--r--mm/rmap.c18
-rw-r--r--mm/shmem.c3
-rw-r--r--mm/slub.c116
-rw-r--r--mm/swap.h2
-rw-r--r--mm/swap_state.c50
-rw-r--r--mm/swapfile.c9
-rw-r--r--mm/userfaultfd.c389
-rw-r--r--mm/util.c2
-rw-r--r--mm/vmscan.c42
-rw-r--r--net/batman-adv/distributed-arp-table.c2
-rw-r--r--net/batman-adv/fragmentation.c8
-rw-r--r--net/batman-adv/main.c10
-rw-r--r--net/batman-adv/mesh-interface.c16
-rw-r--r--net/batman-adv/mesh-interface.h2
-rw-r--r--net/batman-adv/multicast_forw.c7
-rw-r--r--net/batman-adv/translation-table.c5
-rw-r--r--net/bridge/netfilter/ebtables.c12
-rw-r--r--net/core/bpf_sk_storage.c2
-rw-r--r--net/core/filter.c90
-rw-r--r--net/core/sock.c3
-rw-r--r--net/ethtool/netlink.h28
-rw-r--r--net/ethtool/rss.c14
-rw-r--r--net/ipv4/igmp.c28
-rw-r--r--net/ipv6/mcast.c40
-rw-r--r--net/ipv6/netfilter/nf_conntrack_reasm.c5
-rw-r--r--net/netfilter/ipset/ip_set_hash_gen.h85
-rw-r--r--net/netfilter/ipvs/ip_vs_core.c31
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_sctp.c18
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_tcp.c11
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_udp.c3
-rw-r--r--net/netfilter/nf_flow_table_core.c19
-rw-r--r--net/netfilter/nf_flow_table_ip.c21
-rw-r--r--net/netfilter/nf_flow_table_offload.c22
-rw-r--r--net/netfilter/nfnetlink_log.c26
-rw-r--r--net/netfilter/nfnetlink_queue.c16
-rw-r--r--net/netfilter/nft_lookup.c10
-rw-r--r--net/netfilter/xt_u32.c16
-rw-r--r--rust/kernel/iommu/pgtable.rs3
-rw-r--r--rust/kernel/module_param.rs18
-rw-r--r--rust/kernel/usb.rs31
-rw-r--r--samples/damon/mtier.c5
-rw-r--r--samples/damon/prcl.c4
-rw-r--r--samples/damon/wsse.c4
-rw-r--r--samples/rust/rust_minimal.rs2
-rw-r--r--scripts/module.lds.S5
-rw-r--r--security/landlock/task.c9
-rw-r--r--sound/core/control.c6
-rw-r--r--sound/core/hwdep.c2
-rw-r--r--sound/core/info.c2
-rw-r--r--sound/core/oss/mixer_oss.c2
-rw-r--r--sound/core/oss/pcm_oss.c2
-rw-r--r--sound/core/pcm_native.c2
-rw-r--r--sound/drivers/aloop.c118
-rw-r--r--sound/hda/codecs/cm9825.c148
-rw-r--r--sound/hda/codecs/realtek/alc269.c11
-rw-r--r--sound/hda/codecs/side-codecs/Kconfig2
-rw-r--r--sound/soc/amd/acp/acp-i2s.c6
-rw-r--r--sound/soc/amd/raven/acp3x-i2s.c6
-rw-r--r--sound/soc/amd/vangogh/acp5x-i2s.c6
-rw-r--r--sound/soc/amd/yc/acp6x-mach.c12
-rw-r--r--sound/soc/codecs/audio-iio-aux.c1
-rw-r--r--sound/soc/codecs/cs35l32.c10
-rw-r--r--sound/soc/codecs/cs42l43-jack.c3
-rw-r--r--sound/soc/codecs/cs4349.c8
-rw-r--r--sound/soc/codecs/lpass-rx-macro.c31
-rw-r--r--sound/soc/codecs/lpass-tx-macro.c25
-rw-r--r--sound/soc/codecs/max98090.c8
-rw-r--r--sound/soc/codecs/max98363.c7
-rw-r--r--sound/soc/codecs/max98373-i2c.c9
-rw-r--r--sound/soc/codecs/max98373-sdw.c7
-rw-r--r--sound/soc/codecs/max98388.c8
-rw-r--r--sound/soc/codecs/max98396.c24
-rw-r--r--sound/soc/codecs/max98927.c8
-rw-r--r--sound/soc/codecs/pcm1681.c7
-rw-r--r--sound/soc/codecs/pcm1754.c6
-rw-r--r--sound/soc/codecs/pcm1789.c7
-rw-r--r--sound/soc/codecs/pcm179x.c6
-rw-r--r--sound/soc/codecs/pcm186x.c9
-rw-r--r--sound/soc/codecs/pcm3060.c8
-rw-r--r--sound/soc/codecs/pcm512x.c9
-rw-r--r--sound/soc/codecs/pm4125-sdw.c8
-rw-r--r--sound/soc/codecs/pm4125.c3
-rw-r--r--sound/soc/codecs/rt1017-sdca-sdw.c7
-rw-r--r--sound/soc/codecs/rt1316-sdw.c7
-rw-r--r--sound/soc/codecs/rt1318-sdw.c7
-rw-r--r--sound/soc/codecs/rt1320-sdw.c17
-rw-r--r--sound/soc/codecs/rt5514.c16
-rw-r--r--sound/soc/codecs/rt5645.c16
-rw-r--r--sound/soc/codecs/rt5682-sdw.c20
-rw-r--r--sound/soc/codecs/rt712-sdca-dmic.c17
-rw-r--r--sound/soc/codecs/rt712-sdca-sdw.c17
-rw-r--r--sound/soc/codecs/rt721-sdca-sdw.c17
-rw-r--r--sound/soc/codecs/rt722-sdca-sdw.c8
-rw-r--r--sound/soc/codecs/rt9120.c9
-rw-r--r--sound/soc/codecs/tas2552.c10
-rw-r--r--sound/soc/codecs/tas2562.c5
-rw-r--r--sound/soc/codecs/tas2783-sdw.c16
-rw-r--r--sound/soc/codecs/uda1342.c9
-rw-r--r--sound/soc/codecs/wcd937x-sdw.c8
-rw-r--r--sound/soc/codecs/wcd938x-sdw.c8
-rw-r--r--sound/soc/codecs/wcd939x-sdw.c8
-rw-r--r--sound/soc/codecs/wm2200.c10
-rw-r--r--sound/soc/codecs/wm5100.c10
-rw-r--r--sound/soc/codecs/wm8962.c9
-rw-r--r--sound/soc/codecs/wsa881x.c8
-rw-r--r--sound/soc/codecs/wsa883x.c8
-rw-r--r--sound/soc/codecs/wsa884x.c8
-rw-r--r--sound/soc/meson/t9015.c6
-rw-r--r--sound/soc/qcom/sc8280xp.c1
-rw-r--r--sound/soc/samsung/aries_wm8994.c1
-rw-r--r--sound/soc/samsung/midas_wm1811.c1
-rw-r--r--sound/soc/spacemit/k1_i2s.c7
-rw-r--r--sound/soc/stm/stm32_adfsdm.c1
-rw-r--r--sound/soc/ux500/ux500_msp_dai.c2
-rw-r--r--sound/usb/quirks.c2
-rw-r--r--tools/bpf/bpftool/gen.c2
-rw-r--r--tools/bpf/bpftool/sign.c24
-rw-r--r--tools/bpf/resolve_btfids/Makefile5
-rw-r--r--tools/include/uapi/linux/fs.h1
-rw-r--r--tools/include/uapi/linux/userfaultfd.h54
-rw-r--r--tools/lib/api/fd/array.c6
-rw-r--r--tools/lib/bpf/bpf_gen_internal.h1
-rw-r--r--tools/lib/bpf/gen_loader.c76
-rw-r--r--tools/lib/bpf/libbpf_internal.h1
-rw-r--r--tools/lib/bpf/skel_internal.h31
-rw-r--r--tools/perf/builtin-stat.c7
-rw-r--r--tools/perf/pmu-events/arch/x86/amdzen5/floating-point.json42
-rwxr-xr-xtools/perf/tests/shell/stat.sh12
-rw-r--r--tools/perf/util/data-convert-json.c1
-rw-r--r--tools/perf/util/dso.h57
-rw-r--r--tools/perf/util/sideband_evlist.c14
-rw-r--r--tools/sched_ext/include/scx/cid.bpf.h88
-rw-r--r--tools/sched_ext/include/scx/common.bpf.h2
-rw-r--r--tools/sched_ext/scx_qmap.c21
-rw-r--r--tools/sched_ext/scx_qmap.h34
-rw-r--r--tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c12
-rw-r--r--tools/testing/selftests/bpf/prog_tests/icmp_send_kfunc.c292
-rw-r--r--tools/testing/selftests/bpf/prog_tests/kfunc_call.c1
-rw-r--r--tools/testing/selftests/bpf/prog_tests/res_spin_lock.c20
-rw-r--r--tools/testing/selftests/bpf/prog_tests/signed_loader.c1033
-rw-r--r--tools/testing/selftests/bpf/progs/icmp_send.c123
-rw-r--r--tools/testing/selftests/bpf/progs/kfunc_call_fail.c33
-rw-r--r--tools/testing/selftests/bpf/progs/tcp_ca_untrusted_btf_write.c26
-rw-r--r--tools/testing/selftests/bpf/progs/test_signed_loader.c9
-rw-r--r--tools/testing/selftests/bpf/progs/verifier_map_ptr.c23
-rw-r--r--tools/testing/selftests/bpf/progs/verifier_scalar_ids.c56
-rwxr-xr-xtools/testing/selftests/drivers/net/hw/rss_ctx.py11
-rw-r--r--tools/testing/selftests/drivers/net/lib/py/env.py27
-rwxr-xr-xtools/testing/selftests/drivers/net/xdp.py94
-rw-r--r--tools/testing/selftests/kvm/Makefile.kvm7
-rw-r--r--tools/testing/selftests/kvm/arch_timer.c2
-rw-r--r--tools/testing/selftests/kvm/arm64/arch_timer_edge_cases.c2
-rw-r--r--tools/testing/selftests/kvm/demand_paging_test.c2
-rw-r--r--tools/testing/selftests/kvm/dirty_log_perf_test.c4
-rw-r--r--tools/testing/selftests/kvm/dirty_log_test.c11
-rw-r--r--tools/testing/selftests/kvm/include/kvm_syscalls.h7
-rw-r--r--tools/testing/selftests/kvm/include/kvm_util.h12
-rw-r--r--tools/testing/selftests/kvm/include/proc_util.h11
-rw-r--r--tools/testing/selftests/kvm/include/test_util.h25
-rw-r--r--tools/testing/selftests/kvm/include/x86/kvm_util_arch.h4
-rw-r--r--tools/testing/selftests/kvm/irq_test.c362
-rw-r--r--tools/testing/selftests/kvm/lib/assert.c8
-rw-r--r--tools/testing/selftests/kvm/lib/kvm_util.c54
-rw-r--r--tools/testing/selftests/kvm/lib/memstress.c8
-rw-r--r--tools/testing/selftests/kvm/lib/proc_util.c54
-rw-r--r--tools/testing/selftests/kvm/lib/test_util.c27
-rw-r--r--tools/testing/selftests/kvm/mmu_stress_test.c15
-rw-r--r--tools/testing/selftests/kvm/rseq_test.c6
-rw-r--r--tools/testing/selftests/kvm/steal_time.c22
-rw-r--r--tools/testing/selftests/kvm/x86/sev_dbg_test.c2
-rw-r--r--tools/testing/selftests/kvm/x86/sev_migrate_tests.c47
-rw-r--r--tools/testing/selftests/kvm/x86/xapic_ipi_test.c2
-rw-r--r--tools/testing/selftests/landlock/fs_test.c2
-rw-r--r--tools/testing/selftests/landlock/net_test.c11
-rw-r--r--tools/testing/selftests/landlock/scoped_signal_test.c67
-rw-r--r--tools/testing/selftests/liveupdate/.gitignore1
-rw-r--r--tools/testing/selftests/liveupdate/config1
-rw-r--r--tools/testing/selftests/liveupdate/config.aarch642
-rw-r--r--tools/testing/selftests/liveupdate/config.x86_642
-rw-r--r--tools/testing/selftests/liveupdate/init.c179
-rw-r--r--tools/testing/selftests/liveupdate/luo_test_utils.c15
-rwxr-xr-xtools/testing/selftests/liveupdate/run-vmtests.sh97
-rwxr-xr-xtools/testing/selftests/liveupdate/vmtest.sh263
-rw-r--r--tools/testing/selftests/mm/pagemap_ioctl.c56
-rw-r--r--tools/testing/selftests/mm/uffd-unit-tests.c919
-rw-r--r--tools/testing/selftests/net/lib.sh15
-rw-r--r--tools/testing/selftests/net/tcp_mmap.c4
-rw-r--r--tools/testing/selftests/rseq/Makefile6
-rw-r--r--tools/testing/selftests/sched_ext/Makefile1
-rw-r--r--tools/testing/selftests/sched_ext/nohz_tick.bpf.c65
-rw-r--r--tools/testing/selftests/sched_ext/nohz_tick.c347
-rw-r--r--tools/testing/selftests/sched_ext/prog_run.c34
-rw-r--r--tools/testing/vma/include/dup.h2
-rw-r--r--tools/usb/usbip/libsrc/usbip_common.c2
-rw-r--r--tools/usb/usbip/libsrc/usbip_device_driver.c4
-rw-r--r--tools/usb/usbip/libsrc/vhci_driver.c1
-rw-r--r--virt/kvm/kvm_main.c9
1098 files changed, 47785 insertions, 7544 deletions
diff --git a/.mailmap b/.mailmap
index 33809ff5b8cf..afcc7e79cd2e 100644
--- a/.mailmap
+++ b/.mailmap
@@ -185,6 +185,7 @@ Carlos Bilbao <carlos.bilbao@kernel.org> <bilbao@vt.edu>
Changbin Du <changbin.du@intel.com> <changbin.du@gmail.com>
Chao Yu <chao@kernel.org> <chao2.yu@samsung.com>
Chao Yu <chao@kernel.org> <yuchao0@huawei.com>
+Charlie Jenkins <thecharlesjenkins@gmail.com> <charlie@rivosinc.com>
Chen-Yu Tsai <wens@kernel.org> <wens@csie.org>
Chester Lin <chester62515@gmail.com> <clin@suse.com>
Chris Chiu <chris.chiu@canonical.com> <chiu@endlessm.com>
@@ -875,6 +876,7 @@ Tobias Klauser <tklauser@distanz.ch> <klto@zhaw.ch>
Tobias Klauser <tklauser@distanz.ch> <tklauser@nuerscht.ch>
Tobias Klauser <tklauser@distanz.ch> <tklauser@xenon.tklauser.home>
Todor Tomov <todor.too@gmail.com> <todor.tomov@linaro.org>
+Tomasz Duszynski <tduszyns@gmail.com> <tomasz.duszynski@octakon.com>
Tomasz Jeznach <tomasz.jeznach@linux.dev> <tjeznach@rivosinc.com>
Tony Luck <tony.luck@intel.com>
Trilok Soni <quic_tsoni@quicinc.com> <tsoni@codeaurora.org>
diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
index 4ea5598e7cd2..5cc2e82c4997 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio
+++ b/Documentation/ABI/testing/sysfs-bus-iio
@@ -770,6 +770,7 @@ Description:
3.85kohm_to_gnd: connected to ground via a 3.85kOhm resistor,
6kohm_to_gnd: connected to ground via a 6kOhm resistor,
7.7kohm_to_gnd: connected to ground via a 7.7kOhm resistor,
+ 10kohm_to_gnd: connected to ground via a 10kOhm resistor,
16kohm_to_gnd: connected to ground via a 16kOhm resistor,
20kohm_to_gnd: connected to ground via a 20kOhm resistor,
32kohm_to_gnd: connected to ground via a 32kOhm resistor,
diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb
index af9b653422f1..baf4bf6d32ee 100644
--- a/Documentation/ABI/testing/sysfs-bus-usb
+++ b/Documentation/ABI/testing/sysfs-bus-usb
@@ -293,7 +293,7 @@ Description:
Supported values are 0 - 15.
More information on how besl values map to microseconds can be found in
- USB 2.0 ECN Errata for Link Power Management, section 4.10)
+ USB 2.0 ECN Errata for Link Power Management, section 4.10
What: /sys/bus/usb/devices/.../rx_lanes
Date: March 2018
diff --git a/Documentation/accounting/delay-accounting.rst b/Documentation/accounting/delay-accounting.rst
index 4bb2e72a6043..0f1d8023338b 100644
--- a/Documentation/accounting/delay-accounting.rst
+++ b/Documentation/accounting/delay-accounting.rst
@@ -181,7 +181,7 @@ Interactive keyboard controls during runtime::
M - Toggle display mode (Default/Memory Verbose)
q - Quit
-Available sort fields(use -s/--sort or interactive command)::
+Available sort fields (use -s/--sort or interactive command)::
cpu(c) - CPU delay
blkio(i) - I/O delay
@@ -219,8 +219,8 @@ Advanced usage examples::
-delaytop add delay_max fields to track the maximum delay value for each delay type
-(cpu, blkio, irq, swapin, freepages, thrashing, compact, wpcopy) per task.
+delaytop add delay_max fields to track the maximum delay value for each delay
+ type (cpu, blkio, irq, swapin, freepages, thrashing, compact, wpcopy) per task::
bash# ./delaytop -t cpu
System Pressure Information: (avg10/avg60/avg300/total)
diff --git a/Documentation/admin-guide/laptops/thinkpad-acpi.rst b/Documentation/admin-guide/laptops/thinkpad-acpi.rst
index f874db31801d..db4588af0278 100644
--- a/Documentation/admin-guide/laptops/thinkpad-acpi.rst
+++ b/Documentation/admin-guide/laptops/thinkpad-acpi.rst
@@ -1543,6 +1543,30 @@ Values:
This setting can also be toggled via the Fn+doubletap hotkey.
+USB-C Security
+--------------
+
+sysfs: usb_c_security
+
+Reports the current state of the USB-C Security (Restricted Mode) feature
+on supported ThinkPad systems. When enabled, USB-C data connections are
+disabled while power delivery is preserved.
+
+The available command is::
+
+ cat /sys/devices/platform/thinkpad_acpi/usb_c_security
+
+Values:
+
+ * ``enabled`` - USB-C data connections are currently blocked
+ * ``disabled`` - USB-C data connections are currently allowed
+
+The attribute is read-only. The USB-C Security state can only be toggled
+via the Fn+U followed by Fn+S hotkey chord.
+
+The sysfs attribute is not created on platforms that do not support this
+feature.
+
Auxmac
------
diff --git a/Documentation/admin-guide/media/em28xx-cardlist.rst b/Documentation/admin-guide/media/em28xx-cardlist.rst
index 7dac07986d91..741aa7f7c882 100644
--- a/Documentation/admin-guide/media/em28xx-cardlist.rst
+++ b/Documentation/admin-guide/media/em28xx-cardlist.rst
@@ -446,3 +446,7 @@ EM28xx cards list
- MyGica UTV3 Analog USB2.0 TV Box
- em2860
- eb1a:2860
+ * - 113
+ - StarTech SVID2USB232
+ - em28281
+ - eb1a:8286
diff --git a/Documentation/admin-guide/mm/pagemap.rst b/Documentation/admin-guide/mm/pagemap.rst
index 20e3fe76f099..77447c454632 100644
--- a/Documentation/admin-guide/mm/pagemap.rst
+++ b/Documentation/admin-guide/mm/pagemap.rst
@@ -19,8 +19,11 @@ There are four components to pagemap:
* Bit 55 pte is soft-dirty (see
Documentation/admin-guide/mm/soft-dirty.rst)
* Bit 56 page exclusively mapped (since 4.2)
- * Bit 57 pte is uffd-wp write-protected (since 5.13) (see
- Documentation/admin-guide/mm/userfaultfd.rst)
+ * Bit 57 pte is tracked by userfaultfd (since 5.13) — in a
+ ``VM_UFFD_WP`` VMA this indicates a write-protected PTE; in a
+ ``VM_UFFD_RWP`` VMA it indicates an RWP-protected PTE. WP and
+ RWP are mutually exclusive per VMA, so the meaning is
+ unambiguous. See Documentation/admin-guide/mm/userfaultfd.rst.
* Bit 58 pte is a guard region (since 6.15) (see madvise (2) man page)
* Bits 59-60 zero
* Bit 61 page is file-page or shared-anon (since 3.5)
@@ -244,7 +247,8 @@ in this IOCTL:
Following flags about pages are currently supported:
- ``PAGE_IS_WPALLOWED`` - Page has async-write-protection enabled
-- ``PAGE_IS_WRITTEN`` - Page has been written to from the time it was write protected
+- ``PAGE_IS_WRITTEN`` - Page in a ``UFFDIO_REGISTER_MODE_WP`` VMA has been
+ written to since it was write-protected. Only reported inside such VMAs.
- ``PAGE_IS_FILE`` - Page is file backed
- ``PAGE_IS_PRESENT`` - Page is present in the memory
- ``PAGE_IS_SWAPPED`` - Page is in swapped
@@ -252,6 +256,9 @@ Following flags about pages are currently supported:
- ``PAGE_IS_HUGE`` - Page is PMD-mapped THP or Hugetlb backed
- ``PAGE_IS_SOFT_DIRTY`` - Page is soft-dirty
- ``PAGE_IS_GUARD`` - Page is a part of a guard region
+- ``PAGE_IS_ACCESSED`` - Page in a ``UFFDIO_REGISTER_MODE_RWP`` VMA has been
+ accessed since RWP was applied. Only reported inside such VMAs. See
+ Documentation/admin-guide/mm/userfaultfd.rst for the RWP workflow.
The ``struct pm_scan_arg`` is used as the argument of the IOCTL.
diff --git a/Documentation/admin-guide/mm/userfaultfd.rst b/Documentation/admin-guide/mm/userfaultfd.rst
index e5cc8848dcb3..783d969f0e28 100644
--- a/Documentation/admin-guide/mm/userfaultfd.rst
+++ b/Documentation/admin-guide/mm/userfaultfd.rst
@@ -131,6 +131,16 @@ userfaults on the range registered. Not all ioctls will necessarily be
supported for all memory types (e.g. anonymous memory vs. shmem vs.
hugetlbfs), or all types of intercepted faults.
+.. note::
+
+ Re-registering an already-registered range must not drop any of the
+ modes that install per-PTE markers — currently
+ ``UFFDIO_REGISTER_MODE_WP`` and ``UFFDIO_REGISTER_MODE_RWP``. Doing
+ so would strand markers with no flag to describe them, so the call
+ is rejected with ``-EBUSY``; userspace must issue
+ ``UFFDIO_UNREGISTER`` first. This differs from older kernels, which
+ silently replaced the mode bits on re-registration.
+
Userland can use the ``uffdio_register.ioctls`` to manage the virtual
address space in the background (to add or potentially also remove
memory from the ``userfaultfd`` registered range). This means a userfault
@@ -265,16 +275,16 @@ tracking and it can be different in a few ways:
- Dirty information will not get lost if the pte was zapped due to
various reasons (e.g. during split of a shmem transparent huge page).
- - Due to a reverted meaning of soft-dirty (page clean when uffd-wp bit
- set; dirty when uffd-wp bit cleared), it has different semantics on
- some of the memory operations. For example: ``MADV_DONTNEED`` on
+ - Due to a reverted meaning of soft-dirty (page clean when the uffd bit
+ is set; dirty when the uffd bit is cleared), it has different semantics
+ on some of the memory operations. For example: ``MADV_DONTNEED`` on
anonymous (or ``MADV_REMOVE`` on a file mapping) will be treated as
- dirtying of memory by dropping uffd-wp bit during the procedure.
+ dirtying of memory by dropping the uffd bit during the procedure.
The user app can collect the "written/dirty" status by looking up the
-uffd-wp bit for the pages being interested in /proc/pagemap.
+uffd bit for the pages being interested in /proc/pagemap.
-The page will not be under track of uffd-wp async mode until the page is
+The page will not be under track of userfaultfd-wp async mode until the page is
explicitly write-protected by ``ioctl(UFFDIO_WRITEPROTECT)`` with the mode
flag ``UFFDIO_WRITEPROTECT_MODE_WP`` set. Trying to resolve a page fault
that was tracked by async mode userfaultfd-wp is invalid.
@@ -297,6 +307,253 @@ transparent to the guest, we want that same address range to act as if it was
still poisoned, even though it's on a new physical host which ostensibly
doesn't have a memory error in the exact same spot.
+Read-Write Protection
+---------------------
+
+``UFFDIO_REGISTER_MODE_RWP`` enables read-write protection tracking on a
+memory range. It is similar to (but faster than) ``mprotect(PROT_NONE)``
+combined with a signal handler; unlike ``mprotect(PROT_NONE)``, RWP only
+traps accesses to *present* PTEs, so accesses to unpopulated addresses in a
+protected range fall through to the normal missing-page path. It uses the
+PROT_NONE hinting mechanism (same as NUMA balancing) to make pages
+inaccessible while keeping them resident in memory. Works on anonymous,
+shmem, and hugetlbfs memory.
+
+RWP is designed for VM memory managers that need to track the working set
+of guest memory for cold page eviction to tiered or remote storage.
+
+**Setup:**
+
+1. Open a userfaultfd and enable ``UFFD_FEATURE_RWP`` via ``UFFDIO_API``.
+ Optionally request ``UFFD_FEATURE_RWP_ASYNC`` as well — it requires
+ ``UFFD_FEATURE_RWP`` to be set in the same ``UFFDIO_API`` call.
+
+2. Register the guest memory range with ``UFFDIO_REGISTER_MODE_RWP``
+ (and ``UFFDIO_REGISTER_MODE_MISSING`` if evicted pages will need to be
+ fetched back from storage).
+
+**Feature availability:**
+
+RWP is built on top of two kernel primitives: a spare PTE bit owned by
+userfaultfd (``CONFIG_HAVE_ARCH_USERFAULTFD_WP``) and architecture support
+for present-but-inaccessible PTEs (``CONFIG_ARCH_HAS_PTE_PROTNONE``). When both
+are available on a 64-bit kernel, the build selects
+``CONFIG_USERFAULTFD_RWP=y`` and the ``VM_UFFD_RWP`` VMA flag becomes
+available.
+
+``UFFD_FEATURE_RWP`` and ``UFFD_FEATURE_RWP_ASYNC`` are unavailable when
+the running kernel or architecture does not support them — for example
+32-bit kernels (where ``VM_UFFD_RWP`` is unavailable), kernels built
+without ``CONFIG_USERFAULTFD_RWP``, and architectures whose ptes cannot
+carry the uffd bit at runtime (e.g. riscv without the ``SVRSW60T59B``
+extension). Requesting an unsupported feature in
+``uffdio_api.features`` makes ``UFFDIO_API`` fail with ``EINVAL`` and
+leaves the userfaultfd context uninitialized; the structure is returned
+zeroed, so the error path cannot be used to discover what the kernel
+supports. The recommended probe sequence is therefore to open a
+throwaway userfaultfd, call ``UFFDIO_API`` once with ``features = 0``,
+inspect the returned bitmask, close that fd, then open the real one
+and call ``UFFDIO_API`` again with only the supported features set.
+
+**Protecting and Unprotecting:**
+
+Use ``UFFDIO_RWPROTECT`` to protect or unprotect a range, mirroring the
+``UFFDIO_WRITEPROTECT`` interface::
+
+ struct uffdio_rwprotect rwp = {
+ .range = { .start = addr, .len = len },
+ .mode = UFFDIO_RWPROTECT_MODE_RWP, /* protect */
+ };
+ ioctl(uffd, UFFDIO_RWPROTECT, &rwp);
+
+Setting ``UFFDIO_RWPROTECT_MODE_RWP`` sets PROT_NONE on present PTEs in the
+range. Pages stay resident and their physical frames are preserved — only
+access permissions are removed.
+
+Clearing ``UFFDIO_RWPROTECT_MODE_RWP`` restores normal VMA permissions and
+wakes any faulting threads (unless ``UFFDIO_RWPROTECT_MODE_DONTWAKE`` is set).
+
+**Scope of protection:**
+
+RWP protection is a property of *present* PTEs. ``UFFDIO_RWPROTECT`` only
+affects entries that are already populated. Unpopulated addresses within
+the range remain unpopulated; when first accessed they fault through the
+normal missing path (``do_anonymous_page()``, ``do_swap_page()``,
+``finish_fault()``) and the resulting PTE is not RWP-protected. To observe
+the population itself, co-register the range with
+``UFFDIO_REGISTER_MODE_MISSING``.
+
+Protection is preserved across page reclaim: a page swapped out while
+RWP-protected carries the marker on its swap entry, and swap-in restores
+the PROT_NONE state so the first access after swap-in still faults. The
+same applies to pages temporarily replaced by migration entries.
+
+Operations that drop the PTE entirely — ``MADV_DONTNEED`` on anonymous
+memory, hole-punch on shmem, truncation of a file mapping — also drop the
+RWP marker: the next access re-populates the range without protection.
+Unlike WP (which persists via ``PTE_MARKER_UFFD_WP``), there is no
+persistent RWP marker today. The user needs to re-arm the range with
+``UFFDIO_RWPROTECT`` after any operation that explicitly frees PTEs.
+
+**Fault Handling:**
+
+When a protected page is accessed:
+
+- **Sync mode** (default): The faulting thread blocks and a
+ ``UFFD_PAGEFAULT_FLAG_RWP`` message is delivered to the userfaultfd
+ handler. The handler resolves the fault with ``UFFDIO_RWPROTECT``
+ (clearing ``MODE_RWP``), which restores the PTE permissions and wakes
+ the faulting thread.
+
+- **Async mode** (``UFFD_FEATURE_RWP_ASYNC``): The kernel automatically
+ restores PTE permissions and the thread continues without blocking. No
+ message is delivered to the handler.
+
+**Runtime Mode Switching:**
+
+``UFFDIO_SET_MODE`` toggles ``UFFD_FEATURE_RWP_ASYNC`` at runtime, allowing
+the VMM to switch between lightweight async detection and safe sync
+eviction without re-registering. The toggle takes ``mmap_write_lock()``
+and calls ``vma_start_write()`` on each UFFD-armed VMA, draining
+in-flight per-VMA-locked faults before the new mode takes effect.
+
+**Working-set detection with PAGEMAP_SCAN:**
+
+RWP-protected PTEs carry the uffd PTE bit; an access (and, in async mode, its
+auto-resolution) clears it. ``PAGEMAP_SCAN`` reports ``PAGE_IS_ACCESSED`` once
+the bit is clear on a ``VM_UFFD_RWP`` VMA, so a *non-inverted* scan reports the
+pages that were touched during the interval -- the hot set::
+
+ struct pm_scan_arg arg = {
+ .size = sizeof(arg),
+ .start = guest_mem_start,
+ .end = guest_mem_end,
+ .vec = (uint64_t)regions,
+ .vec_len = regions_len,
+ .category_mask = PAGE_IS_ACCESSED,
+ .return_mask = PAGE_IS_ACCESSED,
+ };
+ long n = ioctl(pagemap_fd, PAGEMAP_SCAN, &arg);
+
+The returned ``page_region`` array lists the hot ranges. ``PAGE_IS_ACCESSED``
+is set on an accessed page whether it is still present or has since been
+swapped out, so the hot scan needs no ``PAGE_IS_PRESENT`` filter -- unpopulated
+holes carry neither bit and are excluded on their own.
+
+Track the hot set and reclaim everything else from the backing file (see the
+workflow below). Do **not** invert the scan to enumerate "cold" pages
+directly: an inverted scan reports only the ``VM_UFFD_RWP`` PTEs that are still
+protected, i.e. the resident portion of *this* VMA. For a file mapping the
+working set spans the whole file -- pages that live in the page cache but are
+not mapped into this VMA (a pre-populated tmpfs file, or memory populated
+through another mapping) are ``pte_none`` here, never appear in the scan, and
+would never be considered for eviction even though they occupy memory. Driving
+eviction from "file offsets minus the hot set" avoids that blind spot; a cold
+PTE scan cannot. To additionally record the *first* access to a cached but
+unmapped page (e.g. pre-populated content) as hot, co-register the range with
+``UFFDIO_REGISTER_MODE_MINOR``: such accesses then fault as minor faults
+instead of mapping the page silently.
+
+**Cleanup:**
+
+When the userfaultfd is closed or the range is unregistered, all PROT_NONE
+PTEs are automatically restored to their normal VMA permissions. This
+prevents pages from becoming permanently inaccessible.
+
+**VMM Working Set Tracking Workflow:**
+
+A typical VMM lifecycle for cold page eviction to tiered storage. Two
+mappings of the same shmem (or hugetlbfs) file are used: ``guest_mem`` is
+the RWP-registered mapping that vCPUs access through, and ``io_mem`` is a
+private mapping for VMM-side I/O. Reading ``io_mem`` does not go through
+the RWP-protected PTEs of ``guest_mem``, so the VMM's own ``pwrite()``
+never traps on its own ::
+
+ /* One-time setup */
+ fd = memfd_create("guest", MFD_CLOEXEC);
+ ftruncate(fd, guest_size);
+ guest_mem = mmap(NULL, guest_size, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, 0); /* vCPU view, RWP-registered */
+ io_mem = mmap(NULL, guest_size, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, 0); /* VMM I/O view, unprotected */
+
+ uffd = userfaultfd(O_CLOEXEC | O_NONBLOCK);
+ struct uffdio_api api = {
+ .api = UFFD_API,
+ .features = UFFD_FEATURE_RWP | UFFD_FEATURE_RWP_ASYNC,
+ };
+ ioctl(uffd, UFFDIO_API, &api);
+ if (!(api.features & UFFD_FEATURE_RWP))
+ /* RWP unavailable on this kernel/arch -- fall back. */
+ ioctl(uffd, UFFDIO_REGISTER, &(struct uffdio_register){
+ .range = { guest_mem, guest_size },
+ .mode = UFFDIO_REGISTER_MODE_RWP |
+ UFFDIO_REGISTER_MODE_MISSING,
+ });
+
+ /* Tracking loop */
+ while (vm_running) {
+ /* 1. Detection phase (async -- no vCPU stalls) */
+ ioctl(uffd, UFFDIO_RWPROTECT, &(struct uffdio_rwprotect){
+ .range = full_range,
+ .mode = UFFDIO_RWPROTECT_MODE_RWP });
+ sleep(tracking_interval);
+
+ /*
+ * 2. Switch to sync BEFORE scanning. In async mode a vCPU
+ * access races eviction: it would auto-resolve and mark the
+ * page hot just as the VMM writes it out and punches it,
+ * losing the update. Sync mode makes such accesses block and
+ * be delivered, freezing the hot snapshot for the rest of the
+ * iteration.
+ */
+ ioctl(uffd, UFFDIO_SET_MODE,
+ &(struct uffdio_set_mode){
+ .disable = UFFD_FEATURE_RWP_ASYNC });
+
+ /* 3. Read the hot set: pages touched this interval. */
+ ioctl(pagemap_fd, PAGEMAP_SCAN, &(struct pm_scan_arg){
+ .category_mask = PAGE_IS_ACCESSED,
+ .return_mask = PAGE_IS_ACCESSED,
+ ...
+ });
+
+ /*
+ * 4. Reclaim the file offsets that are NOT in the hot set.
+ * Driving this from the file's offset space (rather than from a
+ * cold PTE scan) also reclaims pages that are cached but not
+ * mapped into guest_mem, e.g. pre-populated content.
+ */
+ for each non-hot offset range:
+ /* Read from io_mem -- bypasses RWP, no fault. */
+ pwrite(storage_fd, (char *)io_mem + off, len, off);
+ /* Drop the page from the shared file. */
+ fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
+ off, len);
+ /*
+ * Wake any vCPU blocked on the RWP fault for this range:
+ * fallocate() does not iterate ctx->fault_pending_wqh.
+ */
+ ioctl(uffd, UFFDIO_WAKE, &(struct uffdio_range){
+ .start = (uintptr_t)guest_mem + off, .len = len });
+
+ /* 5. Resume async tracking */
+ ioctl(uffd, UFFDIO_SET_MODE,
+ &(struct uffdio_set_mode){
+ .enable = UFFD_FEATURE_RWP_ASYNC });
+ }
+
+During step 4, a vCPU that accesses a ``guest_mem`` offset being evicted
+blocks with a ``UFFD_PAGEFAULT_FLAG_RWP`` fault while the eviction is in
+progress. After ``fallocate()`` punches the page out and ``UFFDIO_WAKE``
+fires, the vCPU retries the access, faults as ``MISSING``, and the
+handler resolves it with ``UFFDIO_COPY`` from storage.
+
+This workflow targets shmem and hugetlbfs (both support a private
+``io_mem`` mapping over the same fd). Anonymous-memory backings need a
+different inner-loop strategy because the VMM has no way to read the
+page without going through the RWP-protected mapping.
+
QEMU/KVM
========
diff --git a/Documentation/admin-guide/sysctl/vm.rst b/Documentation/admin-guide/sysctl/vm.rst
index 22cc54cac3b2..5b318d17aa4b 100644
--- a/Documentation/admin-guide/sysctl/vm.rst
+++ b/Documentation/admin-guide/sysctl/vm.rst
@@ -19,9 +19,6 @@ The files in this directory can be used to tune the operation
of the virtual memory (VM) subsystem of the Linux kernel and
the writeout of dirty data to disk.
-Default values and initialization routines for most of these
-files can be found in mm/swap.c.
-
Currently, these files are in /proc/sys/vm:
- admin_reserve_kbytes
diff --git a/Documentation/bpf/index.rst b/Documentation/bpf/index.rst
index 0d5c6f659266..638a00d42bc2 100644
--- a/Documentation/bpf/index.rst
+++ b/Documentation/bpf/index.rst
@@ -28,6 +28,7 @@ that goes into great technical depth about the BPF Architecture.
classic_vs_extended.rst
bpf_iterators
bpf_licensing
+ signing
test_debug
clang-notes
linux-notes
diff --git a/Documentation/bpf/signing.rst b/Documentation/bpf/signing.rst
new file mode 100644
index 000000000000..e73eaaebd8b1
--- /dev/null
+++ b/Documentation/bpf/signing.rst
@@ -0,0 +1,497 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+============
+BPF signing
+============
+
+This document describes how BPF programs are cryptographically signed, how the
+kernel verifies them at load time, and how Linux Security Modules (LSMs) -
+including the BPF LSM - use the resulting verdict to enforce policy. It is
+written for developers who want to produce signed BPF objects, understand what
+the signature actually guarantees, or build a policy on top of it.
+
+Motivation
+==========
+
+A signed BPF program lets the kernel establish that the bytecode being loaded
+originates from a trusted producer and was not modified in transit. On its own
+the kernel does not *require* signatures - an unsigned program loads exactly as
+before - but it records a verdict (see `The verdict`_) that an LSM can gate on.
+This is the building block for policies such as "only run BPF that was signed by
+a key in the trusted keyring", as could in the future be enforced by an LSM
+such as IPE.
+
+Signing is orthogonal to the existing permission model: it does not replace the
+capability checks or the verifier. A signed load still requires the usual
+privileges (``CAP_BPF`` and any program-type-specific capability, subject to
+``kernel.unprivileged_bpf_disabled``), and the loader's instructions are still
+checked by the verifier like any other program. A valid signature establishes
+*origin and integrity*, not safety - it lets a policy trust where the bytecode
+came from, it does not let a load skip any check it would otherwise face.
+
+The hard part is *what* gets signed. A naive scheme would sign a program's
+instruction buffer at build time and verify that signature at
+``BPF_PROG_LOAD``. That does not survive contact with real BPF objects, because
+the bytes the kernel finally loads are not the bytes the developer built and
+signed. Between the two, libbpf and the kernel rewrite the program:
+
+- **map file descriptors** are patched into ``ld_imm64`` instructions
+ (``BPF_PSEUDO_MAP_FD``), and a map's fd is assigned at load time, so it
+ differs on every run;
+- **CO-RE relocations** rewrite field offsets, sizes and existence flags against
+ the *running* kernel's BTF, so the result differs from one kernel to the next;
+- **kfunc and ksym references** are resolved to ids/addresses in the running
+ kernel;
+- **global data** (``.rodata``/``.data``/``.bss``) is created and seeded as maps
+ at load.
+
+So a signature over the original instructions cannot match the relocated
+instructions the verifier ends up checking, and the relocated form cannot be
+produced ahead of time because it depends on the target kernel. There is no
+fixed byte string that is both signable at build time and what the kernel
+actually loads - which is why a program cannot simply be signed and loaded
+directly.
+
+The trusted loader
+==================
+
+The solution is to move that setup work *into* a small BPF program - the
+**loader** - and sign the loader instead of the individual programs. libbpf's
+``gen_loader`` machinery (``bpftool gen skeleton -L``, the "light skeleton")
+emits a ``BPF_PROG_TYPE_SYSCALL`` program whose body performs the bpf() syscalls
+that create maps, apply relocations, and load the real programs. The payload it
+installs - the serialized programs, map descriptions, relocation data and
+initial values - lives in a separate array map, the **metadata map**
+(``__loader.map``).
+
+So the unit of trust is the loader, and the signing contract is::
+
+ Sig(I_loader || D_meta)
+
+where ``I_loader`` is the loader's instruction stream and ``D_meta`` is the
+content of the metadata map. Verifying the loader's signature establishes that
+both the loader *and* the payload it is about to install are authentic. The
+loader is reproducible: ``gen_loader`` builds it from primitives so the same
+object yields the same bytes on any build host.
+
+Why the loader is signable when the program is not
+--------------------------------------------------
+
+The loader sidesteps every rewrite listed above, because the bytes that are
+signed are *relocation-invariant*:
+
+- The loader's own instructions are a fixed sequence of bpf() syscalls emitted
+ by ``gen_loader``; they carry no CO-RE relocations and resolve no ksyms, so
+ they are identical on every kernel. The metadata map is referenced by *index*
+ into ``fd_array`` (``BPF_PSEUDO_MAP_IDX_VALUE``), not by a baked-in file
+ descriptor, so even that reference does not change between build and load.
+ The loader instruction bytes the kernel verifies are exactly the bytes that
+ were signed.
+- The metadata map is opaque, frozen data - the serialized target programs,
+ their relocation records, map descriptions and initial values. Its bytes are
+ identical at build time and at load time, so they are simply appended to the
+ instructions and covered by the same signature (there is no separate metadata
+ hash to compute or compare).
+
+All the host-specific rewriting - creating maps, patching their fds into the
+target programs, applying CO-RE, resolving ksyms, seeding global data - still
+happens, but it happens *inside the loader at runtime*, on the verified
+metadata, **after** the kernel has verified the ``insns || metadata`` signature.
+The kernel never has to verify the relocated target programs: it verifies the
+loader and its inputs once, and trust transfers to whatever that now-trusted,
+deterministic loader installs. The relocation step is moved from "before the
+signature can be checked" to "after a trusted program runs" - which is exactly
+what makes it signable.
+
+Because the metadata map is the loader's only untrusted input, two existing map
+properties are reused to keep it trustworthy across the load:
+
+Exclusive maps
+ A map created with ``excl_prog_hash`` (see ``BPF_MAP_CREATE``) may only be
+ accessed by a program whose digest matches that hash. The verifier enforces
+ ``map->excl_prog_sha == prog->digest`` for every map a program uses, so the
+ metadata map is bound to exactly the signed loader and cannot be shared with
+ or mutated by another program.
+
+Frozen maps
+ The metadata map is frozen (``BPF_MAP_FREEZE``) before the loader is loaded.
+ Freezing blocks further userspace writes, so the bytes folded into the
+ signature cannot change before the loader runs. (Freezing does not make the
+ map read-only to the loader program itself, which still writes created file
+ descriptors back into the blob's scratch area.)
+
+Load-time verification
+=======================
+
+Rather than have the loader check its own metadata from within BPF, the kernel
+verifies it directly at ``BPF_PROG_LOAD``, with no new UAPI. The mechanism
+reuses the existing ``fd_array``:
+
+#. Userspace creates the metadata map with ``excl_prog_hash`` set to the
+ loader's digest, populates it, and freezes it.
+#. The loader is loaded with ``signature``/``signature_size``/``keyring_id``
+ set, the metadata map referenced through ``fd_array``, and ``fd_array_cnt``
+ set so the kernel knows the array's length.
+#. Signature verification runs inside the verifier (``bpf_check()``), once it
+ has resolved the ``fd_array`` entries into the program's ``used_maps``. The
+ maps folded into the signature are therefore the very objects the program
+ binds - a single resolution of ``fd_array``, not a separate read, so the
+ verified bytes cannot be swapped for a different map after the check (no
+ time-of-check/time-of-use window). Each folded map must be exclusive (carry
+ ``excl_prog_sha``) and a plain array map (``BPF_MAP_TYPE_ARRAY``); only an
+ array map exposes its value buffer through ``map_direct_value_addr()`` as a
+ kernel address spanning ``value_size`` bytes. A map that is not exclusive, not
+ frozen, or not a plain array is rejected, with a verifier log message naming
+ the offending map. The kernel appends each map's frozen
+ contents to the instruction buffer and verifies the PKCS#7 signature over the
+ concatenation ``insns || metadata_0 || metadata_1 || ...`` in ``used_maps``
+ order, before it rewrites the (signed) instructions.
+
+A signed program therefore takes one of exactly two shapes, both fully
+supported:
+
+- **No bound maps** (``fd_array_cnt == 0``): there is nothing to append, so the
+ kernel verifies the signature over the instructions alone. A valid signature
+ yields ``BPF_SIG_VERIFIED`` and the program loads. This is the ordinary case
+ for a directly-loaded signed program with no separate payload; it is *not*
+ rejected for "missing" metadata, because it has none to cover.
+- **Exclusive bound maps** (``fd_array_cnt > 0``): every entry is exclusive and
+ folded, so the signature covers ``insns || metadata``.
+
+There is no third shape: a non-exclusive map in a signed program's ``fd_array``
+is rejected rather than silently left out of the signature, so a signed loader
+never binds a map its signature does not cover.
+
+The digest binding (``excl_prog_sha == prog->digest``) is enforced by the
+verifier as usual; because that check runs while ``fd_array`` is resolved -
+before the verifier would otherwise compute the tag - ``prog->digest`` is
+computed up front in the verifier, over the unmodified (signature-covered)
+instructions, for any signed load.
+
+Coverage is then enforced as the verifier resolves instructions, at the point
+each object is bound rather than by a count taken afterwards. Once the signature
+has been verified, binding any further map is refused: a map reached by a
+directly-referenced fd, or a map swapped into an ``fd_array`` slot the loader
+reads, is not among those already folded, so it is rejected the moment the
+verifier tries to bind it. A BTF is refused outright for a signed program - a
+ksym or a BTF fd in ``fd_array``, whether resolved up front or lazily for a
+module kfunc, is rejected when it would be bound. Together with the fold rule
+above this keeps the verdict binary: a signed program cannot use a map its
+signature does not cover, and a different but equally digest-bound map cannot be
+substituted at an ``fd_array`` slot. Non-exclusive maps are never folded, so a
+signed program cannot use one at all.
+
+The verdict
+===========
+
+A program is either unsigned or fully verified - there is no intermediate
+state. The outcome is recorded in ``prog->aux->sig.verdict``:
+
+.. code-block:: c
+
+ enum bpf_sig_verdict {
+ BPF_SIG_UNSIGNED = 0,
+ BPF_SIG_VERIFIED,
+ };
+
+``BPF_SIG_VERIFIED`` means the signature is valid and covers the instructions
+*and* the frozen contents of every exclusive map the program uses:
+
+- For an ordinary, directly-loaded signed program the instructions are the whole
+ artifact and it uses no exclusive maps, so a valid instruction signature is
+ the complete verification.
+- For a signed loader the metadata map is exclusive, so its contents are folded
+ in and the signature covers ``insns || metadata``.
+
+There is deliberately no "instructions verified but metadata not" verdict: a
+signed loader that fails to cover its metadata is *rejected* (see above), not
+recorded with a weaker verdict. ``BPF_SIG_VERIFIED`` therefore always means the
+program and everything the signature is responsible for are authentic, which is
+what a policy can rely on.
+
+Alongside the verdict the kernel records which keyring validated the signature;
+see `Keyrings`_.
+
+Enforcement via LSMs
+====================
+
+Signing only *records* a verdict; an LSM turns it into policy. The verdict and
+keyring fields live in ``struct bpf_prog_aux``, so a BPF LSM program can read
+them directly (see Documentation/bpf/prog_lsm.rst for writing and attaching BPF
+LSM programs); the same fields are equally available to in-tree LSMs. Two hooks
+are useful at different points of the load: the dedicated
+``security_bpf_prog_load()`` gates admission before the main verification work,
+and the existing ``security_bpf_prog()`` observes a program that has fully
+loaded.
+
+Admission: ``security_bpf_prog_load()``
+---------------------------------------
+
+This hook gates admission **for every load**, from a single call site inside the
+verifier (``bpf_check()``), before the main verification work. It runs after the
+optional signature verification, so the verdict and keyring fields are final - the
+hook can see whether, and how strongly, the program was signed, which keyring
+validated it, the load ``attr``, the BPF token and whether the load came from the
+kernel. For a signed load the verdict is ``BPF_SIG_VERIFIED`` here (the signature
+has just been checked); for an unsigned load it is ``BPF_SIG_UNSIGNED``.
+
+This is the place for *coarse admission* that must also see unsigned and
+not-yet-verified loads: require a signature at all, restrict the acceptable
+keyring, restrict which token/credentials may load BPF, apply per-program-type
+rules, or audit every load attempt that makes it past signature verification -
+attempts failing the signature or the metadata binding abort before this hook
+fires. It is the primary deny point.
+
+One subtlety: this hook runs *before* the verifier finishes its work, so
+``BPF_SIG_VERIFIED`` *here* means only "validly signed" - not "loaded". Allowing
+a load at this point lets it *proceed*; it does not guarantee the program will
+load. A validly signed program can still be rejected afterwards on two
+independent grounds: the verifier may reject it like any other program (unsafe
+memory access, bad control flow, resource limits, ...), and the kernel separately
+refuses - as the verifier resolves instructions and binds each object - any map
+the signature does not cover or any BTF at all, regardless of what this hook
+returned. Only after the program has fully loaded, at the next hook
+(``security_bpf_prog()``), does ``BPF_SIG_VERIFIED`` carry its full meaning:
+validly signed *and* fully verified.
+
+A more realistic admission policy than "is it signed at all": accept programs
+signed by a system keyring, accept a user-keyring signature only if the
+key/keyring it was verified against is on an explicit allowlist, and emit a
+tamper-evident record of every decision so that even denied attempts are
+auditable. (Illustrative - error checking elided.)
+
+.. code-block:: c
+
+ /* Serials of user keys/keyrings we additionally trust. */
+ struct {
+ __uint(type, BPF_MAP_TYPE_HASH);
+ __type(key, __s32); /* keyring_serial */
+ __type(value, __u8);
+ __uint(max_entries, 64);
+ } trusted_user_keys SEC(".maps");
+
+ /* Audit stream consumed by a userspace logger. */
+ struct {
+ __uint(type, BPF_MAP_TYPE_RINGBUF);
+ __uint(max_entries, 1 << 16);
+ } audit SEC(".maps");
+
+ struct decision { __u32 prog_type, verdict, ktype; __s32 serial, ret; };
+
+ SEC("lsm/bpf_prog_load")
+ int BPF_PROG(admit, struct bpf_prog *prog, union bpf_attr *attr,
+ struct bpf_token *token, bool kernel)
+ {
+ __u32 verdict = prog->aux->sig.verdict;
+ __u32 ktype = prog->aux->sig.keyring_type;
+ __s32 serial = prog->aux->sig.keyring_serial;
+ struct decision *d;
+ int ret = 0;
+
+ if (kernel)
+ return 0; /* trust in-kernel loads */
+
+ if (verdict != BPF_SIG_VERIFIED)
+ ret = -EPERM; /* must be validly signed */
+ else if (ktype == BPF_SIG_KEYRING_USER &&
+ !bpf_map_lookup_elem(&trusted_user_keys, &serial))
+ ret = -EPERM; /* key/keyring not allowlisted */
+
+ d = bpf_ringbuf_reserve(&audit, sizeof(*d), 0);
+ if (d) {
+ d->prog_type = attr->prog_type;
+ d->verdict = verdict;
+ d->ktype = ktype;
+ d->serial = serial;
+ d->ret = ret;
+ bpf_ringbuf_submit(d, 0); /* record allow *and* deny */
+ }
+ return ret;
+ }
+
+Observing a verified load: ``security_bpf_prog()``
+--------------------------------------------------
+
+There is deliberately no separate "metadata attested" hook. The coverage check
+above is enforced by the kernel unconditionally, so a signed loader that fails
+to cover its metadata never loads and an LSM never has to re-establish that
+fact. To *act on* a program that has successfully and fully loaded, use the
+existing ``security_bpf_prog()`` hook (``lsm/bpf_prog``), which fires from
+``bpf_prog_new_fd()`` - after the verifier, after the coverage check, and after
+``bpf_prog_alloc_id()``. Relative to the admission hook this point is strictly
+later and stronger:
+
+- the program has an id (``prog->aux->id``), so it can be recorded or correlated
+ with later events;
+- ``verdict == BPF_SIG_VERIFIED`` *here* means **fully** verified - a program
+ that used a map the signature does not cover was already rejected, so it cannot
+ reach this point;
+- it observes only programs that actually loaded; a failed load never mints an
+ fd, so it never reaches this hook.
+
+It takes only the ``prog`` and a non-zero return still aborts (the fd is not
+handed out), so it can veto as well as observe. One wrinkle: it also fires on
+other paths that mint a new program fd - notably ``bpf_prog_get_fd_by_id()`` -
+not just on a fresh load. Because the program already has its id here, an LSM
+can tell the two apart with a small hash map: the *first* time an id is seen is
+the load; a later sighting of the same id is just another fd to a program that
+already exists.
+
+To bound the map and let a reused id read as a fresh load, this can be paired
+with ``security_bpf_prog_free()`` (``lsm/bpf_prog_free``), which deletes the
+entry on teardown - keyed by the same ``prog`` pointer, since
+``bpf_prog_free_id()`` has already cleared ``prog->aux->id`` to ``0`` by the time
+that hook runs. (Illustrative - privileged LSM, error checking elided.)
+
+.. code-block:: c
+
+ struct rec { __u32 id, ktype; __s32 serial; };
+
+ struct {
+ __uint(type, BPF_MAP_TYPE_HASH);
+ __type(key, __u64); /* struct bpf_prog * -- stable id */
+ __type(value, struct rec);
+ __uint(max_entries, 4096);
+ } live SEC(".maps");
+
+ SEC("lsm/bpf_prog") /* fires after load and on every later fd */
+ int BPF_PROG(observe, struct bpf_prog *prog)
+ {
+ __u64 key = (__u64)(unsigned long)prog;
+ struct rec r;
+
+ if (prog->aux->sig.verdict != BPF_SIG_VERIFIED)
+ return 0;
+ if (bpf_map_lookup_elem(&live, &key))
+ return 0; /* seen before: a later fd, not a load */
+
+ /* First sighting == this program just loaded; id is valid here. */
+ r.id = prog->aux->id;
+ r.ktype = prog->aux->sig.keyring_type;
+ r.serial = prog->aux->sig.keyring_serial;
+ bpf_map_update_elem(&live, &key, &r, BPF_NOEXIST);
+ /* ... newly-loaded verified-program action, e.g. record r.id ... */
+ return 0;
+ }
+
+Putting them together: to *require* verified BPF, deny at the admission hook
+unless the verdict is ``BPF_SIG_VERIFIED`` (and, if desired, restrict the
+keyring). The kernel then guarantees that any program which actually loads with
+that verdict covered all of its exclusive maps, rejecting any that did not - so
+a deny-by-default admission policy needs no second enforcement point. Use
+``security_bpf_prog()`` to record or finally gate the verified programs once
+they carry an id. The ``verdict``, ``keyring_type`` and ``keyring_serial`` fields
+let a policy distinguish, for example, "verified and signed by a builtin key"
+from "verified by a user key". A policy LSM such as IPE could consume the same
+hooks to enforce system policy without writing any BPF, though none implements
+this today.
+
+Keyrings
+========
+
+``keyring_id`` selects the trusted keyring the PKCS#7 signature is verified
+against. The well-known ids ``0`` (builtin), ``VERIFY_USE_SECONDARY_KEYRING``
+and ``VERIFY_USE_PLATFORM_KEYRING`` select the corresponding system keyrings;
+any other value is treated as the serial of a user/session key or keyring.
+The keyring is looked up first, before the signature bytes are examined, so a
+signature naming a non-existent keyring is rejected up front, and a failed
+verification aborts the load - so a program that loads successfully with a
+signature always has consistent keyring fields recorded.
+
+Two fields are recorded in ``prog->aux->sig`` for an LSM to inspect:
+
+``keyring_type`` (``enum bpf_sig_keyring``)
+ Classified purely from ``keyring_id`` whenever the program is signed:
+ ``BPF_SIG_KEYRING_BUILTIN``, ``_SECONDARY``, ``_PLATFORM`` for the system
+ keyrings, or ``_USER`` for a user/session keyring. It is
+ ``BPF_SIG_KEYRING_NONE`` for an unsigned program.
+
+``keyring_serial`` (``s32``)
+ Set **only** on a successful verification, to the serial of the
+ **user/session key or keyring** that ``keyring_id`` resolved to - the
+ object the signature was verified against, not the individual asymmetric
+ key inside it that matched the signer. Passing
+ ``KEY_SPEC_SESSION_KEYRING``, for example, records the session keyring's
+ serial. The system keyrings are trusted as a whole and expose no serial
+ here, so the serial is ``0`` for builtin, secondary and platform
+ signatures, and ``0`` for unsigned programs. In other words, a non-zero
+ ``keyring_serial`` is exactly "verified against the user key/keyring with
+ this serial".
+
+.. list-table::
+ :header-rows: 1
+
+ * - ``keyring_id``
+ - ``keyring_type``
+ - ``keyring_serial``
+ * - (no signature)
+ - ``BPF_SIG_KEYRING_NONE``
+ - ``0``
+ * - ``0``
+ - ``BPF_SIG_KEYRING_BUILTIN``
+ - ``0``
+ * - ``VERIFY_USE_SECONDARY_KEYRING``
+ - ``BPF_SIG_KEYRING_SECONDARY``
+ - ``0``
+ * - ``VERIFY_USE_PLATFORM_KEYRING``
+ - ``BPF_SIG_KEYRING_PLATFORM``
+ - ``0``
+ * - other (a user/session key serial)
+ - ``BPF_SIG_KEYRING_USER``
+ - serial of the resolved key/keyring
+
+Producing a signed object
+==========================
+
+``bpftool`` generates and signs a light skeleton in one step::
+
+ bpftool gen skeleton -L -S -k <private_key.pem> -i <certificate.x509> \
+ obj.bpf.o > obj.lskel.h
+
+``-L`` selects the light-skeleton (``gen_loader``) backend and ``-S`` enables
+signing; ``-k`` and ``-i`` supply the signing key and its X.509 certificate.
+``bpftool`` signs ``insns || metadata`` - the exact bytes the kernel
+reconstructs - and also computes ``excl_prog_hash`` as the digest of the loader
+instructions so the metadata map can be bound to the loader. The signature and
+hash are embedded in the generated header; the certificate is used only for
+signing and is not included. Loading the skeleton performs the
+create/populate/freeze/load sequence described above.
+
+At runtime the trusted public key must be present in the chosen keyring (for
+example added to the session keyring, or built into the kernel's builtin trusted
+keyring) for verification to succeed.
+
+UAPI reference
+==============
+
+``BPF_PROG_LOAD`` (``union bpf_attr``):
+
+``signature``, ``signature_size``
+ Pointer to and length of the PKCS#7 signature blob.
+
+``keyring_id``
+ Trusted keyring selector (see `Keyrings`_).
+
+``fd_array``, ``fd_array_cnt``
+ Array of map (and module BTF) file descriptors bound to the program.
+ ``fd_array_cnt`` must be set for the kernel to scan the array. When a
+ signature is present, a BTF entry is rejected outright, and every map must
+ be exclusive; its frozen contents are folded into the verified buffer, and
+ a non-exclusive entry is rejected.
+
+``BPF_MAP_CREATE`` (``union bpf_attr``):
+
+``excl_prog_hash``, ``excl_prog_hash_size``
+ SHA-256 digest of the program permitted to access this (exclusive) map. This
+ binds the metadata map to the loader; it is not a hash of the map *content*.
+ The map content is not hashed separately at all - it is covered, as bytes,
+ by the program signature.
+
+Notes and limitations
+======================
+
+- The instructions plus folded metadata are verified as one ``bpf_dynptr``,
+ which bounds the combined size (currently ~16 MiB); very large objects can
+ exceed it.
+- The metadata container is a single-element array map, accessed through
+ ``map_direct_value_addr``.
diff --git a/Documentation/core-api/mm-api.rst b/Documentation/core-api/mm-api.rst
index 4df7d5edbee5..c1d03a5a2a19 100644
--- a/Documentation/core-api/mm-api.rst
+++ b/Documentation/core-api/mm-api.rst
@@ -118,7 +118,7 @@ More Memory Management Functions
.. #kernel-doc:: mm/hmm.c (build warnings)
.. kernel-doc:: mm/memremap.c
.. kernel-doc:: mm/hugetlb.c
-.. kernel-doc:: mm/swap.c
+.. kernel-doc:: mm/folio.c
.. kernel-doc:: mm/memcontrol.c
.. #kernel-doc:: mm/memory-tiers.c (build warnings)
.. kernel-doc:: mm/shmem.c
diff --git a/Documentation/core-api/workqueue.rst b/Documentation/core-api/workqueue.rst
index 411e1b28b8de..bb770f556568 100644
--- a/Documentation/core-api/workqueue.rst
+++ b/Documentation/core-api/workqueue.rst
@@ -356,7 +356,7 @@ Guidelines
well under the default limit.
* A wq serves as a domain for forward progress guarantee
- (``WQ_MEM_RECLAIM``, flush and work item attributes. Work items
+ (``WQ_MEM_RECLAIM``), flush and work item attributes. Work items
which are not involved in memory reclaim and don't need to be
flushed as a part of a group of work items, and don't require any
special attribute, can use one of the system wq. There is no
diff --git a/Documentation/devicetree/bindings/arm/qcom.yaml b/Documentation/devicetree/bindings/arm/qcom.yaml
index 9df4074bb582..cd53e8726a48 100644
--- a/Documentation/devicetree/bindings/arm/qcom.yaml
+++ b/Documentation/devicetree/bindings/arm/qcom.yaml
@@ -56,6 +56,11 @@ properties:
- const: qcom,apq8084
- items:
+ - const: qcom,eliza-cqs-evk
+ - const: qcom,eliza-cqs-som
+ - const: qcom,eliza
+
+ - items:
- enum:
- sony,karin_windy
- const: qcom,apq8094
@@ -187,6 +192,7 @@ properties:
- microsoft,makepeace
- microsoft,moneypenny
- motorola,falcon
+ - motorola,titan
- samsung,ms013g
- samsung,s3ve3g
- const: qcom,msm8226
@@ -967,6 +973,24 @@ properties:
- items:
- enum:
+ - qcom,shikra-cqm-evk
+ - const: qcom,shikra-cqm-som
+ - const: qcom,shikra
+
+ - items:
+ - enum:
+ - qcom,shikra-cqs-evk
+ - const: qcom,shikra-cqs-som
+ - const: qcom,shikra
+
+ - items:
+ - enum:
+ - qcom,shikra-iqs-evk
+ - const: qcom,shikra-iqs-som
+ - const: qcom,shikra
+
+ - items:
+ - enum:
- qcom,sdx55-mtp
- qcom,sdx55-telit-fn980-tlb
- qcom,sdx55-t55
@@ -1054,6 +1078,7 @@ properties:
- enum:
- motorola,dubai
- nothing,spacewar
+ - xiaomi,taoyao
- const: qcom,sm7325
- items:
@@ -1166,6 +1191,7 @@ properties:
- dell,inspiron-14-plus-7441
- dell,latitude-7455
- dell,xps13-9345
+ - honor,magicbook-art-14-snapdragon
- hp,elitebook-ultra-g1q
- hp,omnibook-x14
- lenovo,ideacentre-mini-01q8x10
diff --git a/Documentation/devicetree/bindings/cache/qcom,llcc.yaml b/Documentation/devicetree/bindings/cache/qcom,llcc.yaml
index 34e3a2d78592..a1340226a0d0 100644
--- a/Documentation/devicetree/bindings/cache/qcom,llcc.yaml
+++ b/Documentation/devicetree/bindings/cache/qcom,llcc.yaml
@@ -19,35 +19,40 @@ description: |
properties:
compatible:
- enum:
- - qcom,eliza-llcc
- - qcom,glymur-llcc
- - qcom,hawi-llcc
- - qcom,ipq5424-llcc
- - qcom,kaanapali-llcc
- - qcom,qcs615-llcc
- - qcom,qcs8300-llcc
- - qcom,qdu1000-llcc
- - qcom,sa8775p-llcc
- - qcom,sar1130p-llcc
- - qcom,sar2130p-llcc
- - qcom,sc7180-llcc
- - qcom,sc7280-llcc
- - qcom,sc8180x-llcc
- - qcom,sc8280xp-llcc
- - qcom,sdm670-llcc
- - qcom,sdm845-llcc
- - qcom,shikra-llcc
- - qcom,sm6350-llcc
- - qcom,sm7150-llcc
- - qcom,sm8150-llcc
- - qcom,sm8250-llcc
- - qcom,sm8350-llcc
- - qcom,sm8450-llcc
- - qcom,sm8550-llcc
- - qcom,sm8650-llcc
- - qcom,sm8750-llcc
- - qcom,x1e80100-llcc
+ oneOf:
+ - enum:
+ - qcom,eliza-llcc
+ - qcom,glymur-llcc
+ - qcom,hawi-llcc
+ - qcom,ipq5424-llcc
+ - qcom,kaanapali-llcc
+ - qcom,qcs615-llcc
+ - qcom,qcs8300-llcc
+ - qcom,qdu1000-llcc
+ - qcom,sa8775p-llcc
+ - qcom,sar1130p-llcc
+ - qcom,sar2130p-llcc
+ - qcom,sc7180-llcc
+ - qcom,sc7280-llcc
+ - qcom,sc8180x-llcc
+ - qcom,sc8280xp-llcc
+ - qcom,sdm670-llcc
+ - qcom,sdm845-llcc
+ - qcom,shikra-llcc
+ - qcom,sm6350-llcc
+ - qcom,sm7150-llcc
+ - qcom,sm8150-llcc
+ - qcom,sm8250-llcc
+ - qcom,sm8350-llcc
+ - qcom,sm8450-llcc
+ - qcom,sm8550-llcc
+ - qcom,sm8650-llcc
+ - qcom,sm8750-llcc
+ - qcom,x1e80100-llcc
+ - items:
+ - enum:
+ - qcom,maili-llcc
+ - const: qcom,hawi-llcc
reg:
minItems: 1
diff --git a/Documentation/devicetree/bindings/clock/qcom,rpmcc.yaml b/Documentation/devicetree/bindings/clock/qcom,rpmcc.yaml
index b6c835bfd0d9..17332aa55886 100644
--- a/Documentation/devicetree/bindings/clock/qcom,rpmcc.yaml
+++ b/Documentation/devicetree/bindings/clock/qcom,rpmcc.yaml
@@ -21,35 +21,41 @@ description: |
properties:
compatible:
- items:
- - enum:
- - qcom,rpmcc-apq8060
- - qcom,rpmcc-apq8064
- - qcom,rpmcc-ipq806x
- - qcom,rpmcc-mdm9607
- - qcom,rpmcc-msm8226
- - qcom,rpmcc-msm8660
- - qcom,rpmcc-msm8909
- - qcom,rpmcc-msm8916
- - qcom,rpmcc-msm8917
- - qcom,rpmcc-msm8936
- - qcom,rpmcc-msm8937
- - qcom,rpmcc-msm8940
- - qcom,rpmcc-msm8953
- - qcom,rpmcc-msm8974
- - qcom,rpmcc-msm8976
- - qcom,rpmcc-msm8992
- - qcom,rpmcc-msm8994
- - qcom,rpmcc-msm8996
- - qcom,rpmcc-msm8998
- - qcom,rpmcc-qcm2290
- - qcom,rpmcc-qcs404
- - qcom,rpmcc-sdm429
- - qcom,rpmcc-sdm660
- - qcom,rpmcc-sm6115
- - qcom,rpmcc-sm6125
- - qcom,rpmcc-sm6375
- - const: qcom,rpmcc
+ oneOf:
+ - items:
+ - enum:
+ - qcom,rpmcc-apq8060
+ - qcom,rpmcc-apq8064
+ - qcom,rpmcc-ipq806x
+ - qcom,rpmcc-mdm9607
+ - qcom,rpmcc-msm8226
+ - qcom,rpmcc-msm8660
+ - qcom,rpmcc-msm8909
+ - qcom,rpmcc-msm8916
+ - qcom,rpmcc-msm8917
+ - qcom,rpmcc-msm8936
+ - qcom,rpmcc-msm8937
+ - qcom,rpmcc-msm8940
+ - qcom,rpmcc-msm8953
+ - qcom,rpmcc-msm8974
+ - qcom,rpmcc-msm8976
+ - qcom,rpmcc-msm8992
+ - qcom,rpmcc-msm8994
+ - qcom,rpmcc-msm8996
+ - qcom,rpmcc-msm8998
+ - qcom,rpmcc-qcm2290
+ - qcom,rpmcc-qcs404
+ - qcom,rpmcc-sdm429
+ - qcom,rpmcc-sdm660
+ - qcom,rpmcc-sm6115
+ - qcom,rpmcc-sm6125
+ - qcom,rpmcc-sm6375
+ - const: qcom,rpmcc
+ - items:
+ - enum:
+ - qcom,rpmcc-shikra
+ - const: qcom,rpmcc-qcm2290
+ - const: qcom,rpmcc
'#clock-cells':
const: 1
@@ -126,6 +132,7 @@ allOf:
- qcom,rpmcc-qcs404
- qcom,rpmcc-sdm429
- qcom,rpmcc-sdm660
+ - qcom,rpmcc-shikra
- qcom,rpmcc-sm6115
- qcom,rpmcc-sm6125
diff --git a/Documentation/devicetree/bindings/clock/qcom,shikra-gcc.yaml b/Documentation/devicetree/bindings/clock/qcom,shikra-gcc.yaml
new file mode 100644
index 000000000000..da6eebfa84c2
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/qcom,shikra-gcc.yaml
@@ -0,0 +1,70 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/qcom,shikra-gcc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Global Clock & Reset Controller on Qualcomm Shikra SoC
+
+maintainers:
+ - Imran Shaik <imran.shaik@oss.qualcomm.com>
+ - Taniya Das <taniya.das@oss.qualcomm.com>
+
+description: |
+ Global clock control module provides the clocks, resets and power
+ domains on Qualcomm Shikra SoC platform.
+
+ See also: include/dt-bindings/clock/qcom,shikra-gcc.h
+
+properties:
+ compatible:
+ const: qcom,shikra-gcc
+
+ clocks:
+ items:
+ - description: Board XO source
+ - description: Sleep clock source
+ - description: EMAC0 sgmiiphy mac rclk source
+ - description: EMAC0 sgmiiphy mac tclk source
+ - description: EMAC1 sgmiiphy mac rclk source
+ - description: EMAC1 sgmiiphy mac tclk source
+ - description: PCIE Pipe clock source
+ - description: USB3 phy wrapper pipe clock source
+
+ power-domains:
+ items:
+ - description: CX domain
+
+required:
+ - compatible
+ - clocks
+ - power-domains
+ - '#power-domain-cells'
+
+allOf:
+ - $ref: qcom,gcc.yaml#
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/qcom,rpmcc.h>
+ #include <dt-bindings/power/qcom-rpmpd.h>
+ clock-controller@1400000 {
+ compatible = "qcom,shikra-gcc";
+ reg = <0x01400000 0x1f0000>;
+ clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>,
+ <&sleep_clk>,
+ <&emac0_sgmiiphy_rclk>,
+ <&emac0_sgmiiphy_tclk>,
+ <&emac1_sgmiiphy_rclk>,
+ <&emac1_sgmiiphy_tclk>,
+ <&pcie_pipe_clk>,
+ <&usb3_phy_wrapper_gcc_usb30_pipe_clk>;
+ power-domains = <&rpmpd RPMPD_VDDCX>;
+ #clock-cells = <1>;
+ #power-domain-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/firmware/qcom,scm.yaml b/Documentation/devicetree/bindings/firmware/qcom,scm.yaml
index 25f62bacbc91..f344d1390b1b 100644
--- a/Documentation/devicetree/bindings/firmware/qcom,scm.yaml
+++ b/Documentation/devicetree/bindings/firmware/qcom,scm.yaml
@@ -37,6 +37,7 @@ properties:
- qcom,scm-ipq9574
- qcom,scm-ipq9650
- qcom,scm-kaanapali
+ - qcom,scm-maili
- qcom,scm-mdm9607
- qcom,scm-milos
- qcom,scm-msm8226
@@ -212,6 +213,7 @@ allOf:
- qcom,scm-eliza
- qcom,scm-hawi
- qcom,scm-kaanapali
+ - qcom,scm-maili
- qcom,scm-milos
- qcom,scm-sm8450
- qcom,scm-sm8550
diff --git a/Documentation/devicetree/bindings/iio/adc/mediatek,mt6359-auxadc.yaml b/Documentation/devicetree/bindings/iio/adc/mediatek,mt6359-auxadc.yaml
index 9936aa605c7b..c2f7387e4bfc 100644
--- a/Documentation/devicetree/bindings/iio/adc/mediatek,mt6359-auxadc.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/mediatek,mt6359-auxadc.yaml
@@ -4,7 +4,7 @@
$id: http://devicetree.org/schemas/iio/adc/mediatek,mt6359-auxadc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
-title: MediaTek MT6350 series PMIC AUXADC
+title: MediaTek MT6350 series and similar PMIC AUXADC
maintainers:
- AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
@@ -20,6 +20,7 @@ properties:
compatible:
oneOf:
- enum:
+ - mediatek,mt6323-auxadc
- mediatek,mt6357-auxadc
- mediatek,mt6358-auxadc
- mediatek,mt6359-auxadc
diff --git a/Documentation/devicetree/bindings/iio/adc/xlnx,versal-sysmon.yaml b/Documentation/devicetree/bindings/iio/adc/xlnx,versal-sysmon.yaml
new file mode 100644
index 000000000000..1ad58e3d6163
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/xlnx,versal-sysmon.yaml
@@ -0,0 +1,154 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) 2022 - 2026, Advanced Micro Devices, Inc.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/adc/xlnx,versal-sysmon.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: AMD/Xilinx Versal System Monitor
+
+maintainers:
+ - Salih Erim <salih.erim@amd.com>
+
+description:
+ The AMD/Xilinx Versal System Monitor (SysMon) is the successor to the
+ Zynq UltraScale+ AMS block. It provides on-chip voltage and temperature
+ monitoring with up to 160 voltage measurement points and up to
+ 64 temperature satellites distributed across the SoC. The hardware
+ supports configurable threshold alarms and oversampling. The device
+ can be accessed via memory-mapped I/O or via an I2C interface.
+
+properties:
+ compatible:
+ const: xlnx,versal-sysmon
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ '#io-channel-cells':
+ const: 1
+
+ voltage-channels:
+ type: object
+ description:
+ Container for voltage measurement channels.
+
+ properties:
+ '#address-cells':
+ const: 1
+
+ '#size-cells':
+ const: 0
+
+ patternProperties:
+ '^channel@([0-9a-f]|[1-9][0-9a-f])$':
+ $ref: adc.yaml
+
+ description:
+ Measures a voltage rail. The register index and rail
+ name are assigned by the hardware design tool (Vivado).
+
+ properties:
+ reg:
+ minimum: 0
+ maximum: 159
+ description:
+ Voltage measurement register index assigned by the hardware
+ design tool.
+
+ required:
+ - reg
+ - label
+
+ unevaluatedProperties: false
+
+ required:
+ - '#address-cells'
+ - '#size-cells'
+
+ additionalProperties: false
+
+ temperature-channels:
+ type: object
+ description:
+ Container for temperature satellite measurement channels.
+
+ properties:
+ '#address-cells':
+ const: 1
+
+ '#size-cells':
+ const: 0
+
+ patternProperties:
+ '^channel@([1-9a-f]|[1-3][0-9a-f]|40)$':
+ $ref: adc.yaml
+
+ description:
+ Reads a temperature satellite sensor. Each satellite monitors
+ a specific region of the SoC die.
+
+ properties:
+ reg:
+ minimum: 1
+ maximum: 64
+ description:
+ Temperature satellite number (1-based hardware index).
+
+ required:
+ - reg
+ - label
+
+ unevaluatedProperties: false
+
+ required:
+ - '#address-cells'
+ - '#size-cells'
+
+ additionalProperties: false
+
+required:
+ - compatible
+ - reg
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ sysmon@f1270000 {
+ compatible = "xlnx,versal-sysmon";
+ reg = <0xf1270000 0x4000>;
+ interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
+ #io-channel-cells = <1>;
+
+ voltage-channels {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ channel@0 {
+ reg = <0>;
+ label = "vccaux";
+ };
+
+ channel@3 {
+ reg = <3>;
+ label = "vcc_ram";
+ bipolar;
+ };
+ };
+
+ temperature-channels {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ channel@a {
+ reg = <10>;
+ label = "aie-temp-ch1";
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/iio/chemical/sensirion,scd30.yaml b/Documentation/devicetree/bindings/iio/chemical/sensirion,scd30.yaml
index a5b0debe85b1..25291bda1a8b 100644
--- a/Documentation/devicetree/bindings/iio/chemical/sensirion,scd30.yaml
+++ b/Documentation/devicetree/bindings/iio/chemical/sensirion,scd30.yaml
@@ -8,6 +8,7 @@ title: Sensirion SCD30 carbon dioxide sensor
maintainers:
- Maxwell Doose <m32285159@gmail.com>
+ - Tomasz Duszynski <tduszyns@gmail.com>
description: |
Air quality sensor capable of measuring co2 concentration, temperature
diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad3530r.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad3530r.yaml
index a355d52a9d64..2fe098619772 100644
--- a/Documentation/devicetree/bindings/iio/dac/adi,ad3530r.yaml
+++ b/Documentation/devicetree/bindings/iio/dac/adi,ad3530r.yaml
@@ -10,15 +10,17 @@ maintainers:
- Kim Seer Paller <kimseer.paller@analog.com>
description: |
- The AD3530/AD3530R (8-channel) and AD3531/AD3531R (4-channel) are low-power,
- 16-bit, buffered voltage output digital-to-analog converters (DACs) with
- software-programmable gain controls, providing full-scale output spans of 2.5V
- or 5V for reference voltages of 2.5V. These devices operate from a single 2.7V
- to 5.5V supply and are guaranteed monotonic by design. The "R" variants
- include a 2.5V, 5ppm/°C internal reference, which is disabled by default.
+ The AD3530/AD3530R (8-channel), AD3531/AD3531R (4-channel), and AD3532/AD3532R
+ (16-channel) are low-power, 16-bit, buffered voltage output digital-to-analog
+ converters (DACs) with software-programmable gain controls, providing
+ full-scale output spans of 2.5V or 5V for reference voltages of 2.5V. These
+ devices operate from a single 2.7V to 5.5V supply and are guaranteed monotonic
+ by design. The "R" variants include a 2.5V, 5ppm/°C internal reference, which
+ is disabled by default.
Datasheet can be found here:
https://www.analog.com/media/en/technical-documentation/data-sheets/ad3530_ad530r.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/ad3531-ad3531r.pdf
+ https://www.analog.com/media/en/technical-documentation/data-sheets/ad3532r.pdf
properties:
compatible:
@@ -27,6 +29,8 @@ properties:
- adi,ad3530r
- adi,ad3531
- adi,ad3531r
+ - adi,ad3532
+ - adi,ad3532r
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/leds/backlight/awinic,aw99706.yaml b/Documentation/devicetree/bindings/leds/backlight/awinic,aw99706.yaml
index f48ce7a3434d..60eae50ff742 100644
--- a/Documentation/devicetree/bindings/leds/backlight/awinic,aw99706.yaml
+++ b/Documentation/devicetree/bindings/leds/backlight/awinic,aw99706.yaml
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Awinic AW99706 6-channel WLED Backlight Driver
maintainers:
- - Junjie Cao <caojunjie650@gmail.com>
+ - Junjie Cao <junjie.cao@linux.dev>
allOf:
- $ref: common.yaml#
diff --git a/Documentation/devicetree/bindings/leds/backlight/silergy,sy7758.yaml b/Documentation/devicetree/bindings/leds/backlight/silergy,sy7758.yaml
new file mode 100644
index 000000000000..64af6b34641a
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/backlight/silergy,sy7758.yaml
@@ -0,0 +1,52 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/leds/backlight/silergy,sy7758.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Silergy SY7758 6-channel High Efficiency LED Driver
+
+maintainers:
+ - Neil Armstrong <neil.armstrong@linaro.org>
+
+description:
+ Silergy SY7758 is a high efficiency 6-channels LED backlight
+ driver with I2C brightness control.
+
+allOf:
+ - $ref: common.yaml#
+
+properties:
+ compatible:
+ const: silergy,sy7758
+
+ reg:
+ maxItems: 1
+
+ vdd-supply: true
+
+ enable-gpios:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - enable-gpios
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ backlight@11 {
+ compatible = "silergy,sy7758";
+ reg = <0x11>;
+ vdd-supply = <&bl_vdd>;
+ enable-gpios = <&gpio 16 GPIO_ACTIVE_HIGH>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/mfd/mediatek,mt8195-scpsys.yaml b/Documentation/devicetree/bindings/mfd/mediatek,mt8195-scpsys.yaml
index 4cafa381979b..9f073d0c28ef 100644
--- a/Documentation/devicetree/bindings/mfd/mediatek,mt8195-scpsys.yaml
+++ b/Documentation/devicetree/bindings/mfd/mediatek,mt8195-scpsys.yaml
@@ -26,6 +26,7 @@ properties:
- mediatek,mt8183-scpsys
- mediatek,mt8186-scpsys
- mediatek,mt8188-scpsys
+ - mediatek,mt8189-scpsys
- mediatek,mt8192-scpsys
- mediatek,mt8195-scpsys
- mediatek,mt8365-scpsys
diff --git a/Documentation/devicetree/bindings/pci/qcom,hawi-pcie.yaml b/Documentation/devicetree/bindings/pci/qcom,hawi-pcie.yaml
index 2c999ca6b205..aba89b599155 100644
--- a/Documentation/devicetree/bindings/pci/qcom,hawi-pcie.yaml
+++ b/Documentation/devicetree/bindings/pci/qcom,hawi-pcie.yaml
@@ -16,7 +16,12 @@ description:
properties:
compatible:
- const: qcom,hawi-pcie
+ oneOf:
+ - const: qcom,hawi-pcie
+ - items:
+ - enum:
+ - qcom,maili-pcie
+ - const: qcom,hawi-pcie
reg:
items:
diff --git a/Documentation/devicetree/bindings/serial/maxim,max310x.yaml b/Documentation/devicetree/bindings/serial/maxim,max310x.yaml
index 889eeaca64a0..e598dda4d13f 100644
--- a/Documentation/devicetree/bindings/serial/maxim,max310x.yaml
+++ b/Documentation/devicetree/bindings/serial/maxim,max310x.yaml
@@ -9,6 +9,13 @@ title: Maxim MAX310X Advanced Universal Asynchronous Receiver-Transmitter (UART)
maintainers:
- Hugo Villeneuve <hvilleneuve@dimonoff.com>
+description:
+ The MAX310X is a family of SPI/I2C UARTs with one (max3107, max3108),
+ two (max3109) or four (max14830) channels. Single-channel parts are
+ described as a serial node with RS-485 properties on the chip node;
+ multi-channel parts use one "serial@N" child node per channel, each
+ carrying its own serial/RS-485 properties.
+
properties:
compatible:
enum:
@@ -49,8 +56,55 @@ required:
allOf:
- $ref: /schemas/spi/spi-peripheral-props.yaml#
- - $ref: /schemas/serial/serial.yaml#
- - $ref: /schemas/serial/rs485.yaml#
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - maxim,max3107
+ - maxim,max3108
+ then:
+ allOf:
+ - $ref: /schemas/serial/serial.yaml#
+ - $ref: /schemas/serial/rs485.yaml#
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - maxim,max3109
+ - maxim,max14830
+ then:
+ properties:
+ "#address-cells":
+ const: 1
+ "#size-cells":
+ const: 0
+ patternProperties:
+ "^serial@[0-3]$":
+ type: object
+ description: A single UART channel of the chip.
+ allOf:
+ - $ref: /schemas/serial/serial.yaml#
+ - $ref: /schemas/serial/rs485.yaml#
+ properties:
+ reg:
+ description: UART channel number on the chip.
+ maximum: 3
+ required:
+ - reg
+ unevaluatedProperties: false
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: maxim,max3109
+ then:
+ patternProperties:
+ "^serial@[23]$": false
unevaluatedProperties: false
@@ -70,5 +124,39 @@ examples:
interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
gpio-controller;
#gpio-cells = <2>;
+ rs485-rts-active-low;
+ linux,rs485-enabled-at-boot-time;
+ };
+ };
+
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ serial@0 {
+ compatible = "maxim,max14830";
+ reg = <0>;
+ spi-max-frequency = <26000000>;
+ clocks = <&xtal4m>;
+ clock-names = "xtal";
+ interrupt-parent = <&gpio3>;
+ interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ serial@0 {
+ reg = <0>;
+ rs485-rts-active-low;
+ linux,rs485-enabled-at-boot-time;
+ };
+
+ serial@2 {
+ reg = <2>;
+ rs485-rts-active-low;
+ };
};
};
diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml
index 8eaa04431d74..9f9d9bcb66c4 100644
--- a/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml
+++ b/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml
@@ -29,6 +29,7 @@ properties:
- qcom,glymur-aoss-qmp
- qcom,hawi-aoss-qmp
- qcom,kaanapali-aoss-qmp
+ - qcom,maili-aoss-qmp
- qcom,milos-aoss-qmp
- qcom,qcs615-aoss-qmp
- qcom,qcs8300-aoss-qmp
diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml
index 2db4288a8a54..16ad4f5698fc 100644
--- a/Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml
+++ b/Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml
@@ -35,6 +35,7 @@ properties:
- items:
- enum:
- qcom,hawi-pmic-glink
+ - qcom,maili-pmic-glink
- const: qcom,kaanapali-pmic-glink
- const: qcom,pmic-glink
- items:
diff --git a/Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml b/Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml
index 76ce7e98c10f..5bd39876e3b3 100644
--- a/Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml
+++ b/Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml
@@ -94,19 +94,19 @@ properties:
reboot-mode:
$ref: /schemas/power/reset/syscon-reboot-mode.yaml
- type: object
+ unevaluatedProperties: false
description:
Reboot mode to alter bootloader behavior for the next boot
syscon-poweroff:
$ref: /schemas/power/reset/syscon-poweroff.yaml#
- type: object
+ unevaluatedProperties: false
description:
Node for power off method
syscon-reboot:
$ref: /schemas/power/reset/syscon-reboot.yaml#
- type: object
+ unevaluatedProperties: false
description:
Node for reboot method
@@ -181,8 +181,29 @@ allOf:
compatible:
contains:
enum:
+ - samsung,exynos7-pmu
+ then:
+ properties:
+ reboot-mode:
+ patternProperties:
+ # Negative look-ahead to disallow unsupported modes. The '$' has to be
+ # part of lookahead group to work, instead of trailing outside of ().
+ "^mode-(?!(bootloader$|download$|fastboot$|recovery$))": false
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
- google,gs101-pmu
then:
+ properties:
+ reboot-mode:
+ patternProperties:
+ # Negative look-ahead to disallow unsupported modes. The '$' has to be
+ # part of lookahead group to work, instead of trailing outside of ().
+ "^mode-(?!(bootloader$|charge$|dm-verity-device-corrupted$|fastboot$|reboot-ab-update$|recovery$)|rescue$|shutdown-thermal$|shutdown-thermal-battery$)": false
+
required:
- google,pmu-intr-gen-syscon
else:
diff --git a/Documentation/devicetree/bindings/sound/dmic-codec.yaml b/Documentation/devicetree/bindings/sound/dmic-codec.yaml
index cc3c84dd4c26..83c23e029ea4 100644
--- a/Documentation/devicetree/bindings/sound/dmic-codec.yaml
+++ b/Documentation/devicetree/bindings/sound/dmic-codec.yaml
@@ -39,6 +39,10 @@ properties:
wakeup-delay-ms:
description: Delay (in ms) after enabling the DMIC
+ port:
+ $ref: audio-graph-port.yaml#
+ unevaluatedProperties: false
+
required:
- compatible
diff --git a/Documentation/devicetree/bindings/sound/fsl,micfil.yaml b/Documentation/devicetree/bindings/sound/fsl,micfil.yaml
index c47b7a097490..4c7dadb310de 100644
--- a/Documentation/devicetree/bindings/sound/fsl,micfil.yaml
+++ b/Documentation/devicetree/bindings/sound/fsl,micfil.yaml
@@ -66,6 +66,10 @@ properties:
"#sound-dai-cells":
const: 0
+ port:
+ $ref: audio-graph-port.yaml#
+ unevaluatedProperties: false
+
required:
- compatible
- reg
diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml
index 2eed2277511f..4988e7ed6e34 100644
--- a/Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml
@@ -21,6 +21,7 @@ properties:
- qcom,sc8280xp-lpass-rx-macro
- items:
- enum:
+ - qcom,eliza-lpass-rx-macro
- qcom,kaanapali-lpass-rx-macro
- qcom,sm8650-lpass-rx-macro
- qcom,sm8750-lpass-rx-macro
diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-tx-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-tx-macro.yaml
index e5e65e226a02..d8682ff2e82c 100644
--- a/Documentation/devicetree/bindings/sound/qcom,lpass-tx-macro.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,lpass-tx-macro.yaml
@@ -21,6 +21,7 @@ properties:
- qcom,sc8280xp-lpass-tx-macro
- items:
- enum:
+ - qcom,eliza-lpass-tx-macro
- qcom,kaanapali-lpass-tx-macro
- qcom,sm8650-lpass-tx-macro
- qcom,sm8750-lpass-tx-macro
diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml
index 5c42b2b323ee..aea31fbdad37 100644
--- a/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml
@@ -21,6 +21,7 @@ properties:
- qcom,sc8280xp-lpass-va-macro
- items:
- enum:
+ - qcom,eliza-lpass-va-macro
- qcom,glymur-lpass-va-macro
- qcom,kaanapali-lpass-va-macro
- qcom,sm8650-lpass-va-macro
diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml
index d5f22b5cf021..9fedd80532e2 100644
--- a/Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml
@@ -20,6 +20,7 @@ properties:
- qcom,sc8280xp-lpass-wsa-macro
- items:
- enum:
+ - qcom,eliza-lpass-wsa-macro
- qcom,glymur-lpass-wsa-macro
- qcom,kaanapali-lpass-wsa-macro
- qcom,sm8650-lpass-wsa-macro
diff --git a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml
index 15f38622b98b..dae440ecab59 100644
--- a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml
@@ -23,6 +23,7 @@ properties:
- const: qcom,sdm845-sndcard
- items:
- enum:
+ - qcom,eliza-sndcard
- qcom,kaanapali-sndcard
- qcom,sm8550-sndcard
- qcom,sm8650-sndcard
diff --git a/Documentation/devicetree/bindings/sound/wlf,wm8524.yaml b/Documentation/devicetree/bindings/sound/wlf,wm8524.yaml
index 4d951ece394e..dffc41d5f7de 100644
--- a/Documentation/devicetree/bindings/sound/wlf,wm8524.yaml
+++ b/Documentation/devicetree/bindings/sound/wlf,wm8524.yaml
@@ -24,6 +24,10 @@ properties:
description:
a GPIO spec for the MUTE pin.
+ port:
+ $ref: audio-graph-port.yaml#
+ unevaluatedProperties: false
+
required:
- compatible
- wlf,mute-gpios
diff --git a/Documentation/devicetree/bindings/sram/sram.yaml b/Documentation/devicetree/bindings/sram/sram.yaml
index 5bf27c5f63e2..8f9b335c5a9d 100644
--- a/Documentation/devicetree/bindings/sram/sram.yaml
+++ b/Documentation/devicetree/bindings/sram/sram.yaml
@@ -38,6 +38,7 @@ properties:
- qcom,glymur-imem
- qcom,hawi-imem
- qcom,kaanapali-imem
+ - qcom,maili-imem
- qcom,milos-imem
- qcom,rpm-msg-ram
- rockchip,rk3288-pmu-sram
diff --git a/Documentation/devicetree/bindings/usb/qcom,snps-dwc3.yaml b/Documentation/devicetree/bindings/usb/qcom,snps-dwc3.yaml
index d99af9f413d0..c9dc5f302c4c 100644
--- a/Documentation/devicetree/bindings/usb/qcom,snps-dwc3.yaml
+++ b/Documentation/devicetree/bindings/usb/qcom,snps-dwc3.yaml
@@ -29,6 +29,7 @@ properties:
- qcom,glymur-dwc3-mp
- qcom,ipq4019-dwc3
- qcom,ipq5018-dwc3
+ - qcom,ipq5210-dwc3
- qcom,ipq5332-dwc3
- qcom,ipq5424-dwc3
- qcom,ipq6018-dwc3
@@ -203,6 +204,7 @@ allOf:
compatible:
contains:
enum:
+ - qcom,ipq5210-dwc3
- qcom,ipq5424-dwc3
- qcom,ipq9574-dwc3
- qcom,kaanapali-dwc3
@@ -497,6 +499,7 @@ allOf:
compatible:
contains:
enum:
+ - qcom,ipq5210-dwc3
- qcom,ipq5424-dwc3
- qcom,ipq9574-dwc3
then:
diff --git a/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml b/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml
index dc74e70f1b92..13715b7c94c8 100644
--- a/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml
+++ b/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml
@@ -27,6 +27,7 @@ properties:
- renesas,usbhs-r9a07g044 # RZ/G2{L,LC}
- renesas,usbhs-r9a07g054 # RZ/V2L
- renesas,usbhs-r9a08g045 # RZ/G3S
+ - renesas,usbhs-r9a08g046 # RZ/G3L
- renesas,usbhs-r9a09g047 # RZ/G3E
- renesas,usbhs-r9a09g056 # RZ/V2N
- renesas,usbhs-r9a09g057 # RZ/V2H(P)
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index 85a27937832e..eef5ed1a1e17 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -741,6 +741,8 @@ patternProperties:
description: Honestar Technologies Co., Ltd.
"^honeywell,.*":
description: Honeywell
+ "^honor,.*":
+ description: Honor Device Co., Ltd.
"^hoperf,.*":
description: Shenzhen Hope Microelectronics Co., Ltd.
"^hoperun,.*":
diff --git a/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml b/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml
index 845b5e8b5abc..b99e7913e398 100644
--- a/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml
+++ b/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml
@@ -19,6 +19,7 @@ properties:
- enum:
- apple,t6020-wdt
- apple,t8122-wdt
+ - apple,t8132-wdt
- const: apple,t8103-wdt
- items:
- enum:
diff --git a/Documentation/driver-api/media/maintainer-entry-profile.rst b/Documentation/driver-api/media/maintainer-entry-profile.rst
index c5c00c66d85c..7806d83128d4 100644
--- a/Documentation/driver-api/media/maintainer-entry-profile.rst
+++ b/Documentation/driver-api/media/maintainer-entry-profile.rst
@@ -432,6 +432,10 @@ The Media Driver Maintainers responsible for specific areas are:
- Qualcomm drivers
+ - Ricardo Ribalda <ribalda@chromium.org>
+
+ - Media-CI
+
Submit Checklist Addendum
-------------------------
diff --git a/Documentation/filesystems/proc.rst b/Documentation/filesystems/proc.rst
index 2ccd5b2dfdd3..27189f6e004e 100644
--- a/Documentation/filesystems/proc.rst
+++ b/Documentation/filesystems/proc.rst
@@ -608,6 +608,7 @@ encoded manner. The codes are the following:
um userfaultfd missing tracking
uw userfaultfd wr-protect tracking
ui userfaultfd minor fault
+ ur userfaultfd read-write-protect tracking
ss shadow/guarded control stack page
sl sealed
lf lock on fault pages
diff --git a/Documentation/gpu/intel-display/dp-link-capabilities.rst b/Documentation/gpu/intel-display/dp-link-capabilities.rst
new file mode 100644
index 000000000000..331cc69d13a0
--- /dev/null
+++ b/Documentation/gpu/intel-display/dp-link-capabilities.rst
@@ -0,0 +1,11 @@
+.. SPDX-License-Identifier: MIT
+.. Copyright © 2026 Intel Corporation
+
+DisplayPort Link Capabilities
+=============================
+
+.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+ :doc: DisplayPort link capabilities
+
+.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+ :internal:
diff --git a/Documentation/gpu/intel-display/index.rst b/Documentation/gpu/intel-display/index.rst
index 6fa929d82c38..e81f49bf20df 100644
--- a/Documentation/gpu/intel-display/index.rst
+++ b/Documentation/gpu/intel-display/index.rst
@@ -39,6 +39,7 @@ driver. The display driver isn't an independent driver in that sense.
frontbuffer
hotplug
dp-link-training
+ dp-link-capabilities
plane
psr
snps-phy
diff --git a/Documentation/leds/leds-st1202.rst b/Documentation/leds/leds-st1202.rst
index 1a09fbfcedcf..ed32eb3a27d4 100644
--- a/Documentation/leds/leds-st1202.rst
+++ b/Documentation/leds/leds-st1202.rst
@@ -16,8 +16,9 @@ in terms of PWM duty-cycle and duration (ms).
To be compatible with the hardware pattern format, maximum 8 tuples of
brightness (PWM) and duration must be written to hw_pattern.
+- Brightness range: 0-255
- Min pattern duration: 22 ms
-- Max pattern duration: 5660 ms
+- Max pattern duration: 5610 ms
The format of the hardware pattern values should be:
"brightness duration brightness duration ..."
@@ -26,9 +27,7 @@ The format of the hardware pattern values should be:
----------------------------
Specify a pattern repeat number, which is common for all channels.
-Default is 1; negative numbers and 0 are invalid.
+Default is 1. Writing 0 is invalid. Writing -1 or 255 repeats the
+pattern indefinitely.
This file will always return the originally written repeat number.
-
-When the 255 value is written to it, all patterns will repeat
-indefinitely.
diff --git a/Documentation/mm/page_owner.rst b/Documentation/mm/page_owner.rst
index 383e59c42743..a6bd3fe6423a 100644
--- a/Documentation/mm/page_owner.rst
+++ b/Documentation/mm/page_owner.rst
@@ -65,14 +65,15 @@ un-tracking state.
Usage
=====
-1) Build user-space helpers::
+1) Build user-space helpers:
+::
-To filter page_owner output:
+ To filter page_owner output:
cd tools/mm
make page_owner_filter
-To sort and analyze page_owner output:
+ To sort and analyze page_owner output:
cd tools/mm
make page_owner_sort
diff --git a/Documentation/sphinx-static/custom.css b/Documentation/sphinx-static/custom.css
index 5aa0a1ed9864..2e019c8f8a56 100644
--- a/Documentation/sphinx-static/custom.css
+++ b/Documentation/sphinx-static/custom.css
@@ -156,15 +156,6 @@ div.language-selection ul li:hover {
background: #dddddd;
}
-/*
- * Let long inline literals in paragraph text wrap as needed to prevent
- * overflow.
- */
-code.docutils.literal span.pre {
- white-space: normal;
- overflow-wrap: anywhere;
-}
-
/* Let rendered reference links in tables wrap when needed. */
div.body table.docutils a.reference {
overflow-wrap: anywhere;
diff --git a/MAINTAINERS b/MAINTAINERS
index 47cfe6531719..8729cea57c3d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4398,7 +4398,7 @@ S: Maintained
F: drivers/media/pci/hws/
AWINIC AW99706 WLED BACKLIGHT DRIVER
-M: Junjie Cao <caojunjie650@gmail.com>
+M: Junjie Cao <junjie.cao@linux.dev>
S: Maintained
F: Documentation/devicetree/bindings/leds/backlight/awinic,aw99706.yaml
F: drivers/video/backlight/aw99706.c
@@ -6220,6 +6220,7 @@ F: include/dt-bindings/sound/cs*
F: include/linux/mfd/cs42l43*
F: include/sound/cs*
F: sound/hda/codecs/cirrus*
+F: sound/hda/codecs/side-codecs/cirrus*
F: sound/hda/codecs/side-codecs/cs*
F: sound/hda/codecs/side-codecs/hda_component*
F: sound/soc/codecs/cs*
@@ -6862,6 +6863,13 @@ L: linux-riscv@lists.infradead.org
S: Maintained
F: drivers/cpuidle/cpuidle-riscv-sbi.c
+CPUIDLE DRIVER - S390
+M: Mete Durlu <meted@linux.ibm.com>
+L: linux-pm@vger.kernel.org
+L: linux-s390@vger.kernel.org
+S: Maintained
+F: drivers/cpuidle/cpuidle-s390.c
+
CPUMASK API [RUST]
M: Viresh Kumar <viresh.kumar@linaro.org>
R: Yury Norov <yury.norov@gmail.com>
@@ -16578,6 +16586,13 @@ S: Maintained
F: Documentation/devicetree/bindings/mmc/mtk-sd.yaml
F: drivers/mmc/host/mtk-sd.c
+MEDIATEK MT6323 PMIC AUXADC DRIVER
+M: Roman Vivchar <rva333@protonmail.com>
+L: linux-iio@vger.kernel.org
+S: Maintained
+F: drivers/iio/adc/mt6323-auxadc.c
+F: include/dt-bindings/iio/adc/mediatek,mt6323-auxadc.h
+
MEDIATEK MT6735 CLOCK & RESET DRIVERS
M: Yassine Oudjana <y.oudjana@protonmail.com>
L: linux-clk@vger.kernel.org
@@ -17109,7 +17124,7 @@ F: Documentation/admin-guide/mm/multigen_lru.rst
F: Documentation/mm/multigen_lru.rst
F: include/linux/mm_inline.h
F: include/linux/mmzone.h
-F: mm/swap.c
+F: mm/folio.c
F: mm/vmscan.c
F: mm/workingset.c
@@ -17261,7 +17276,6 @@ F: include/linux/swap.h
F: include/linux/swapfile.h
F: include/linux/swapops.h
F: mm/page_io.c
-F: mm/swap.c
F: mm/swap.h
F: mm/swap_table.h
F: mm/swap_state.c
@@ -17488,6 +17502,7 @@ F: arch/arm64/boot/dts/marvell/armada-3720-uDPU.*
MHI BUS
M: Manivannan Sadhasivam <mani@kernel.org>
+R: Jeff Hugo <jeff.hugo@oss.qualcomm.com>
L: mhi@lists.linux.dev
L: linux-arm-msm@vger.kernel.org
S: Maintained
@@ -22348,6 +22363,15 @@ F: Documentation/devicetree/bindings/media/*qcom*
F: drivers/media/platform/qcom
F: include/dt-bindings/media/*qcom*
+QUALCOMM PAS TZ SERVICE
+M: Sumit Garg <sumit.garg@oss.qualcomm.com>
+L: linux-arm-msm@vger.kernel.org
+S: Maintained
+F: drivers/firmware/qcom/qcom_pas.c
+F: drivers/firmware/qcom/qcom_pas.h
+F: drivers/firmware/qcom/qcom_pas_tee.c
+F: include/linux/firmware/qcom/qcom_pas.h
+
QUALCOMM SMB CHARGER DRIVER
M: Casey Connolly <casey.connolly@linaro.org>
L: linux-arm-msm@vger.kernel.org
@@ -23833,6 +23857,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux.git
F: Documentation/driver-api/s390-drivers.rst
F: Documentation/arch/s390/
F: arch/s390/
+F: drivers/cpuidle/cpuidle-s390.c
F: drivers/s390/
F: drivers/watchdog/diag288_wdt.c
@@ -24570,6 +24595,7 @@ F: drivers/iio/chemical/sunrise_co2.c
SENSIRION SCD30 CARBON DIOXIDE SENSOR DRIVER
M: Maxwell Doose <m32285159@gmail.com>
+M: Tomasz Duszynski <tduszyns@gmail.com>
S: Maintained
F: Documentation/devicetree/bindings/iio/chemical/sensirion,scd30.yaml
F: drivers/iio/chemical/scd30.h
@@ -25303,6 +25329,19 @@ T: git git://linuxtv.org/media.git
F: Documentation/devicetree/bindings/media/i2c/sony,imx415.yaml
F: drivers/media/i2c/imx415.c
+SONY IMX471 SENSOR DRIVER
+M: Kate Hsuan <hpa@redhat.com>
+L: linux-media@vger.kernel.org
+S: Maintained
+F: drivers/media/i2c/imx471.c
+
+SONY IMX678 SENSOR DRIVER
+M: Jai Luthra <jai.luthra@ideasonboard.com>
+L: linux-media@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/media/i2c/sony,imx678.yaml
+F: drivers/media/i2c/imx678.c
+
SONY MEMORYSTICK SUBSYSTEM
M: Maxim Levitsky <maximlevitsky@gmail.com>
M: Alex Dubov <oakad@yahoo.com>
@@ -29656,6 +29695,14 @@ F: Documentation/devicetree/bindings/memory-controllers/xlnx,versal-net-ddrmc5.y
F: drivers/edac/versalnet_edac.c
F: include/linux/cdx/edac_cdx_pcol.h
+XILINX VERSAL SYSMON DRIVER
+M: Salih Erim <salih.erim@amd.com>
+M: Sai Krishna Potthuri <sai.krishna.potthuri@amd.com>
+L: linux-iio@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/iio/adc/xlnx,versal-sysmon.yaml
+F: drivers/iio/adc/versal-sysmon*
+
XILINX WATCHDOG DRIVER
M: Srinivas Neeli <srinivas.neeli@amd.com>
R: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
diff --git a/Makefile b/Makefile
index c635e88fedf4..b06691841ff3 100644
--- a/Makefile
+++ b/Makefile
@@ -475,6 +475,10 @@ KBUILD_USERLDFLAGS := $(USERLDFLAGS)
# These flags apply to all Rust code in the tree, including the kernel and
# host programs.
+#
+# `-Aclippy::unwrap_or_default`: the lint is buggy [1] and ignores our
+# MSRV. It can trigger depending on the optimization level.
+# [1] https://github.com/rust-lang/rust-clippy/issues/17379
export rust_common_flags := --edition=2021 \
-Zbinary_dep_depinfo=y \
-Astable_features \
@@ -503,6 +507,7 @@ export rust_common_flags := --edition=2021 \
-Aclippy::uninlined_format_args \
-Wclippy::unnecessary_safety_comment \
-Wclippy::unnecessary_safety_doc \
+ -Aclippy::unwrap_or_default \
-Wrustdoc::missing_crate_level_docs \
-Wrustdoc::unescaped_backticks
diff --git a/Next/SHA1s b/Next/SHA1s
new file mode 100644
index 000000000000..6ba224473ffa
--- /dev/null
+++ b/Next/SHA1s
@@ -0,0 +1,429 @@
+Name SHA1
+---- ----
+origin a635d6748234582ea287c5ffeae28b9b23f91c7e
+ext4-fixes 981fcc5674e67158d24d23e841523eccba19d0e7
+vfs-brauner-fixes 24dddc384fb9aec2d7eea5463ca6dac98a3b3854
+fscrypt-current dc59e4fea9d83f03bad6bddf3fa2e52491777482
+fsverity-current dc59e4fea9d83f03bad6bddf3fa2e52491777482
+btrfs-fixes 6c893b948351d42cfc3761cc746ab5b3d03ee7f3
+vfs-fixes 49c5d168a3a8f4eb27d44a2a22b7e8a856ca601f
+erofs-fixes 95e19a4d8dd3072d51209081a29467d887c84158
+nfsd-fixes 92ea163c773cb4d0d5eaf103ed80c49d6758b96f
+v9fs-fixes 028ef9c96e96197026887c0f092424679298aae8
+overlayfs-fixes 4549871118cf616eecdd2d939f78e3b9e1dddc48
+fscrypt 2d0afaac9137e95e504bd3ad3512a9044745536b
+btrfs 0542d886e45d5b1ac54c37f5d303c71e8683471e
+ceph 1397040896280b7a6a6213e874ee4f6146bc9cd9
+cifs d2c46c9f7a9baf80a322eb1d4494a70e535b637c
+configfs 6363844fdbbb76afe1d44d678fe0746390204a5f
+ecryptfs 95ce5ffd54cf66098f91892f98606c3bd33846fe
+dlm e61113cfcaf71cbdf4c17e3d086d8fb7f92c62bf
+erofs dc59e4fea9d83f03bad6bddf3fa2e52491777482
+exfat 5362e7aedd113bb8b042e47e385103fe98274764
+ext3 f4d8f32d771d21ee6da8f20687fc3e23d26b9d34
+ext4 c143957520c6c9b5cd72e0de8b52b814f0c576fe
+f2fs dc59e4fea9d83f03bad6bddf3fa2e52491777482
+fsverity dc59e4fea9d83f03bad6bddf3fa2e52491777482
+fuse 7d87a5a284bb34edb3f4e7e312ef403b3385a7b7
+gfs2 5f80d9113360c08111ae7471f662f3f89f23ce32
+jfs dad98c5b2a05ef744af4c884c97066a3c8cdad61
+ksmbd b88458c8863782f06e187baeaff733a8e0ed41af
+nfs 8cdeaa50eae8dad34885515f62559ee83e7e8dda
+nfs-anna 27934d02cbeb8a957dd11c985a579e58d30c5270
+nfsd 26ddc8a26f00b67fd9b40e134f06ad269b46c1c7
+ntfs c02bbc2556708a0389a2b620fea231e5cfd37e0f
+ntfs3 dc59e4fea9d83f03bad6bddf3fa2e52491777482
+orangefs e61bc5e4d87433c8759e7dc92bb640ef71a8970c
+overlayfs 1f6ee9be92f8df85a8c9a5a78c20fd39c0c21a95
+ubifs 11efa98bcc0d00271e8f66c7c940c284f973f39d
+v9fs aa88278693cbfaf7a2acf961379973fbb63b165c
+v9fs-ericvh 028ef9c96e96197026887c0f092424679298aae8
+xfs f88caa121eac3b6a050262ac3de0c133ee17f7b2
+zonefs 3a8389d42bdf4213730f4067f8bfa78bae6564ef
+vfs-brauner b148f6ef8f3b0306ccff2644529a65ff19a11f03
+vfs 4dda01b67c8662c5d0c53034974cb8280c575a5d
+mm-hotfixes 198e0efeba02b65aa761df83a85890c6fae115a3
+fs-current ecb6a42490f8cf243399f971da4c3c5eaf5ee226
+kbuild-current dc59e4fea9d83f03bad6bddf3fa2e52491777482
+clang-fixes 175db11786bde9061db526bf1ac5107d915f5163
+arc-current 7aaa8047eafd0bd628065b15757d9b48c5f9c07d
+arm-current 009b6c6486b94a3aff566b017256b598dc96bf18
+arm64-fixes a52d6c7160f7e2f8c56adf29146385b8f2868d3d
+arm-soc-fixes 9c648f3554920721d8878807cd794fe2d7f989e8
+davinci-current dc59e4fea9d83f03bad6bddf3fa2e52491777482
+drivers-memory-fixes dc59e4fea9d83f03bad6bddf3fa2e52491777482
+sophgo-fixes 19272b37aa4f83ca52bdf9c16d5d81bdd1354494
+sophgo-soc-fixes 0af2f6be1b4281385b618cb86ad946eded089ac8
+m68k-current dc5200f6b1ada318463dd141b041ec9f044b2bf5
+powerpc-fixes 8cdeaa50eae8dad34885515f62559ee83e7e8dda
+s390-fixes 7d5c2f679147859c1db97d9f66366ff16909abee
+net 2c7c88a412aa6d09cd04b414211b4ef8553b5309
+bpf 7cbd0c4cebe4c9f678d15e6b9ba975e1155a107f
+ipsec f38f8cce2f7e79775b3db7e8a5eacda04ac908e4
+netfilter 2c7c88a412aa6d09cd04b414211b4ef8553b5309
+ipvs 60444706aa17616efc03190d099ac347e28b3d0a
+wireless cb8afea4655ff004fa7feee825d5c79783525383
+ath 55f3aa06951cac78b0206bde961c8cf11929a27a
+iwlwifi 093305d801fae6ff9b8bb531fd78b579794c4f80
+wpan 8ce4f287524c74a118b0af1eebd4b24a8efca57a
+rdma-fixes 3cda0dfe8c651dcbb9e38977905d3d3b1750c4ab
+sound-current 8ca0016a9b799d8366b32da7e729fcf56627516f
+sound-asoc-fixes 3238c634725afbb2a137fdda762208510828f71d
+regmap-fixes fabc5b59d3e647637dd71cdb94c96ac0fbecf632
+regulator-fixes d38f8bd771c4999b797d7074b348cf201414bd34
+spi-fixes c5fe48953568257c665ebec2b0d15174147acf6e
+pci-current 34db32102439d948e0c9aea060e48f979aae827d
+driver-core.current 667d0fb32149f023b8b34a1f6f3d384556eafb5a
+tty.current 22dd2777e6c180e1c945b00f6d18550979436324
+usb.current 6df47500b557e01737eef6f6b07b12f97a35d841
+usb-serial-fixes 6bfc8d01ac4068eced509f8fc74d0cd205e4dcec
+phy dc59e4fea9d83f03bad6bddf3fa2e52491777482
+staging.current 1463ca3ec6601cbb097d8d87dbf5dcf1cb86a344
+iio-fixes b7c969d0d445c415b8e9f32627d7e8f092c7e916
+watchdog-fixes 7362ba0f9c96ac3ad6a2ca3995bd9fc9a28a8661
+counter-current dc59e4fea9d83f03bad6bddf3fa2e52491777482
+char-misc.current 3585cfd4563731a8ae406b32807613c667c2b887
+soundwire-fixes dc59e4fea9d83f03bad6bddf3fa2e52491777482
+thunderbolt-fixes db79679595326fd3f6bd1e6fd0cefc3ba016039a
+input-current 536394ec81419b67d9f4f0028812c4372397be1b
+crypto-current 6ea0ce3a19f9c37a014099e2b0a46b27fa164564
+libcrypto-fixes dc59e4fea9d83f03bad6bddf3fa2e52491777482
+vfio-fixes e242e974e812e7a47e3088860c80d9492fac314f
+kselftest-fixes dc59e4fea9d83f03bad6bddf3fa2e52491777482
+dmaengine-fixes 867621ba203027338b525af6729719c544135336
+backlight-fixes dc59e4fea9d83f03bad6bddf3fa2e52491777482
+mtd-fixes 2b533e775aec580cf60074417f4ca00ac9cf3580
+mfd-fixes d5d2d7a8d8be18681a0864f58e3875f1c639e11c
+v4l-dvb-fixes dc59e4fea9d83f03bad6bddf3fa2e52491777482
+reset-fixes 71827776667f4e4677a4fa806bcfb24d4b8dd9d7
+mips-fixes 8cdeaa50eae8dad34885515f62559ee83e7e8dda
+at91-fixes 765aaba18413a66f6c8fe8416336ca9b3dd98a79
+omap-fixes dc59e4fea9d83f03bad6bddf3fa2e52491777482
+kvm-fixes 098e32cba334da0f3fa8cfd4e022ae7c72341400
+kvms390-fixes 3e3aa6da87d30a0064a17b836685cd43c90a3572
+kvm-arm-fixes 8d187d4b33c262c0f3e44842553521151d8629e8
+hwmon-fixes f151d0143ac4e086f92f52328ebdbdc50933d8ef
+nvdimm-fixes a8aec14230322ed8f1e8042b6d656c1631d41163
+cxl-fixes d90f236f8b9e354848bd226f581db27755ab901d
+dma-mapping-fixes dc59e4fea9d83f03bad6bddf3fa2e52491777482
+drivers-x86-fixes 2726b5758f80a546a4ddeec5019e72035a7fa166
+samsung-krzk-fixes dc59e4fea9d83f03bad6bddf3fa2e52491777482
+pinctrl-samsung-fixes dc59e4fea9d83f03bad6bddf3fa2e52491777482
+pinctrl-qcom-fixes 437a8d2aa1aa442c4a176fdf4700a9b3bb0c8794
+devicetree-fixes b39a6b2e9d5bd6a3153aed4c7440172b8f6a739e
+dt-krzk-fixes dc59e4fea9d83f03bad6bddf3fa2e52491777482
+scsi-fixes 5d5221f8a4064a256b9499485a9f8c6f530f21dc
+drm-fixes 6763a0aea6d658d69b9215ab9151d7bd4c1c314b
+drm-intel-fixes 3d04d9f390eeaab4d9e1ed4e9737e3d83581e18b
+mmc-fixes 86152fef52cac15cd662ed3bfc7604fbfef378f0
+rtc-fixes 254f49634ee16a731174d2ae34bc50bd5f45e731
+gnss-fixes 5d6919055dec134de3c40167a490f33c74c12581
+hyperv-fixes dc59e4fea9d83f03bad6bddf3fa2e52491777482
+risc-v-fixes a2ac823d8a228e392bc6a79ea63b550ab84a55b2
+riscv-dt-fixes 0df8aa2b9aec5cd21e8c71d9cc1227e57bea43b3
+riscv-soc-fixes 75ef233975589d9a8c88bc8822a7c725c71ff650
+fpga-fixes 19272b37aa4f83ca52bdf9c16d5d81bdd1354494
+spdx dc59e4fea9d83f03bad6bddf3fa2e52491777482
+gpio-brgl-fixes b11c513ad943f35cf5e8007d3a56279c79b7ed4b
+gpio-intel-fixes dc59e4fea9d83f03bad6bddf3fa2e52491777482
+pinctrl-intel-fixes dc59e4fea9d83f03bad6bddf3fa2e52491777482
+auxdisplay-fixes dc59e4fea9d83f03bad6bddf3fa2e52491777482
+kunit-fixes dc59e4fea9d83f03bad6bddf3fa2e52491777482
+memblock-fixes 2ebce860bdd7ae5e13002811bc9bbbf33fcfc221
+renesas-fixes 8a78d1c454b3cc7b66d52582474e8b3732833352
+perf-current 558ef39aeb9a089a6be9dda8413b0b9d42e843ea
+efi-fixes d8809f6931065cbbf3554647a50a65a471ab5983
+battery-fixes 254f49634ee16a731174d2ae34bc50bd5f45e731
+iommufd-fixes dc59e4fea9d83f03bad6bddf3fa2e52491777482
+rust-fixes 4688cf884b3abcd12498e03b625d1916bf49a1e4
+w1-fixes dc59e4fea9d83f03bad6bddf3fa2e52491777482
+pmdomain-fixes 25e252bcf1593b420b12a7231d9dd64b885a2ae2
+i2c-andi-fixes dc59e4fea9d83f03bad6bddf3fa2e52491777482
+i2c-rust-fixes 4eb422482ca5d924d7212ad2ca1cb7ea6f5b524d
+sparc-fixes 254f49634ee16a731174d2ae34bc50bd5f45e731
+clk-fixes 8cdeaa50eae8dad34885515f62559ee83e7e8dda
+thead-clk-fixes 8f0b4cce4481fb22653697cced8d0d04027cb1e8
+tenstorrent-clk-fixes 6de23f81a5e08be8fbf5e8d7e9febc72a5b5f27f
+fustini-config-fixes 254f49634ee16a731174d2ae34bc50bd5f45e731
+pwrseq-fixes dc59e4fea9d83f03bad6bddf3fa2e52491777482
+thead-dt-fixes 254f49634ee16a731174d2ae34bc50bd5f45e731
+ftrace-fixes 1650a1b6cb1ae6cb99bb4fce21b30ebdf9fc238e
+ring-buffer-fixes 057caace5214da3b457bbd295e1a2ad34d3685ea
+trace-fixes 05074bb90af94f2acbbc8f8ffaa507f914c273c8
+tracefs-fixes 07004a8c4b572171934390148ee48c4175c77eed
+spacemit-fixes eb525edd48907795c0d4e498ff57ad168070b289
+tip-fixes 5ec0167664ba2a25b1461eb7bc0166e4828772cd
+slab-fixes af9ea231c0b4530edc389a3126a69e0699b7699d
+kexec-fixes dc59e4fea9d83f03bad6bddf3fa2e52491777482
+liveupdate-fixes dc59e4fea9d83f03bad6bddf3fa2e52491777482
+drm-msm-fixes db339b6bc9f234b4883eb02946ea01d8d9faa11c
+uml-fixes 254f49634ee16a731174d2ae34bc50bd5f45e731
+fwctl-fixes 4549871118cf616eecdd2d939f78e3b9e1dddc48
+devsec-tsm-fixes c3fd16c3b98ed726294feab2f94f876290bf7b61
+drm-rust-fixes dc59e4fea9d83f03bad6bddf3fa2e52491777482
+tenstorrent-dt-fixes 6de23f81a5e08be8fbf5e8d7e9febc72a5b5f27f
+nfc-fixes e87faad807329d1348595dbcea3444acd7bb0ca6
+drm-misc-fixes cf385cf6e713eba0720651174dac0b2d2f5bb8f8
+rust dc59e4fea9d83f03bad6bddf3fa2e52491777482
+rust-interop 05f7e89ab9731565d8a62e3b5d1ec206485eeb0b
+rust-alloc dc59e4fea9d83f03bad6bddf3fa2e52491777482
+rust-io 86731a2a651e58953fc949573895f2fa6d456841
+rust-pin-init dc59e4fea9d83f03bad6bddf3fa2e52491777482
+rust-timekeeping ddb1444d3335129ae87d9796ab1debf41c0ee51b
+rust-xarray c455f19bbe6104debd980bb15515faf716bd81b8
+rust-analyzer 5f45afb8ab04d934fc0601a202f95267ebc20059
+mm-stable 0e35b9b6ec0ffcc5e23cbdec09f5c622ad532b53
+mm-nonmm-stable 0e35b9b6ec0ffcc5e23cbdec09f5c622ad532b53
+mm-unstable 4a6c88e10a0791d9c3b0677ce984365815c2ab4f
+mm-nonmm-unstable d9a23f527f674f3d6fe02028b7d769e87b1d240f
+kbuild fba1a1acb42c0bb4fd0da01faf7bbdb7cd3c979c
+clang-format 8f0b4cce4481fb22653697cced8d0d04027cb1e8
+perf 8c5f60344b07f839267c0c835962e2206143be85
+compiler-attributes 8f0b4cce4481fb22653697cced8d0d04027cb1e8
+dma-mapping dc59e4fea9d83f03bad6bddf3fa2e52491777482
+asm-generic adbbd9714f8058730f93c8df5c5bf1679456424b
+alpha d58041d2c63e09a1c9083e0e9f4151e487c4e16a
+arm 75ca78c7d982a0b7c658722fa9eb2ce70e180307
+arm64 36fa5ffa60344bcc59fb3f50b33af8187e6b8753
+arm-perf 5936245125f78d896fdb1bbc2ae79213e28a6579
+arm-soc 972ea78305bddb6a1db0586357914f125e913ffe
+amlogic 4336e970ec6890fbd424128c352564a9c1dd514a
+asahi-soc a23ce286383c90a828f6ab9f4154f4abf778cc32
+at91 6d892f8d5cd9f20cfef5e9d59b0cde53c30daec6
+bmc 40ae2e16214adcd59481a8d799af03be7b0f5e08
+broadcom f705b0c80bab155e9ffc6b796408ab16c9abf206
+cix a0cffbd8878c55b12dc4555f883adf3372cecd91
+davinci dc59e4fea9d83f03bad6bddf3fa2e52491777482
+drivers-memory 8111c7f3723f414b7f655a3880775cbbd0e9de8e
+fsl dc59e4fea9d83f03bad6bddf3fa2e52491777482
+imx-mxs 10e06b5bd4be88cc89375227c31467734f6658de
+mediatek 03168882793c8833e687325ce1facfd934b78715
+mvebu 3ea0dabfa4500104c5c6eebecfa4d23aeb847611
+omap ba251bb5ce2db9228a4c1ca9aef787c368121af7
+qcom 076bbf9ad4df1ac73f2b0363320869c7223de6ba
+renesas 30d3a7db7471001c926c20333e07e54749fd3572
+reset d373605cd514837d8a6de3d00c786d4bae6dbaf8
+rockchip f5ed1537219ae8bf55446232d331b114653a1475
+samsung-krzk cf776975e6d8a57dca424190be8fcc0f3c5c0f42
+scmi 2edd29cc765fe6ff312464f7dabc53a4673c1f67
+sophgo f7337210bede62fc7c6230ef58013dddf7e0a921
+sophgo-soc c8754c7deab4cbfa947fa2d656cbaf83771828ef
+spacemit eb525edd48907795c0d4e498ff57ad168070b289
+stm32 fba4a31a7f3b6b29b01c83180f83e7ed4c398738
+sunxi 36078904c9908a8ad674ef5b3d31cf8d90828e6a
+tee a3067938fd192b116b6dfb325b654300a6d1b461
+tegra 75767942c9895ac6e29b931dee9a2e79f9269dd4
+tenstorrent-dt 33583baeb1ba7d328e6a9775d889036900b74cdb
+fustini-config fd52109054693750f38d6fae134cffd1ac8c9c74
+thead-dt 3a5791956edbfa84d7256224167941931cbc46e7
+ti 1b98f483adfd99bf7008dc334ae72fc608d47a77
+xilinx b881149621b235b8bd556c407d7cd76f0eeb3954
+socfpga 39ea7cb4019245ce488ea547b3ec68a3d7d57aef
+clk 8cdeaa50eae8dad34885515f62559ee83e7e8dda
+clk-imx b3dcc8c608fbb6352bd94932ba935f2078c9090d
+clk-renesas 91fb4643954379f8493dba649d520c23f0d1f4e6
+thead-clk baf4fc7c03bd0f68c768cfe27829674bd060c6b4
+tenstorrent-clk 23c8ebc952849b3ba47d04d0ec95daf5cc136061
+csky abb81e5ce7d995baa41556b8125fa59e28ba3be8
+loongarch 262a3b4fa1792d40728c69995924e11cf761f5cf
+m68k dc5200f6b1ada318463dd141b041ec9f044b2bf5
+m68knommu 1b57914105506ad650ca72c74bfe60506fcaf8db
+microblaze 6de23f81a5e08be8fbf5e8d7e9febc72a5b5f27f
+mips 8cdeaa50eae8dad34885515f62559ee83e7e8dda
+openrisc aca063c9024522e4e5b9a9d1927433f6a01785a3
+parisc-hd dc59e4fea9d83f03bad6bddf3fa2e52491777482
+powerpc 8cdeaa50eae8dad34885515f62559ee83e7e8dda
+risc-v a2ac823d8a228e392bc6a79ea63b550ab84a55b2
+riscv-dt 82ab962ef6c2a3571e3d590b30c023118c92b776
+riscv-soc dfceff38cea2b80c6871459c30a8cb96fecc533b
+s390 d87e492ce6f446bd835b68377b71c59a47347e52
+sh b0aa5e4b087b686575f1b31ce54048b4d059b7b8
+sparc 5b2a3b1a98fb47c593144c2770e012d463952b70
+uml 254f49634ee16a731174d2ae34bc50bd5f45e731
+xtensa a7c958e8721eb2724ee2e2ef13129bc67e1c8a75
+fs-next 6565eb0f84455b0e9b240b454e0f11a098a76ba3
+printk 04a68c4b40960b5430b88eaf3ad2a33234f90c50
+pci 5d9f1dd3b3e7bd64ac7ddedf28fcb7db81053819
+pstore 24b8f8dcb9a139a36cf48bfbe935e8dc1f33ed79
+hid 194a48576843858afcd9c00ed4f105ec2b398e6c
+i2c 8cd9520d35a6c38db6567e97dd93b1f11f185dc6
+i2c-andi 04e9bf1648f846976b543e91c1838a712433772a
+i2c-rust c0260c740d20751c8498865a9c5dc18b69c3d267
+i3c eeedacd0866eec6e9dad2f082a5b828b895a5ed0
+dmi 1afafbaf749d8e8ec53f8e38efdc731131902b5b
+hwmon-staging a810e1aa11bf6f4fb1bfc2b94bc7541615379209
+jc_docs f4b990a286fdc2c5f7973f07e1998bdb978e9583
+v4l-dvb 38d9078f8bb3e07973fbc7152a1f6f1318fedee2
+v4l-dvb-next adc218676eef25575469234709c2d87185ca223a
+pm dc8bff6f7d6da011245f6d050e949e2174926009
+cpufreq-arm f456178290356167c7349d51432889113565d1ba
+cpupower dc59e4fea9d83f03bad6bddf3fa2e52491777482
+devfreq c096be11c2a9d4acca8e75f1f8edeb744aceb521
+pmdomain 567cf92d980543f2a71b4b480db478dfda0e490c
+opp dc59e4fea9d83f03bad6bddf3fa2e52491777482
+thermal 968098b4ca5219b0d2e0a981aed1dacfbd5adc69
+rdma b21d9bf627dd4162dd485f5f8d7d0fbdd71a175e
+net-next 832255a6df491b6bfa41e6458d097f269b680d77
+bpf-next b1d4514ff1f96ee83192e17d3db766d2e4ec77f7
+ipsec-next 355f808d8a11fa69b19dfd8811bc87d97830f5d6
+mlx5-next ddbddbf8aee54bee038149187270c93a45478473
+netfilter-next 08030ddb87b4c6c6a2c03c82731b5e188f02f5b9
+ipvs-next b73bc9ca3686b78b642fb35dcc1fdf874ecb74a1
+bluetooth ca75417ab1793f23b3ddc91869f0809b593d6954
+wireless-next ac798f757d6475dc6fee2ec899980d6740714596
+ath-next 913998f903fb1432c0046c33003db38a9e8bedb1
+iwlwifi-next a6136ca2dd9773d6bcd45e8290403536c9c71054
+wpan-next a6bfdfcc6711d1d5a92e98644359dedc67c0c858
+wpan-staging a6bfdfcc6711d1d5a92e98644359dedc67c0c858
+mtd d276783e490d73536135f90f96c5875f263481ab
+nand adfc275b317c02cd043b0cf28b8cfb7459b041f0
+spi-nor df415c5e1de0f1aeefacb4e6252ff98d38c04437
+crypto e264401ce4776a288524e5b87593d4d864147115
+libcrypto 1002500f54b5f60faa6a03636c7865fd4db53ad6
+drm e3cdab67efa8b1981620c792a845da91f75aaa63
+drm-exynos 3a8660878839faadb4f1a6dd72c3179c1df56787
+drm-misc 104c00917264c5b9571072471e3a8689cd1a2c4d
+amdgpu 5c6c247992d4d9200e073b83f4ec6c703c096845
+drm-intel 4fee95d4f88752c3facbc41f4d0994a074780744
+drm-msm 9a967125427e03c7ebc24d7ad26e9307e8403d4e
+drm-msm-lumag 8de061ca149c94871e41d91a5b2e442ecc26a572
+drm-xe 9cdcdadab543149c1417d22f5574cecbe5ba0702
+drm-rust d85845b64c0020b2812243a22fa79d57cc1c1e38
+drm-nova 93296e9d9528f0d87f2cf3fee494599060a0f14a
+etnaviv 6bde14ba5f7ef59e103ac317df6cc5ac4291ff4a
+fbdev dc59e4fea9d83f03bad6bddf3fa2e52491777482
+regmap 1c790e0326461809ac256c91402d61747f2143c9
+sound 75c4027e741db349bafd2f6f9983a5b9a53e173f
+ieee1394 dc59e4fea9d83f03bad6bddf3fa2e52491777482
+sound-asoc 8dfce4002fc1e720316bb931bc4beb7e525b6389
+modules 852fd31eb074f1fdaf05cd5ec60601d07cacb30a
+input c8f174900926d3b58cd048ac33b4cbb3de419bfe
+block 8285cd727ff80552e4809f89a6e8eeb460f42c90
+device-mapper 55c99f2d901c783c49dddd98f7c05d98ad834ce9
+libata e64e6b5dc86758c14ed28a6e85bf5d1b78146ed5
+pcmcia b3c26ea81ccc522e77ed0b1707add61fc9206216
+mmc df92d47b3ae7384588e9b54665d66d76273f9c4e
+mfd 6384e5c5e0bcfbc9a915d70cb3925e0022d7b337
+backlight 4b3f5baf67dea91452b5b114dcb19139feba71dd
+battery a888754e51e915731c8974c4d6d62709facb35d3
+regulator 6b65d28d91d78715345900747ca6a0003b8d82d4
+security 0cee720cfd51402cfcb14d96cb326a36c13b823a
+apparmor dda61023f976d7ab3bc7c8b46d26d6d23424f890
+integrity 81429cd0161ae654454c2b277a1db2c0ecb7712e
+selinux 9a66a80db12e234b286792dcc0d934a7e1f61dc0
+smack a7c44fd9f80e37763acf9cd3c87a58058d206427
+tomoyo 38fe7c9c3dcad3afce653b05b7f75d7431247d5d
+tpmdd-tpm 4ece5759c1a29fd711b7b1d1a3b81078547697fd
+tpmdd-keys 51cb1aa1250c36269474b8b6ca6b6319e170f5a5
+watchdog a182c680d77fe8f73927ed9eb637c03759a45c8f
+iommu 750356af88d6178156ce776df17c10a9035fcc9c
+audit 1715cd1303c703e73115e2f7bac7e01b9ca84049
+devicetree 4ec74681d93e8cb5b777b5d5cfd76e9685da0900
+dt-krzk dc59e4fea9d83f03bad6bddf3fa2e52491777482
+mailbox 36cac4b5101f8ecbc851356df175b99543c84ec6
+spi 5f1b513690edf51727e6928b97705b6437f9a98e
+tip c50d2a841739b51b1472b6028887790bbdc97a47
+kexec af78cec42d1b0113993e427139f0ab2f34b047ee
+liveupdate 57e2c35f4e7277a35026d553a35c0ac734a640c3
+clockevents a9ac745bc320cbdc2ed3c851eb78f91f22ff975b
+edac 17c8b40ef28bec9185204e8b1d70ac73c3dbf3ba
+ftrace 030bb1d8bb0773053df6518ed635f27005fd5e43
+rcu e853c1b28580ea93fda3cd729e440a3fc16fa647
+paulmck 48f7a50c027dd2abb9e7b8a6ecc8e531d87f2c21
+kvm a204badd8432f93b7e862e7dac6db0fe3d65f370
+kvm-arm 1ee27dacbe5dc4def481794d899d67b0d4570094
+kvms390 babe08404e1993697a523e60bc0f9d096ffe1ef8
+kvm-ppc 8cdeaa50eae8dad34885515f62559ee83e7e8dda
+kvm-riscv 52738352a6f29279e15285fcb7b50241ef867e27
+kvm-x86 f1e5ada5ab62dbe32350bc161771c9afc6a896de
+xen-tip fcd245ea7528d50fddffc0fd1308941a9180f5b3
+percpu 8f0b4cce4481fb22653697cced8d0d04027cb1e8
+workqueues dbff1ec23f68640a743512e8ada125795d1b72c7
+sched-ext a742176b8934435f32a0e1e477d726938291e196
+drivers-x86 62b57396c26a1ce54963709928ea0d01fa522eea
+chrome-platform d1ceb2b2324717fa30b44d56ef0c52813e239569
+chrome-platform-firmware dd06eb60e86a1ab6d3bd4f641100f47b6f7342b6
+hsi 254f49634ee16a731174d2ae34bc50bd5f45e731
+leds-lj 96fa4d69958cf90740d756d1e45cdb02cface41b
+ipmi 6d920a75df9a83ab096b3cde7a643b656e4fdfeb
+driver-core 5dcef303b29f004a447d9c69e62963328da9c608
+usb 0f1dabb7af982dae9325a005297785a792b51223
+thunderbolt d49d71ebec8f03eee2514304279a05a4952fadf7
+usb-serial dc59e4fea9d83f03bad6bddf3fa2e52491777482
+tty 9505146e885b1a842118aa6410f737290c4a5a32
+char-misc 9e32d2a9784736b3fc262f51ddda1141de753314
+coresight 98495b5a4d77dd22e106f462b76e1093a55b29a7
+fastrpc 17ec912dc87bf6b9aba3a85f6a94e99f999d6511
+fpga b5ba63e247075087ab8a6a087622c762dc4172e9
+icc e11872288b4b33c0e90da6987d6006bb49fecbc9
+iio 2e2f2de7532cbbc2269de8be20ec709606c6e79b
+nfc ed85d4cbbfaa4e630c5aa0d607348b42620d976b
+phy-next dc59e4fea9d83f03bad6bddf3fa2e52491777482
+soundwire 90af3209742db61a7f9d7d054a16165818cfc6d8
+extcon 254f49634ee16a731174d2ae34bc50bd5f45e731
+gnss 5d6919055dec134de3c40167a490f33c74c12581
+vfio 785562e31dbcd85ca583cf58c446e63aa8a5af08
+w1 169ae5e65e5aaf213b6a578f6478a9fd2e523606
+spmi 8cdeaa50eae8dad34885515f62559ee83e7e8dda
+staging b46e70613266e52adc412f92de7504cd14804f6d
+counter-next dc59e4fea9d83f03bad6bddf3fa2e52491777482
+mux 59b723cd2adbac2a34fc8e12c74ae26ae45bf230
+dmaengine 0d3e3376b289cdaff5b3b6c1581999926ff1000f
+cgroup 37f35256008bb5c31804cf1baf226ba0c111d6e1
+scsi cf1af0ccca54d5547cc31bf476c6a07cf658ad29
+scsi-mkp 57a6ed0b41677ccc5e28cc0976e495c1dfa33747
+vhost 1f673033c02735bb38ee2f16f1c86f042f4de9d4
+rpmsg 066e0d00bee1331abd2b2ee51ce4b32a0db1b969
+gpio-brgl 611fd6cfe13997245f1f1b59b81e957163491773
+gpio-intel dc59e4fea9d83f03bad6bddf3fa2e52491777482
+pinctrl 94cb9e8f270797e489633cfa53d2d44afecb8bef
+pinctrl-intel ed1608d5e3c4432c1dcba709668b90f44228c10c
+pinctrl-renesas 5a653cedec948423fc8a0180c90b8d05c2239d9d
+pinctrl-samsung dc59e4fea9d83f03bad6bddf3fa2e52491777482
+pinctrl-qcom 77fbc756d9cbe53a9496cb2c53ae209d37d5af2d
+pwm 0062b71a3e5464a4ec0e8c8fd0034413ca90e45d
+ktest 932cdaf3e273a2727e77af97f79f12577174c5a0
+kselftest dc59e4fea9d83f03bad6bddf3fa2e52491777482
+kunit dc59e4fea9d83f03bad6bddf3fa2e52491777482
+kunit-next f47180b0e9cc59e1989adb093a4b94187642b405
+livepatching 0839c8963b7b28d25350bd5ea69bacde794124ab
+rtc dc59e4fea9d83f03bad6bddf3fa2e52491777482
+nvdimm 86e411b6ec277dbb8ac1f1d855dc337181a62a29
+at24 dc59e4fea9d83f03bad6bddf3fa2e52491777482
+ntb dc59e4fea9d83f03bad6bddf3fa2e52491777482
+seccomp 41fa04327384148b0e2e828c9be9862c5240e9fa
+slimbus c922423ce66bcee6c61d1b5aadea09b29ca81400
+nvmem ea87821719eea4cf729e237e5cc417172f8b58e3
+hyperv a4ffc59238be84dd1c26bf1c001543e832674fc6
+auxdisplay dc59e4fea9d83f03bad6bddf3fa2e52491777482
+kgdb fdbdd0ccb30af18d3b29e714ac8d5ab6163279e0
+hmm 19272b37aa4f83ca52bdf9c16d5d81bdd1354494
+cfi dc59e4fea9d83f03bad6bddf3fa2e52491777482
+mhi 34c66fc4c223ae693ce550068ab5f48f3e3fe604
+memblock 1a6e6a79b8df153f9ec702aa4d5407333eeff917
+cxl 31adec5c3dc489966e6061cbe427dddb81d2e6b5
+zstd 65d1f5507ed2c78c64fce40e44e5574a9419eb09
+efi cf790fdb851867532b9a0f88588dcce648dbffe9
+unicode bcfee135d584714c2130031c7e28aafa91057b9a
+slab 23dae2e6397110e912ed6ff1af42579471c180dc
+random bb9ff576fdff48c242876f55098a3ee20a29df5d
+landlock 55f82176ef8dde632ea3eb94a6224950ed809d7c
+sysctl dccde188b7fc11155f3a8d5c3aa19abc4954a0aa
+execve 9bf092c97b86af63694d9902b9e14047214ba76d
+bitmap df2f996d1bcc6495505cc53544828700d7b65c1e
+hte 005b25ad11717139ca5c14c9f06c2a60855c2afd
+kspp c2606fb910d7cade63ee7e9c28e6a4225d0383f6
+nolibc a3b2181459a2c74c03ddbad585f884eefc8ff8ff
+iommufd dc59e4fea9d83f03bad6bddf3fa2e52491777482
+turbostat 1c996a37fd244d19e5dbb715328c1676e28ef607
+pwrseq 162ea02941a936f8899f3dbe10607b1d5af1b07b
+capabilities-next 071588136007482d70fd2667b827036bc60b1f8f
+ipe 028ef9c96e96197026887c0f092424679298aae8
+kcsan 07a1a6562ce29e2e0c134a57882d6e52e8758492
+crc dc59e4fea9d83f03bad6bddf3fa2e52491777482
+keys-next 965e9a2cf23b066d8bdeb690dff9cd7089c5f667
+fwctl dc59e4fea9d83f03bad6bddf3fa2e52491777482
+devsec-tsm 3177779ae17db4c66c851f799505fb95c7530c03
+hisilicon a5db65458a911daa6f8927264366dab501715dc0
+device-id 995832b2cebe6969d1b42635db698803ee31294d
+kthread fa39ec4f89f2637ed1cdbcde3656825951787668
diff --git a/Next/Trees b/Next/Trees
new file mode 100644
index 000000000000..ef300c6c0ed5
--- /dev/null
+++ b/Next/Trees
@@ -0,0 +1,429 @@
+Trees included into this release:
+
+Name Url
+---- ---
+origin https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git#master
+ext4-fixes https://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4.git#fixes
+vfs-brauner-fixes https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git#vfs.fixes
+fscrypt-current https://git.kernel.org/pub/scm/fs/fscrypt/linux.git#for-current
+fsverity-current https://git.kernel.org/pub/scm/fs/fsverity/linux.git#for-current
+btrfs-fixes https://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux.git#next-fixes
+vfs-fixes https://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs.git#fixes
+erofs-fixes https://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs.git#fixes
+nfsd-fixes https://git.kernel.org/pub/scm/linux/kernel/git/cel/linux#nfsd-fixes
+v9fs-fixes https://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs.git#fixes/next
+overlayfs-fixes https://git.kernel.org/pub/scm/linux/kernel/git/overlayfs/vfs.git#ovl-fixes
+fscrypt https://git.kernel.org/pub/scm/fs/fscrypt/linux.git#for-next
+btrfs https://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux.git#for-next
+ceph https://github.com/ceph/ceph-client.git#master
+cifs git://git.samba.org/sfrench/cifs-2.6.git#for-next
+configfs https://git.kernel.org/pub/scm/linux/kernel/git/a.hindborg/linux.git#configfs-next
+ecryptfs https://git.kernel.org/pub/scm/linux/kernel/git/tyhicks/ecryptfs.git#next
+dlm https://git.kernel.org/pub/scm/linux/kernel/git/teigland/linux-dlm.git#next
+erofs https://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs.git#dev
+exfat https://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/exfat.git#dev
+ext3 https://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs.git#for_next
+ext4 https://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4.git#dev
+f2fs https://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git#dev
+fsverity https://git.kernel.org/pub/scm/fs/fsverity/linux.git#for-next
+fuse https://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse.git#for-next
+gfs2 https://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2.git#for-next
+jfs https://github.com/kleikamp/linux-shaggy.git#jfs-next
+ksmbd https://github.com/smfrench/smb3-kernel.git#ksmbd-for-next
+nfs git://git.linux-nfs.org/projects/trondmy/nfs-2.6.git#linux-next
+nfs-anna git://git.linux-nfs.org/projects/anna/linux-nfs.git#linux-next
+nfsd https://git.kernel.org/pub/scm/linux/kernel/git/cel/linux#nfsd-next
+ntfs https://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/ntfs.git#ntfs-next
+ntfs3 https://github.com/Paragon-Software-Group/linux-ntfs3.git#master
+orangefs https://git.kernel.org/pub/scm/linux/kernel/git/hubcap/linux.git#for-next
+overlayfs https://git.kernel.org/pub/scm/linux/kernel/git/overlayfs/vfs.git#overlayfs-next
+ubifs https://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs.git#next
+v9fs https://github.com/martinetd/linux#9p-next
+v9fs-ericvh https://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs.git#ericvh/for-next
+xfs https://git.kernel.org/pub/scm/fs/xfs/xfs-linux.git#for-next
+zonefs https://git.kernel.org/pub/scm/linux/kernel/git/dlemoal/zonefs.git#for-next
+vfs-brauner https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git#vfs.all
+vfs https://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs.git#for-next
+mm-hotfixes https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm#mm-hotfixes-unstable
+kbuild-current https://git.kernel.org/pub/scm/linux/kernel/git/kbuild/linux.git#kbuild-fixes-for-next
+clang-fixes https://git.kernel.org/pub/scm/linux/kernel/git/nathan/linux.git#clang-fixes-for-next
+arc-current https://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc.git#for-curr
+arm-current https://git.kernel.org/pub/scm/linux/kernel/git/rmk/linux.git#fixes
+arm64-fixes https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux#for-next/fixes
+arm-soc-fixes https://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git#arm/fixes
+davinci-current https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git#davinci/for-current
+drivers-memory-fixes https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl.git#fixes
+sophgo-fixes https://github.com/sophgo/linux.git#fixes
+sophgo-soc-fixes https://github.com/sophgo/linux.git#soc-fixes
+m68k-current https://git.kernel.org/pub/scm/linux/kernel/git/geert/linux-m68k.git#for-linus
+powerpc-fixes https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git#fixes
+s390-fixes https://git.kernel.org/pub/scm/linux/kernel/git/s390/linux.git#fixes
+net https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git#main
+bpf https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf.git/#master
+ipsec https://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec.git#master
+netfilter https://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf.git#main
+ipvs https://git.kernel.org/pub/scm/linux/kernel/git/horms/ipvs.git#main
+wireless https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless.git#for-next
+ath https://git.kernel.org/pub/scm/linux/kernel/git/ath/ath.git#for-current
+iwlwifi https://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next.git#fixes
+wpan https://git.kernel.org/pub/scm/linux/kernel/git/wpan/wpan.git#master
+rdma-fixes https://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma.git#for-rc
+sound-current https://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git#for-linus
+sound-asoc-fixes https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git#for-linus
+regmap-fixes https://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git#for-linus
+regulator-fixes https://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git#for-linus
+spi-fixes https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git#for-linus
+pci-current https://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git#for-linus
+driver-core.current https://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core.git#driver-core-linus
+tty.current https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git#tty-linus
+usb.current https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git#usb-linus
+usb-serial-fixes https://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial.git#usb-linus
+phy https://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy.git#fixes
+staging.current https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git#staging-linus
+iio-fixes https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git#fixes-togreg
+watchdog-fixes https://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git#watchdog
+counter-current https://git.kernel.org/pub/scm/linux/kernel/git/wbg/counter.git#counter-current
+char-misc.current https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git#char-misc-linus
+soundwire-fixes https://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire.git#fixes
+thunderbolt-fixes https://git.kernel.org/pub/scm/linux/kernel/git/westeri/thunderbolt.git#fixes
+input-current https://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git#for-linus
+crypto-current https://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6.git#master
+libcrypto-fixes https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git#libcrypto-fixes
+vfio-fixes https://github.com/awilliam/linux-vfio.git#for-linus
+kselftest-fixes https://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest.git#fixes
+dmaengine-fixes https://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine.git#fixes
+backlight-fixes https://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight.git#for-backlight-fixes
+mtd-fixes https://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git#mtd/fixes
+mfd-fixes https://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git#for-mfd-fixes
+v4l-dvb-fixes git://linuxtv.org/media-ci/media-pending.git#fixes
+reset-fixes https://git.kernel.org/pub/scm/linux/kernel/git/pza/linux#reset/fixes
+mips-fixes https://git.kernel.org/pub/scm/linux/kernel/git/mips/linux.git#mips-fixes
+at91-fixes https://git.kernel.org/pub/scm/linux/kernel/git/at91/linux.git#at91-fixes
+omap-fixes https://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-omap.git#fixes
+kvm-fixes git://git.kernel.org/pub/scm/virt/kvm/kvm.git#master
+kvms390-fixes https://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux.git#master
+kvm-arm-fixes https://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm.git#fixes
+hwmon-fixes https://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git#hwmon
+nvdimm-fixes https://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm.git#libnvdimm-fixes
+cxl-fixes https://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl.git#fixes
+dma-mapping-fixes https://git.kernel.org/pub/scm/linux/kernel/git/mszyprowski/linux.git#dma-mapping-fixes
+drivers-x86-fixes https://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86.git#fixes
+samsung-krzk-fixes https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux.git#fixes
+pinctrl-samsung-fixes https://git.kernel.org/pub/scm/linux/kernel/git/pinctrl/samsung.git#fixes
+pinctrl-qcom-fixes https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git#pinctrl-qcom/for-current
+devicetree-fixes https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git#dt/linus
+dt-krzk-fixes https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-dt.git#fixes
+scsi-fixes https://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git#fixes
+drm-fixes https://gitlab.freedesktop.org/drm/kernel.git#drm-fixes
+drm-intel-fixes https://gitlab.freedesktop.org/drm/i915/kernel.git#for-linux-next-fixes
+mmc-fixes https://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc.git#fixes
+rtc-fixes https://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux.git#rtc-fixes
+gnss-fixes https://git.kernel.org/pub/scm/linux/kernel/git/johan/gnss.git#gnss-linus
+hyperv-fixes https://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux.git#hyperv-fixes
+risc-v-fixes https://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux.git#fixes
+riscv-dt-fixes https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux.git#riscv-dt-fixes
+riscv-soc-fixes https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux.git#riscv-soc-fixes
+fpga-fixes https://git.kernel.org/pub/scm/linux/kernel/git/fpga/linux-fpga.git#fixes
+spdx https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/spdx.git#spdx-linus
+gpio-brgl-fixes https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git#gpio/for-current
+gpio-intel-fixes https://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-gpio-intel.git#fixes
+pinctrl-intel-fixes https://git.kernel.org/pub/scm/linux/kernel/git/pinctrl/intel.git#fixes
+auxdisplay-fixes https://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-auxdisplay.git#fixes
+kunit-fixes https://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest.git#kunit-fixes
+memblock-fixes https://git.kernel.org/pub/scm/linux/kernel/git/rppt/memblock.git#fixes
+renesas-fixes https://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-devel.git#fixes
+perf-current https://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools.git#perf-tools
+efi-fixes https://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git#urgent
+battery-fixes https://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply.git#fixes
+iommufd-fixes https://git.kernel.org/pub/scm/linux/kernel/git/jgg/iommufd.git#for-rc
+rust-fixes https://github.com/Rust-for-Linux/linux.git#rust-fixes
+w1-fixes https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-w1.git#fixes
+pmdomain-fixes https://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm.git#fixes
+i2c-andi-fixes https://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux.git#i2c/i2c-fixes
+i2c-rust-fixes https://github.com/ikrtn/rust-for-linux#rust-i2c-fixes
+sparc-fixes https://git.kernel.org/pub/scm/linux/kernel/git/alarsson/linux-sparc.git#for-linus
+clk-fixes https://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git#clk-fixes
+thead-clk-fixes https://git.kernel.org/pub/scm/linux/kernel/git/fustini/linux.git#thead-clk-fixes
+tenstorrent-clk-fixes https://git.kernel.org/pub/scm/linux/kernel/git/tenstorrent/linux.git#tenstorrent-clk-fixes
+fustini-config-fixes https://git.kernel.org/pub/scm/linux/kernel/git/fustini/linux.git#riscv-config-fixes
+pwrseq-fixes https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git#pwrseq/for-current
+thead-dt-fixes https://git.kernel.org/pub/scm/linux/kernel/git/fustini/linux.git#thead-dt-fixes
+ftrace-fixes https://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace.git#ftrace/fixes
+ring-buffer-fixes https://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace.git#ring-buffer/fixes
+trace-fixes https://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace.git#trace/fixes
+tracefs-fixes https://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace.git#tracefs/fixes
+spacemit-fixes https://git.kernel.org/pub/scm/linux/kernel/git/spacemit/linux#fixes
+tip-fixes https://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git#tip/urgent
+slab-fixes https://git.kernel.org/pub/scm/linux/kernel/git/vbabka/slab.git#slab/for-next-fixes
+kexec-fixes https://git.kernel.org/pub/scm/linux/kernel/git/liveupdate/linux.git#kexec-fixes
+liveupdate-fixes https://git.kernel.org/pub/scm/linux/kernel/git/liveupdate/linux.git#fixes
+drm-msm-fixes https://gitlab.freedesktop.org/drm/msm.git#msm-fixes
+uml-fixes https://git.kernel.org/pub/scm/linux/kernel/git/uml/linux.git#fixes
+fwctl-fixes https://git.kernel.org/pub/scm/linux/kernel/git/fwctl/fwctl.git#for-rc
+devsec-tsm-fixes https://git.kernel.org/pub/scm/linux/kernel/git/devsec/tsm.git#fixes
+drm-rust-fixes https://gitlab.freedesktop.org/drm/rust/kernel.git#for-linux-next-fixes
+tenstorrent-dt-fixes https://git.kernel.org/pub/scm/linux/kernel/git/tenstorrent/linux.git#tenstorrent-dt-fixes
+nfc-fixes https://codeberg.org/linux-nfc/linux.git#for-linus
+drm-misc-fixes https://gitlab.freedesktop.org/drm/misc/kernel.git#for-linux-next-fixes
+rust https://github.com/Rust-for-Linux/linux.git#rust-next
+rust-interop https://github.com/Rust-for-Linux/linux.git#interop-next
+rust-alloc https://github.com/Rust-for-Linux/linux.git#alloc-next
+rust-io https://github.com/Rust-for-Linux/linux.git#io-next
+rust-pin-init https://github.com/Rust-for-Linux/linux.git#pin-init-next
+rust-timekeeping https://github.com/Rust-for-Linux/linux.git#timekeeping-next
+rust-xarray https://github.com/Rust-for-Linux/linux.git#xarray-next
+rust-analyzer https://github.com/Rust-for-Linux/linux.git#rust-analyzer-next
+mm-stable https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm#mm-stable
+mm-nonmm-stable https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm#mm-nonmm-stable
+mm-unstable https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm#mm-unstable
+mm-nonmm-unstable https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm#mm-nonmm-unstable
+kbuild https://git.kernel.org/pub/scm/linux/kernel/git/kbuild/linux.git#kbuild-for-next
+clang-format https://github.com/ojeda/linux.git#clang-format
+perf https://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools-next.git#perf-tools-next
+compiler-attributes https://github.com/ojeda/linux.git#compiler-attributes
+dma-mapping https://git.kernel.org/pub/scm/linux/kernel/git/mszyprowski/linux.git#dma-mapping-for-next
+asm-generic https://git.kernel.org/pub/scm/linux/kernel/git/arnd/asm-generic#master
+alpha https://git.kernel.org/pub/scm/linux/kernel/git/mattst88/alpha.git#alpha-next
+arm https://git.kernel.org/pub/scm/linux/kernel/git/rmk/linux.git#for-next
+arm64 https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux#for-next/core
+arm-perf https://git.kernel.org/pub/scm/linux/kernel/git/will/linux.git#for-next/perf
+arm-soc https://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git#for-next
+amlogic https://git.kernel.org/pub/scm/linux/kernel/git/amlogic/linux.git#for-next
+asahi-soc https://github.com/AsahiLinux/linux.git#asahi-soc/for-next
+at91 https://git.kernel.org/pub/scm/linux/kernel/git/at91/linux.git#at91-next
+bmc https://git.kernel.org/pub/scm/linux/kernel/git/bmc/linux.git#for-next
+broadcom https://github.com/Broadcom/stblinux.git#next
+cix https://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/cix.git#for-next
+davinci https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git#davinci/for-next
+drivers-memory https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl.git#for-next
+fsl https://git.kernel.org/pub/scm/linux/kernel/git/chleroy/linux.git#soc_fsl
+imx-mxs https://git.kernel.org/pub/scm/linux/kernel/git/frank.li/linux.git#for-next
+mediatek https://git.kernel.org/pub/scm/linux/kernel/git/mediatek/linux.git#for-next
+mvebu https://git.kernel.org/pub/scm/linux/kernel/git/gclement/mvebu.git#for-next
+omap https://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-omap.git#for-next
+qcom https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux.git#for-next
+renesas https://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-devel.git#next
+reset https://git.kernel.org/pub/scm/linux/kernel/git/pza/linux#reset/next
+rockchip https://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git#for-next
+samsung-krzk https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux.git#for-next
+scmi https://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux.git#for-linux-next
+sophgo https://github.com/sophgo/linux.git#for-next
+sophgo-soc https://github.com/sophgo/linux.git#soc-for-next
+spacemit https://git.kernel.org/pub/scm/linux/kernel/git/spacemit/linux#for-next
+stm32 https://git.kernel.org/pub/scm/linux/kernel/git/atorgue/stm32.git#stm32-next
+sunxi https://git.kernel.org/pub/scm/linux/kernel/git/sunxi/linux.git#sunxi/for-next
+tee https://git.kernel.org/pub/scm/linux/kernel/git/jenswi/linux-tee.git#next
+tegra https://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux.git#for-next
+tenstorrent-dt https://git.kernel.org/pub/scm/linux/kernel/git/tenstorrent/linux.git#tenstorrent-dt-for-next
+fustini-config https://git.kernel.org/pub/scm/linux/kernel/git/fustini/linux.git#riscv-config-for-next
+thead-dt https://git.kernel.org/pub/scm/linux/kernel/git/fustini/linux.git#thead-dt-for-next
+ti https://git.kernel.org/pub/scm/linux/kernel/git/ti/linux.git#ti-next
+xilinx https://github.com/Xilinx/linux-xlnx.git#for-next
+socfpga https://git.kernel.org/pub/scm/linux/kernel/git/dinguyen/linux.git#for-next
+clk https://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git#clk-next
+clk-imx https://git.kernel.org/pub/scm/linux/kernel/git/abelvesa/linux.git#for-next
+clk-renesas https://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers.git#renesas-clk
+thead-clk https://git.kernel.org/pub/scm/linux/kernel/git/fustini/linux.git#thead-clk-for-next
+tenstorrent-clk https://git.kernel.org/pub/scm/linux/kernel/git/tenstorrent/linux.git#tenstorrent-clk-for-next
+csky https://github.com/c-sky/csky-linux.git#linux-next
+loongarch https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson.git#loongarch-next
+m68k https://git.kernel.org/pub/scm/linux/kernel/git/geert/linux-m68k.git#for-next
+m68knommu https://git.kernel.org/pub/scm/linux/kernel/git/gerg/m68knommu.git#for-next
+microblaze git://git.monstr.eu/linux-2.6-microblaze.git#next
+mips https://git.kernel.org/pub/scm/linux/kernel/git/mips/linux.git#mips-next
+openrisc https://github.com/openrisc/linux.git#for-next
+parisc-hd https://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux.git#for-next
+powerpc https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git#next
+risc-v https://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux.git#for-next
+riscv-dt https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux.git#riscv-dt-for-next
+riscv-soc https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux.git#riscv-soc-for-next
+s390 https://git.kernel.org/pub/scm/linux/kernel/git/s390/linux.git#for-next
+sh https://git.kernel.org/pub/scm/linux/kernel/git/glaubitz/sh-linux.git#for-next
+sparc https://git.kernel.org/pub/scm/linux/kernel/git/alarsson/linux-sparc.git#for-next
+uml https://git.kernel.org/pub/scm/linux/kernel/git/uml/linux.git#next
+xtensa https://github.com/jcmvbkbc/linux-xtensa.git#xtensa-for-next
+printk https://git.kernel.org/pub/scm/linux/kernel/git/printk/linux.git#for-next
+pci https://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git#next
+pstore https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git#for-next/pstore
+hid https://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git#for-next
+i2c https://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git#i2c/for-next
+i2c-andi https://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux.git#i2c/i2c-next
+i2c-rust https://github.com/ikrtn/rust-for-linux#rust-i2c-next
+i3c https://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux.git#i3c/next
+dmi https://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging.git#dmi-for-next
+hwmon-staging https://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git#hwmon-next
+jc_docs git://git.lwn.net/linux.git#docs-next
+v4l-dvb git://linuxtv.org/media-ci/media-pending.git#next
+v4l-dvb-next git://linuxtv.org/mchehab/media-next.git#master
+pm https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git#linux-next
+cpufreq-arm https://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm.git#cpufreq/arm/linux-next
+cpupower https://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux.git#cpupower
+devfreq https://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git#devfreq-next
+pmdomain https://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm.git#next
+opp https://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm.git#opp/linux-next
+thermal https://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux.git#thermal/linux-next
+rdma https://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma.git#for-next
+net-next https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git#main
+bpf-next https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git#for-next
+ipsec-next https://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec-next.git#master
+mlx5-next https://git.kernel.org/pub/scm/linux/kernel/git/mellanox/linux.git#mlx5-next
+netfilter-next https://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf-next.git#main
+ipvs-next https://git.kernel.org/pub/scm/linux/kernel/git/horms/ipvs-next.git#main
+bluetooth https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git#master
+wireless-next https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git#for-next
+ath-next https://git.kernel.org/pub/scm/linux/kernel/git/ath/ath.git#for-next
+iwlwifi-next https://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next.git#next
+wpan-next https://git.kernel.org/pub/scm/linux/kernel/git/wpan/wpan-next.git#master
+wpan-staging https://git.kernel.org/pub/scm/linux/kernel/git/wpan/wpan-next.git#staging
+mtd https://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git#mtd/next
+nand https://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git#nand/next
+spi-nor https://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git#spi-nor/next
+crypto https://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git#master
+libcrypto https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git#libcrypto-next
+drm https://gitlab.freedesktop.org/drm/kernel.git#drm-next
+drm-exynos https://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos.git#for-linux-next
+drm-misc https://gitlab.freedesktop.org/drm/misc/kernel.git#for-linux-next
+amdgpu https://gitlab.freedesktop.org/agd5f/linux.git#drm-next
+drm-intel https://gitlab.freedesktop.org/drm/i915/kernel.git#for-linux-next
+drm-msm https://gitlab.freedesktop.org/drm/msm.git#msm-next
+drm-msm-lumag https://gitlab.freedesktop.org/lumag/msm.git#msm-next-lumag
+drm-xe https://gitlab.freedesktop.org/drm/xe/kernel.git#drm-xe-next
+drm-rust https://gitlab.freedesktop.org/drm/rust/kernel.git#for-linux-next
+drm-nova https://gitlab.freedesktop.org/drm/nova.git#nova-next
+etnaviv https://git.pengutronix.de/git/lst/linux#etnaviv/next
+fbdev https://git.kernel.org/pub/scm/linux/kernel/git/deller/linux-fbdev.git#for-next
+regmap https://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git#for-next
+sound https://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git#for-next
+ieee1394 https://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394.git#for-next
+sound-asoc https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git#for-next
+modules https://git.kernel.org/pub/scm/linux/kernel/git/modules/linux.git#modules-next
+input https://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git#next
+block https://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux.git#for-next
+device-mapper https://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm.git#for-next
+libata https://git.kernel.org/pub/scm/linux/kernel/git/libata/linux#for-next
+pcmcia https://git.kernel.org/pub/scm/linux/kernel/git/brodo/linux.git#pcmcia-next
+mmc https://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc.git#next
+mfd https://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git#for-mfd-next
+backlight https://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight.git#for-backlight-next
+battery https://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply.git#for-next
+regulator https://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git#for-next
+security https://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/lsm.git#next
+apparmor https://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor#apparmor-next
+integrity https://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity#next-integrity
+selinux https://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux.git#next
+smack https://github.com/cschaufler/smack-next#next
+tomoyo git://git.code.sf.net/p/tomoyo/tomoyo.git#master
+tpmdd-tpm https://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd.git#for-next-tpm
+tpmdd-keys https://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd.git#for-next-keys
+watchdog https://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git#watchdog-next
+iommu https://git.kernel.org/pub/scm/linux/kernel/git/iommu/linux.git#next
+audit https://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/audit.git#next
+devicetree https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git#for-next
+dt-krzk https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-dt.git#for-next
+mailbox https://git.kernel.org/pub/scm/linux/kernel/git/jassibrar/mailbox.git#for-next
+spi https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git#for-next
+tip https://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git#master
+kexec https://git.kernel.org/pub/scm/linux/kernel/git/liveupdate/linux.git#kexec-next
+liveupdate https://git.kernel.org/pub/scm/linux/kernel/git/liveupdate/linux.git#next
+clockevents https://git.kernel.org/pub/scm/linux/kernel/git/daniel.lezcano/linux.git#timers/drivers/next
+edac https://git.kernel.org/pub/scm/linux/kernel/git/ras/ras.git#edac-for-next
+ftrace https://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace.git#for-next
+rcu https://git.kernel.org/pub/scm/linux/kernel/git/rcu/linux#next
+paulmck https://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git#non-rcu/next
+kvm git://git.kernel.org/pub/scm/virt/kvm/kvm.git#next
+kvm-arm https://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm.git#next
+kvms390 https://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux.git#next
+kvm-ppc https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git#topic/ppc-kvm
+kvm-riscv https://github.com/kvm-riscv/linux.git#riscv_kvm_next
+kvm-x86 https://github.com/kvm-x86/linux.git#next
+xen-tip https://git.kernel.org/pub/scm/linux/kernel/git/xen/tip.git#linux-next
+percpu https://git.kernel.org/pub/scm/linux/kernel/git/dennis/percpu.git#for-next
+workqueues https://git.kernel.org/pub/scm/linux/kernel/git/tj/wq.git#for-next
+sched-ext https://git.kernel.org/pub/scm/linux/kernel/git/tj/sched_ext.git#for-next
+drivers-x86 https://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86.git#for-next
+chrome-platform https://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux.git#for-next
+chrome-platform-firmware https://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux.git#for-firmware-next
+hsi https://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-hsi.git#for-next
+leds-lj https://git.kernel.org/pub/scm/linux/kernel/git/lee/leds.git#for-leds-next
+ipmi https://github.com/cminyard/linux-ipmi.git#for-next
+driver-core https://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core.git#driver-core-next
+usb https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git#usb-next
+thunderbolt https://git.kernel.org/pub/scm/linux/kernel/git/westeri/thunderbolt.git#next
+usb-serial https://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial.git#usb-next
+tty https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git#tty-next
+char-misc https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git#char-misc-next
+coresight https://git.kernel.org/pub/scm/linux/kernel/git/coresight/linux.git#next
+fastrpc https://git.kernel.org/pub/scm/linux/kernel/git/srini/fastrpc.git#for-next
+fpga https://git.kernel.org/pub/scm/linux/kernel/git/fpga/linux-fpga.git#for-next
+icc https://git.kernel.org/pub/scm/linux/kernel/git/djakov/icc.git#icc-next
+iio https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git#togreg
+nfc https://codeberg.org/linux-nfc/linux.git#for-next
+phy-next https://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy.git#next
+soundwire https://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire.git#next
+extcon https://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/extcon.git#extcon-next
+gnss https://git.kernel.org/pub/scm/linux/kernel/git/johan/gnss.git#gnss-next
+vfio https://github.com/awilliam/linux-vfio.git#next
+w1 https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-w1.git#for-next
+spmi https://git.kernel.org/pub/scm/linux/kernel/git/sboyd/spmi.git#spmi-next
+staging https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git#staging-next
+counter-next https://git.kernel.org/pub/scm/linux/kernel/git/wbg/counter.git#counter-next
+mux https://gitlab.com/peda-linux/mux.git#for-next
+dmaengine https://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine.git#next
+cgroup https://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git#for-next
+scsi https://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git#for-next
+scsi-mkp https://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git#for-next
+vhost https://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost.git#linux-next
+rpmsg https://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux.git#for-next
+gpio-brgl https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git#gpio/for-next
+gpio-intel https://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-gpio-intel.git#for-next
+pinctrl https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl.git#for-next
+pinctrl-intel https://git.kernel.org/pub/scm/linux/kernel/git/pinctrl/intel.git#for-next
+pinctrl-renesas https://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers.git#renesas-pinctrl
+pinctrl-samsung https://git.kernel.org/pub/scm/linux/kernel/git/pinctrl/samsung.git#for-next
+pinctrl-qcom https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git#pinctrl-qcom/for-next
+pwm https://git.kernel.org/pub/scm/linux/kernel/git/ukleinek/linux.git#pwm/for-next
+ktest https://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-ktest.git#for-next
+kselftest https://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest.git#next
+kunit https://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest.git#test
+kunit-next https://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest.git#kunit
+livepatching https://git.kernel.org/pub/scm/linux/kernel/git/livepatching/livepatching.git#for-next
+rtc https://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux.git#rtc-next
+nvdimm https://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm.git#libnvdimm-for-next
+at24 https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git#at24/for-next
+ntb https://github.com/jonmason/ntb.git#ntb-next
+seccomp https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git#for-next/seccomp
+slimbus https://git.kernel.org/pub/scm/linux/kernel/git/srini/slimbus.git#for-next
+nvmem https://git.kernel.org/pub/scm/linux/kernel/git/srini/nvmem.git#for-next
+hyperv https://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux.git#hyperv-next
+auxdisplay https://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-auxdisplay.git#for-next
+kgdb https://git.kernel.org/pub/scm/linux/kernel/git/danielt/linux.git#kgdb/for-next
+hmm https://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma.git#hmm
+cfi https://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git#cfi/next
+mhi https://git.kernel.org/pub/scm/linux/kernel/git/mani/mhi.git#mhi-next
+memblock https://git.kernel.org/pub/scm/linux/kernel/git/rppt/memblock.git#for-next
+cxl https://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl.git#next
+zstd https://github.com/terrelln/linux.git#zstd-next
+efi https://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git#next
+unicode https://git.kernel.org/pub/scm/linux/kernel/git/krisman/unicode.git#for-next
+slab https://git.kernel.org/pub/scm/linux/kernel/git/vbabka/slab.git#slab/for-next
+random https://git.kernel.org/pub/scm/linux/kernel/git/crng/random.git#master
+landlock https://git.kernel.org/pub/scm/linux/kernel/git/mic/linux.git#next
+sysctl https://git.kernel.org/pub/scm/linux/kernel/git/sysctl/sysctl.git#sysctl-next
+execve https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git#for-next/execve
+bitmap https://github.com/norov/linux.git#bitmap-for-next
+hte https://git.kernel.org/pub/scm/linux/kernel/git/pateldipen1984/linux.git#for-next
+kspp https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git#for-next/kspp
+nolibc https://git.kernel.org/pub/scm/linux/kernel/git/nolibc/linux-nolibc.git#for-next
+iommufd https://git.kernel.org/pub/scm/linux/kernel/git/jgg/iommufd.git#for-next
+turbostat https://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux.git#next
+pwrseq https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git#pwrseq/for-next
+capabilities-next https://git.kernel.org/pub/scm/linux/kernel/git/sergeh/linux.git#caps-next
+ipe https://git.kernel.org/pub/scm/linux/kernel/git/wufan/ipe.git#next
+kcsan https://git.kernel.org/pub/scm/linux/kernel/git/melver/linux.git#next
+crc https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git#crc-next
+keys-next https://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs.git#keys-next
+fwctl https://git.kernel.org/pub/scm/linux/kernel/git/fwctl/fwctl.git#for-next
+devsec-tsm https://git.kernel.org/pub/scm/linux/kernel/git/devsec/tsm.git#next
+hisilicon https://github.com/hisilicon/linux-hisi.git#for-next
+device-id https://git.kernel.org/pub/scm/linux/kernel/git/ukleinek/linux.git#device-id-rework
+kthread https://git.kernel.org/pub/scm/linux/kernel/git/frederic/linux-dynticks.git#for-next
diff --git a/Next/merge.log b/Next/merge.log
new file mode 100644
index 000000000000..2946e5ce9a0e
--- /dev/null
+++ b/Next/merge.log
@@ -0,0 +1,7942 @@
+$ date -R
+Fri, 10 Jul 2026 11:18:16 +0100
+$ git checkout master
+Already on 'master'
+$ git reset --hard stable
+Updating files: 74% (3374/4533) Updating files: 75% (3400/4533) Updating files: 76% (3446/4533) Updating files: 77% (3491/4533) Updating files: 78% (3536/4533) Updating files: 79% (3582/4533) Updating files: 80% (3627/4533) Updating files: 81% (3672/4533) Updating files: 82% (3718/4533) Updating files: 83% (3763/4533) Updating files: 84% (3808/4533) Updating files: 85% (3854/4533) Updating files: 86% (3899/4533) Updating files: 87% (3944/4533) Updating files: 88% (3990/4533) Updating files: 89% (4035/4533) Updating files: 90% (4080/4533) Updating files: 91% (4126/4533) Updating files: 92% (4171/4533) Updating files: 93% (4216/4533) Updating files: 94% (4262/4533) Updating files: 95% (4307/4533) Updating files: 96% (4352/4533) Updating files: 97% (4398/4533) Updating files: 98% (4443/4533) Updating files: 99% (4488/4533) Updating files: 100% (4533/4533) Updating files: 100% (4533/4533), done.
+HEAD is now at 0e35b9b6ec0ff Merge tag 'mm-hotfixes-stable-2026-07-06-17-49' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
+Merging origin/master (a635d67482345 Merge tag 'v7.2-rc2-smb3-server-fixes' of git://git.samba.org/ksmbd)
+$ git merge -m Merge branch 'master' of https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git origin/master
+Updating 0e35b9b6ec0ff..a635d67482345
+Fast-forward (no commit created; -m option ignored)
+ drivers/bluetooth/bpa10x.c | 8 +-
+ drivers/bluetooth/btintel_pcie.c | 102 +++++-----
+ drivers/bluetooth/btnxpuart.c | 6 +
+ drivers/bluetooth/hci_ldisc.c | 14 +-
+ drivers/dibs/dibs_loopback.c | 5 +
+ drivers/hid/bpf/hid_bpf_dispatch.c | 5 +-
+ drivers/hid/hid-appleir.c | 45 ++++-
+ drivers/hid/hid-core.c | 7 +
+ drivers/hid/hid-letsketch.c | 36 +++-
+ drivers/hid/hid-lg-g15.c | 16 ++
+ drivers/hid/hid-logitech-dj.c | 9 +-
+ drivers/hid/hid-multitouch.c | 32 ++--
+ drivers/hid/hid-picolcd_core.c | 3 +-
+ drivers/net/amt.c | 6 +-
+ drivers/net/ethernet/cadence/macb_main.c | 21 ++-
+ drivers/net/ethernet/cavium/liquidio/lio_main.c | 27 ---
+ .../net/ethernet/cavium/liquidio/octeon_device.h | 3 -
+ .../net/ethernet/cavium/liquidio/octeon_mailbox.c | 33 +++-
+ .../net/ethernet/marvell/octeontx2/af/rvu_nix.c | 4 +-
+ .../net/ethernet/marvell/octeontx2/nic/otx2_pf.c | 64 +++++--
+ drivers/net/ethernet/mellanox/mlx5/core/en.h | 12 ++
+ .../ethernet/mellanox/mlx5/core/en/hv_vhca_stats.c | 37 ++--
+ drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 14 +-
+ drivers/net/ethernet/mellanox/mlx5/core/en_stats.c | 9 +-
+ drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 3 +
+ .../net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c | 3 +-
+ .../net/ethernet/mellanox/mlx5/core/lag/mpesw.c | 7 +-
+ .../ethernet/mellanox/mlx5/core/lag/shared_fdb.c | 2 +-
+ .../net/ethernet/mellanox/mlx5/core/lib/hv_vhca.c | 8 +-
+ .../net/ethernet/mellanox/mlx5/core/lib/hv_vhca.h | 6 +-
+ .../net/ethernet/mellanox/mlx5/core/lib/port_tun.c | 3 +-
+ .../ethernet/microchip/lan966x/lan966x_vcap_impl.c | 5 +-
+ .../ethernet/microchip/sparx5/sparx5_vcap_impl.c | 5 +-
+ drivers/net/ethernet/microchip/vcap/vcap_api.c | 72 ++++----
+ drivers/net/ethernet/microchip/vcap/vcap_api.h | 3 +-
+ .../net/ethernet/microchip/vcap/vcap_api_debugfs.c | 8 +-
+ .../microchip/vcap/vcap_api_debugfs_kunit.c | 3 +-
+ .../net/ethernet/microchip/vcap/vcap_api_kunit.c | 3 +-
+ .../net/ethernet/microchip/vcap/vcap_api_private.h | 3 +
+ drivers/net/ethernet/microsoft/mana/mana_en.c | 61 ++++--
+ drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx.c | 26 ++-
+ drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx.h | 5 +-
+ drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx_fw.c | 82 +++++----
+ drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx_fw.h | 14 ++
+ drivers/net/ethernet/qlogic/qede/qede_fp.c | 5 +
+ .../net/ethernet/qualcomm/rmnet/rmnet_handlers.c | 5 +-
+ drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h | 1 +
+ .../net/ethernet/qualcomm/rmnet/rmnet_map_data.c | 78 ++++----
+ drivers/net/macsec.c | 2 +-
+ drivers/net/mdio/Kconfig | 3 +-
+ drivers/net/usb/lan78xx.c | 18 +-
+ drivers/net/usb/net1080.c | 2 +-
+ fs/smb/server/auth.c | 49 ++---
+ fs/smb/server/auth.h | 7 +-
+ fs/smb/server/mgmt/user_session.c | 4 +-
+ fs/smb/server/mgmt/user_session.h | 1 +
+ fs/smb/server/server.c | 16 +-
+ fs/smb/server/smb2pdu.c | 205 +++++++++++++++------
+ fs/smb/server/smbacl.c | 21 ++-
+ fs/smb/server/vfs_cache.h | 1 +
+ include/linux/inetdevice.h | 5 +
+ include/net/addrconf.h | 5 +
+ include/net/bluetooth/hci.h | 5 +-
+ include/net/bluetooth/hci_core.h | 1 +
+ include/net/bluetooth/l2cap.h | 10 +-
+ include/net/gue.h | 2 +-
+ include/net/ip_vs.h | 3 +-
+ include/net/mana/mana.h | 8 +
+ include/net/netfilter/nf_flow_table.h | 7 +-
+ include/net/tc_act/tc_pedit.h | 18 +-
+ net/batman-adv/distributed-arp-table.c | 2 +-
+ net/batman-adv/fragmentation.c | 8 +-
+ net/batman-adv/main.c | 10 +-
+ net/batman-adv/mesh-interface.c | 16 +-
+ net/batman-adv/mesh-interface.h | 2 +
+ net/batman-adv/multicast_forw.c | 7 +-
+ net/batman-adv/translation-table.c | 5 +-
+ net/bluetooth/6lowpan.c | 84 +++------
+ net/bluetooth/af_bluetooth.c | 17 +-
+ net/bluetooth/bnep/core.c | 27 ++-
+ net/bluetooth/hci_conn.c | 21 +--
+ net/bluetooth/hci_sync.c | 137 ++++++++++++--
+ net/bluetooth/iso.c | 44 +++--
+ net/bluetooth/l2cap_core.c | 140 ++++++++++----
+ net/bluetooth/l2cap_sock.c | 107 +++++------
+ net/bluetooth/mgmt.c | 5 +
+ net/bluetooth/msft.c | 2 +-
+ net/bluetooth/sco.c | 15 +-
+ net/bluetooth/smp.c | 27 +--
+ net/bridge/netfilter/ebtables.c | 12 +-
+ net/ethtool/netlink.h | 28 +++
+ net/ethtool/rss.c | 14 +-
+ net/ipv4/igmp.c | 29 ++-
+ net/ipv6/mcast.c | 40 ++--
+ net/ipv6/netfilter/ip6t_ah.c | 5 +
+ net/ipv6/netfilter/ip6t_hbh.c | 1 +
+ net/ipv6/netfilter/ip6t_rt.c | 3 +-
+ net/ipv6/netfilter/nf_conntrack_reasm.c | 5 +-
+ net/llc/af_llc.c | 1 +
+ net/mac802154/iface.c | 2 +-
+ net/netfilter/ipset/ip_set_hash_gen.h | 85 ++++++---
+ net/netfilter/ipvs/ip_vs_conn.c | 4 +-
+ net/netfilter/ipvs/ip_vs_core.c | 33 ++--
+ net/netfilter/ipvs/ip_vs_proto_sctp.c | 18 +-
+ net/netfilter/ipvs/ip_vs_proto_tcp.c | 11 +-
+ net/netfilter/ipvs/ip_vs_proto_udp.c | 3 +-
+ net/netfilter/nf_flow_table_core.c | 19 +-
+ net/netfilter/nf_flow_table_ip.c | 21 ++-
+ net/netfilter/nf_flow_table_offload.c | 22 ++-
+ net/netfilter/nf_nat_sip.c | 11 ++
+ net/netfilter/nf_tables_api.c | 3 +
+ net/netfilter/nfnetlink_cthelper.c | 2 +
+ net/netfilter/nfnetlink_log.c | 26 ++-
+ net/netfilter/nfnetlink_queue.c | 16 +-
+ net/netfilter/nft_lookup.c | 10 +-
+ net/netfilter/nft_set_rbtree.c | 8 +-
+ net/netfilter/xt_connmark.c | 14 +-
+ net/netfilter/xt_rateest.c | 2 +-
+ net/netfilter/xt_u32.c | 28 ++-
+ net/sched/act_api.c | 13 +-
+ net/sched/act_pedit.c | 13 +-
+ net/sched/cls_api.c | 22 ++-
+ net/sched/sch_cake.c | 5 +-
+ net/sched/sch_teql.c | 27 +--
+ net/smc/smc_cdc.c | 15 +-
+ net/tls/tls_sw.c | 11 ++
+ tools/testing/selftests/hid/Makefile | 2 +-
+ tools/testing/selftests/hid/hid_bpf.c | 36 +++-
+ tools/testing/selftests/hid/progs/hid.c | 15 ++
+ .../testing/selftests/hid/tests/test_multitouch.py | 114 ++++++++++++
+ tools/testing/selftests/net/lib.sh | 25 ++-
+ tools/testing/selftests/net/tcp_mmap.c | 4 +
+ 132 files changed, 1908 insertions(+), 868 deletions(-)
+Merging ext4-fixes/fixes (981fcc5674e67 jbd2: fix deadlock in jbd2_journal_cancel_revoke())
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4.git ext4-fixes/fixes
+Already up to date.
+Merging vfs-brauner-fixes/vfs.fixes (24dddc384fb9a Merge patch series "iomap: consolidate bio submission")
+$ git merge -m Merge branch 'vfs.fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git vfs-brauner-fixes/vfs.fixes
+Already up to date.
+Merging fscrypt-current/for-current (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'for-current' of https://git.kernel.org/pub/scm/fs/fscrypt/linux.git fscrypt-current/for-current
+Already up to date.
+Merging fsverity-current/for-current (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'for-current' of https://git.kernel.org/pub/scm/fs/fsverity/linux.git fsverity-current/for-current
+Already up to date.
+Merging btrfs-fixes/next-fixes (6c893b948351d Merge branch 'misc-7.2' into next-fixes)
+$ git merge -m Merge branch 'next-fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux.git btrfs-fixes/next-fixes
+Merge made by the 'ort' strategy.
+ fs/btrfs/file-item.c | 26 +++++++++++++++++++++++++-
+ fs/btrfs/free-space-cache.c | 3 +++
+ fs/btrfs/ioctl.c | 18 ++++++++++++------
+ fs/btrfs/lzo.c | 15 ++++++++++++---
+ fs/btrfs/print-tree.c | 8 ++++----
+ fs/btrfs/props.c | 16 +++++++++++++---
+ fs/btrfs/relocation.c | 15 +++++++--------
+ fs/btrfs/tree-checker.c | 6 ++++++
+ 8 files changed, 82 insertions(+), 25 deletions(-)
+Merging vfs-fixes/fixes (49c5d168a3a8f udf: fix nls leak on udf_fill_super() failure)
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs.git vfs-fixes/fixes
+Auto-merging fs/udf/super.c
+Merge made by the 'ort' strategy.
+Merging erofs-fixes/fixes (95e19a4d8dd30 erofs: get rid of erofs_is_ishare_inode() helper)
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs.git erofs-fixes/fixes
+Merge made by the 'ort' strategy.
+ fs/erofs/ishare.c | 8 +-------
+ fs/erofs/super.c | 17 ++++-------------
+ fs/erofs/zmap.c | 3 ++-
+ 3 files changed, 7 insertions(+), 21 deletions(-)
+Merging nfsd-fixes/nfsd-fixes (92ea163c773cb NFSD: Prevent post-shutdown use-after-free in NFSD_CMD_UNLOCK_FILESYSTEM)
+$ git merge -m Merge branch 'nfsd-fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/cel/linux nfsd-fixes/nfsd-fixes
+Merge made by the 'ort' strategy.
+ fs/nfsd/nfsctl.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+Merging v9fs-fixes/fixes/next (028ef9c96e961 Linux 7.0)
+$ git merge -m Merge branch 'fixes/next' of https://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs.git v9fs-fixes/fixes/next
+Already up to date.
+Merging overlayfs-fixes/ovl-fixes (4549871118cf6 Linux 7.1-rc7)
+$ git merge -m Merge branch 'ovl-fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/overlayfs/vfs.git overlayfs-fixes/ovl-fixes
+Already up to date.
+Merging fscrypt/for-next (2d0afaac9137e fscrypt: Remove workaround for bug in gcc 7 and earlier)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/fs/fscrypt/linux.git fscrypt/for-next
+Merge made by the 'ort' strategy.
+ fs/crypto/crypto.c | 40 ++++++++------------------------------
+ fs/crypto/fscrypt_private.h | 5 +----
+ fs/crypto/keyring.c | 21 +++++++++-----------
+ fs/crypto/keysetup.c | 26 ++++++++++---------------
+ fs/crypto/policy.c | 17 ++--------------
+ include/uapi/linux/fscrypt.h | 1 -
+ tools/include/uapi/linux/fscrypt.h | 1 -
+ 7 files changed, 30 insertions(+), 81 deletions(-)
+Merging btrfs/for-next (0542d886e45d5 Merge branch 'for-next-current-v7.1-20260630' into for-next-20260630)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux.git btrfs/for-next
+Merge made by the 'ort' strategy.
+Merging ceph/master (1397040896280 selftests: ceph: wire up Ceph reset kselftests and documentation)
+$ git merge -m Merge branch 'master' of https://github.com/ceph/ceph-client.git ceph/master
+Auto-merging MAINTAINERS
+Auto-merging tools/testing/selftests/Makefile
+Merge made by the 'ort' strategy.
+ MAINTAINERS | 1 +
+ tools/testing/selftests/Makefile | 1 +
+ tools/testing/selftests/filesystems/ceph/Makefile | 7 +
+ tools/testing/selftests/filesystems/ceph/README | 84 +++
+ .../filesystems/ceph/reset_corner_cases.sh | 646 +++++++++++++++++++
+ .../selftests/filesystems/ceph/reset_stress.sh | 694 +++++++++++++++++++++
+ .../selftests/filesystems/ceph/run_validation.sh | 350 +++++++++++
+ tools/testing/selftests/filesystems/ceph/settings | 1 +
+ .../filesystems/ceph/validate_consistency.py | 297 +++++++++
+ 9 files changed, 2081 insertions(+)
+ create mode 100644 tools/testing/selftests/filesystems/ceph/Makefile
+ create mode 100644 tools/testing/selftests/filesystems/ceph/README
+ create mode 100755 tools/testing/selftests/filesystems/ceph/reset_corner_cases.sh
+ create mode 100755 tools/testing/selftests/filesystems/ceph/reset_stress.sh
+ create mode 100755 tools/testing/selftests/filesystems/ceph/run_validation.sh
+ create mode 100644 tools/testing/selftests/filesystems/ceph/settings
+ create mode 100755 tools/testing/selftests/filesystems/ceph/validate_consistency.py
+Merging cifs/for-next (d2c46c9f7a9ba cifs: Remove CIFSSMBSetPathInfoFB() fallback function)
+$ git merge -m Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6.git cifs/for-next
+Merge made by the 'ort' strategy.
+ fs/smb/client/cifs_fs_sb.h | 1 +
+ fs/smb/client/cifsacl.c | 2 +-
+ fs/smb/client/cifsfs.c | 12 ++++++++++++
+ fs/smb/client/cifsglob.h | 1 +
+ fs/smb/client/cifsproto.h | 2 +-
+ fs/smb/client/cifssmb.c | 36 ------------------------------------
+ fs/smb/client/connect.c | 3 ++-
+ fs/smb/client/dfs_cache.c | 12 ++++++------
+ fs/smb/client/file.c | 7 ++++++-
+ fs/smb/client/inode.c | 13 +++++++------
+ fs/smb/client/link.c | 17 ++++-------------
+ fs/smb/client/misc.c | 14 +++++++++++++-
+ fs/smb/client/readdir.c | 4 ++--
+ fs/smb/client/reparse.c | 17 ++++++++++++++++-
+ fs/smb/client/smb1ops.c | 28 +++++++++++++++++-----------
+ fs/smb/client/smb2file.c | 19 ++++++++-----------
+ fs/smb/client/smb2misc.c | 32 ++++++++++++++++++++++++++------
+ fs/smb/client/smb2ops.c | 19 ++++++++-----------
+ fs/smb/client/smb2pdu.c | 26 ++++++++++++++------------
+ fs/smb/client/smb2proto.h | 2 +-
+ 20 files changed, 146 insertions(+), 121 deletions(-)
+Merging configfs/configfs-next (6363844fdbbb7 samples: configfs: Constify struct configfs_item_operations and configfs_group_operations)
+$ git merge -m Merge branch 'configfs-next' of https://git.kernel.org/pub/scm/linux/kernel/git/a.hindborg/linux.git configfs/configfs-next
+Already up to date.
+Merging ecryptfs/next (95ce5ffd54cf6 ecryptfs: use kasprintf in ecryptfs_crypto_api_algify_cipher_name)
+$ git merge -m Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/tyhicks/ecryptfs.git ecryptfs/next
+Already up to date.
+Merging dlm/next (e61113cfcaf71 dlm: init per node debugfs before add to node hash)
+$ git merge -m Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/teigland/linux-dlm.git dlm/next
+Already up to date.
+Merging erofs/dev (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'dev' of https://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs.git erofs/dev
+Already up to date.
+Merging exfat/dev (5362e7aedd113 exfat: fix mmap data loss when extending valid_size over a shared mapping)
+$ git merge -m Merge branch 'dev' of https://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/exfat.git exfat/dev
+Auto-merging fs/exfat/iomap.c
+Merge made by the 'ort' strategy.
+ fs/exfat/exfat_fs.h | 2 +-
+ fs/exfat/file.c | 219 +++++++++++++++++++++++++++++++++++++++++++---------
+ fs/exfat/iomap.c | 22 +++++-
+ 3 files changed, 205 insertions(+), 38 deletions(-)
+Merging ext3/for_next (f4d8f32d771d2 Pull udf VAT off-by-one fix.)
+$ git merge -m Merge branch 'for_next' of https://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs.git ext3/for_next
+Merge made by the 'ort' strategy.
+ fs/notify/fanotify/fanotify.c | 1 +
+ fs/udf/balloc.c | 12 ++++++++++--
+ fs/udf/inode.c | 26 +++++++++++++++++++++++---
+ fs/udf/partition.c | 2 +-
+ fs/udf/super.c | 23 ++++++++++++++---------
+ fs/udf/truncate.c | 2 +-
+ fs/udf/udfdecl.h | 3 ++-
+ 7 files changed, 52 insertions(+), 17 deletions(-)
+Merging ext4/dev (c143957520c6c ext4: validate donor file superblock early in EXT4_IOC_MOVE_EXT)
+$ git merge -m Merge branch 'dev' of https://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4.git ext4/dev
+Already up to date.
+Merging f2fs/dev (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'dev' of https://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git f2fs/dev
+Already up to date.
+Merging fsverity/for-next (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/fs/fsverity/linux.git fsverity/for-next
+Already up to date.
+Merging fuse/for-next (7d87a5a284bb3 fuse-uring: clear ent->fuse_req in commit_fetch error path)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse.git fuse/for-next
+Already up to date.
+Merging gfs2/for-next (5f80d9113360c Merge tag 'gfs2-for-7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2.git gfs2/for-next
+Already up to date.
+Merging jfs/jfs-next (dad98c5b2a05e jfs: avoid -Wtautological-constant-out-of-range-compare warning again)
+$ git merge -m Merge branch 'jfs-next' of https://github.com/kleikamp/linux-shaggy.git jfs/jfs-next
+Already up to date.
+Merging ksmbd/ksmbd-for-next (b88458c886378 ksmbd: Do not skip lock checks for single-byte ranges)
+$ git merge -m Merge branch 'ksmbd-for-next' of https://github.com/smfrench/smb3-kernel.git ksmbd/ksmbd-for-next
+Merge made by the 'ort' strategy.
+ fs/smb/server/compress.c | 3 +-
+ fs/smb/server/connection.c | 16 ++--
+ fs/smb/server/ksmbd_netlink.h | 1 +
+ fs/smb/server/smb2pdu.c | 174 +++++++++++++++++++++++++++++++++++++-----
+ fs/smb/server/smbacl.c | 147 ++++++++++++++++++++++++-----------
+ fs/smb/server/smbacl.h | 3 +-
+ fs/smb/server/vfs.c | 8 +-
+ 7 files changed, 278 insertions(+), 74 deletions(-)
+$ git am -3 ../patches/0001-ntfs3-Fix-up-merge-with-Linus.patch
+Applying: ntfs3: Fix up merge with Linus
+Using index info to reconstruct a base tree...
+M fs/ntfs3/file.c
+Falling back to patching base and 3-way merge...
+No changes -- Patch already applied.
+Merging nfs/linux-next (8cdeaa50eae8d Linux 7.2-rc2)
+$ git merge -m Merge branch 'linux-next' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6.git nfs/linux-next
+Already up to date.
+Merging nfs-anna/linux-next (27934d02cbeb8 NFS: Charge unstable writes by request size, not folio size)
+$ git merge -m Merge branch 'linux-next' of git://git.linux-nfs.org/projects/anna/linux-nfs.git nfs-anna/linux-next
+Merge made by the 'ort' strategy.
+ fs/nfs/dir.c | 2 ++
+ fs/nfs/internal.h | 12 +++++++-----
+ fs/nfs/pnfs_nfs.c | 2 +-
+ fs/nfs/write.c | 14 ++++++++------
+ include/linux/sunrpc/clnt.h | 1 +
+ net/sunrpc/clnt.c | 19 +++++++++++++++++--
+ net/sunrpc/xprtsock.c | 16 ++++++++++++++--
+ 7 files changed, 50 insertions(+), 16 deletions(-)
+Merging nfsd/nfsd-next (26ddc8a26f00b NFSD: Annotate caller preconditions for the state-table walkers)
+$ git merge -m Merge branch 'nfsd-next' of https://git.kernel.org/pub/scm/linux/kernel/git/cel/linux nfsd/nfsd-next
+Auto-merging fs/nfsd/nfsctl.c
+Merge made by the 'ort' strategy.
+ fs/lockd/svc.c | 4 +-
+ fs/lockd/svc4proc.c | 4 +-
+ fs/lockd/svclock.c | 42 +---
+ fs/lockd/svcproc.c | 4 +-
+ fs/lockd/svcsubs.c | 105 +++++++---
+ fs/nfs/callback.c | 4 +-
+ fs/nfs_common/nfslocalio.c | 16 +-
+ fs/nfsd/filecache.c | 143 +++++++-------
+ fs/nfsd/flexfilelayoutxdr.c | 20 +-
+ fs/nfsd/localio.c | 8 +-
+ fs/nfsd/lockd.c | 6 +-
+ fs/nfsd/netns.h | 29 ++-
+ fs/nfsd/nfs2acl.c | 21 +-
+ fs/nfsd/nfs3acl.c | 17 +-
+ fs/nfsd/nfs4callback.c | 113 +++++++++--
+ fs/nfsd/nfs4layouts.c | 39 ++--
+ fs/nfsd/nfs4proc.c | 84 ++++++--
+ fs/nfsd/nfs4recover.c | 48 +++--
+ fs/nfsd/nfs4state.c | 330 ++++++++++++++++++++++---------
+ fs/nfsd/nfs4xdr.c | 27 ++-
+ fs/nfsd/nfscache.c | 4 +-
+ fs/nfsd/nfsctl.c | 79 +++++---
+ fs/nfsd/nfsfh.c | 12 +-
+ fs/nfsd/nfsproc.c | 7 +
+ fs/nfsd/nfssvc.c | 61 +++---
+ fs/nfsd/state.h | 4 +-
+ fs/nfsd/trace.h | 18 +-
+ fs/nfsd/vfs.c | 48 +++--
+ include/linux/lockd/bind.h | 12 +-
+ include/linux/sunrpc/bc_xprt.h | 5 +
+ include/linux/sunrpc/svc.h | 1 +
+ include/linux/sunrpc/svc_rdma_pcl.h | 4 +-
+ net/sunrpc/auth_gss/auth_gss.c | 6 +-
+ net/sunrpc/auth_gss/gss_krb5_unseal.c | 3 +
+ net/sunrpc/auth_gss/gss_krb5_wrap.c | 13 +-
+ net/sunrpc/auth_gss/gss_rpc_upcall.c | 6 -
+ net/sunrpc/auth_gss/gss_rpc_upcall.h | 1 -
+ net/sunrpc/auth_gss/gss_rpc_xdr.c | 15 +-
+ net/sunrpc/auth_gss/svcauth_gss.c | 8 +-
+ net/sunrpc/backchannel_rqst.c | 38 +++-
+ net/sunrpc/cache.c | 7 +-
+ net/sunrpc/sunrpc_syms.c | 1 +
+ net/sunrpc/svc.c | 81 +++++++-
+ net/sunrpc/svcauth_unix.c | 4 +-
+ net/sunrpc/xdr.c | 2 +-
+ net/sunrpc/xprtrdma/ib_client.c | 42 +++-
+ net/sunrpc/xprtrdma/svc_rdma_pcl.c | 63 +++++-
+ net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | 24 ++-
+ net/sunrpc/xprtrdma/svc_rdma_rw.c | 52 +++--
+ net/sunrpc/xprtrdma/svc_rdma_transport.c | 69 +++++--
+ 50 files changed, 1244 insertions(+), 510 deletions(-)
+$ git am -3 ../patches/0001-Revert-smb-client-implement-fileattr_get-to-support-.patch
+Applying: Revert "smb: client: implement fileattr_get to support FS_IOC_GETFLAGS"
+Using index info to reconstruct a base tree...
+M fs/smb/client/cifsfs.c
+M fs/smb/client/cifsfs.h
+M fs/smb/client/inode.c
+Falling back to patching base and 3-way merge...
+Auto-merging fs/smb/client/inode.c
+Auto-merging fs/smb/client/cifsfs.h
+Auto-merging fs/smb/client/cifsfs.c
+No changes -- Patch already applied.
+Merging ntfs/ntfs-next (c02bbc2556708 ntfs: dir: use kmemdup() instead of kmalloc() and memcpy())
+$ git merge -m Merge branch 'ntfs-next' of https://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/ntfs.git ntfs/ntfs-next
+Auto-merging fs/ntfs/aops.c
+Merge made by the 'ort' strategy.
+ fs/ntfs/aops.c | 17 ++++++++++++++-
+ fs/ntfs/attrib.c | 36 ++++++++++++++++++++-----------
+ fs/ntfs/attrlist.c | 9 ++++++++
+ fs/ntfs/dir.c | 20 ++++++++++++------
+ fs/ntfs/index.c | 5 ++++-
+ fs/ntfs/inode.c | 9 ++++++++
+ fs/ntfs/mft.c | 11 ++++++----
+ fs/ntfs/namei.c | 62 +++++++++++++++++++++++++++---------------------------
+ fs/ntfs/reparse.c | 6 ++----
+ 9 files changed, 116 insertions(+), 59 deletions(-)
+Merging ntfs3/master (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'master' of https://github.com/Paragon-Software-Group/linux-ntfs3.git ntfs3/master
+Already up to date.
+Merging orangefs/for-next (e61bc5e4d8743 bufmap: manage as folios, V2.)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/hubcap/linux.git orangefs/for-next
+Already up to date.
+Merging overlayfs/overlayfs-next (1f6ee9be92f8d ovl: make fsync after metadata copy-up opt-in mount option)
+$ git merge -m Merge branch 'overlayfs-next' of https://git.kernel.org/pub/scm/linux/kernel/git/overlayfs/vfs.git overlayfs/overlayfs-next
+Already up to date.
+Merging ubifs/next (11efa98bcc0d0 ubi: ubi.h: fix kernel-doc warnings)
+$ git merge -m Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs.git ubifs/next
+Auto-merging drivers/mtd/ubi/ubi.h
+Merge made by the 'ort' strategy.
+ drivers/mtd/ubi/ubi.h | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+Merging v9fs/9p-next (aa88278693cbf 9p: Add missing read barrier in virtio zero-copy path)
+$ git merge -m Merge branch '9p-next' of https://github.com/martinetd/linux v9fs/9p-next
+Already up to date.
+Merging v9fs-ericvh/ericvh/for-next (028ef9c96e961 Linux 7.0)
+$ git merge -m Merge branch 'ericvh/for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs.git v9fs-ericvh/ericvh/for-next
+Already up to date.
+Merging xfs/for-next (f88caa121eac3 xfs: use xfs_csn_t for xlog_cil_push_now() push_seq parameter)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/fs/xfs/xfs-linux.git xfs/for-next
+Merge made by the 'ort' strategy.
+ fs/xfs/xfs_log_cil.c | 2 +-
+ fs/xfs/xfs_log_recover.c | 26 ++++++++++++++++++--------
+ fs/xfs/xfs_sysfs.c | 28 +++++++++++++++++-----------
+ fs/xfs/xfs_sysfs.h | 2 ++
+ fs/xfs/xfs_zone_alloc.c | 8 ++++++++
+ 5 files changed, 46 insertions(+), 20 deletions(-)
+Merging zonefs/for-next (3a8389d42bdf4 zonefs: handle integer overflow in zonefs_fname_to_fno)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/dlemoal/zonefs.git zonefs/for-next
+Already up to date.
+Merging vfs-brauner/vfs.all (b148f6ef8f3b0 Merge branch 'vfs-7.3.kthread' into vfs.all)
+$ git merge -m Merge branch 'vfs.all' of https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git vfs-brauner/vfs.all
+Auto-merging MAINTAINERS
+Auto-merging fs/afs/dir.c
+Auto-merging fs/bpf_fs_kfuncs.c
+CONFLICT (content): Merge conflict in fs/bpf_fs_kfuncs.c
+Auto-merging fs/btrfs/ioctl.c
+Auto-merging fs/erofs/super.c
+Auto-merging fs/iomap/buffered-io.c
+Auto-merging fs/iomap/direct-io.c
+Auto-merging fs/iomap/ioend.c
+Auto-merging fs/namei.c
+Auto-merging fs/nfs/dir.c
+Auto-merging fs/nfs/internal.h
+Auto-merging fs/ntfs/namei.c
+Auto-merging fs/overlayfs/inode.c
+Auto-merging fs/smb/client/cifsfs.h
+Auto-merging fs/smb/client/inode.c
+Auto-merging fs/smb/server/smb2pdu.c
+Auto-merging fs/smb/server/vfs.c
+Auto-merging fs/xfs/xfs_buf.c
+Auto-merging fs/xfs/xfs_super.c
+Auto-merging include/linux/fs.h
+Auto-merging include/linux/netfs.h
+Auto-merging kernel/fork.c
+Auto-merging tools/testing/selftests/filesystems/.gitignore
+CONFLICT (content): Merge conflict in tools/testing/selftests/filesystems/.gitignore
+Auto-merging tools/testing/selftests/filesystems/Makefile
+CONFLICT (content): Merge conflict in tools/testing/selftests/filesystems/Makefile
+Resolved 'fs/bpf_fs_kfuncs.c' using previous resolution.
+Resolved 'tools/testing/selftests/filesystems/.gitignore' using previous resolution.
+Resolved 'tools/testing/selftests/filesystems/Makefile' using previous resolution.
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit --no-edit -v -a
+[fs-next f39dba15fe5f1] Merge branch 'vfs.all' of https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git
+$ git diff -M --stat --summary HEAD^..
+ Documentation/filesystems/locking.rst | 2 +-
+ Documentation/filesystems/overlayfs.rst | 16 +
+ Documentation/filesystems/porting.rst | 10 +-
+ Documentation/filesystems/vfs.rst | 2 +-
+ MAINTAINERS | 5 -
+ block/bdev.c | 125 +++-
+ drivers/base/devtmpfs.c | 2 +-
+ drivers/block/rnbd/rnbd-srv.c | 4 +-
+ drivers/char/misc_minor_kunit.c | 25 +-
+ drivers/crypto/ccp/sev-dev.c | 12 +-
+ drivers/target/target_core_alua.c | 11 +-
+ drivers/target/target_core_pr.c | 4 +-
+ fs/9p/vfs_inode.c | 5 +-
+ fs/9p/vfs_inode_dotl.c | 4 +-
+ fs/Kconfig | 1 -
+ fs/Makefile | 1 -
+ fs/affs/affs.h | 2 +-
+ fs/affs/namei.c | 4 +-
+ fs/afs/dir.c | 6 +-
+ fs/autofs/root.c | 2 +-
+ fs/bad_inode.c | 2 +-
+ fs/bfs/dir.c | 2 +-
+ fs/bpf_fs_kfuncs.c | 37 ++
+ fs/btrfs/dev-replace.c | 65 ++-
+ fs/btrfs/inode.c | 4 +-
+ fs/btrfs/ioctl.c | 4 +-
+ fs/btrfs/volumes.c | 116 +++-
+ fs/btrfs/volumes.h | 6 +-
+ fs/ceph/dir.c | 3 +-
+ fs/coda/dir.c | 9 +-
+ fs/coredump.c | 11 +-
+ fs/cramfs/inode.c | 2 +-
+ fs/ecryptfs/inode.c | 2 +-
+ fs/efivarfs/inode.c | 2 +-
+ fs/efs/Kconfig | 16 -
+ fs/efs/Makefile | 8 -
+ fs/efs/dir.c | 105 ----
+ fs/efs/efs.h | 144 -----
+ fs/efs/file.c | 42 --
+ fs/efs/inode.c | 315 ----------
+ fs/efs/namei.c | 120 ----
+ fs/efs/super.c | 368 ------------
+ fs/efs/symlink.c | 50 --
+ fs/erofs/super.c | 35 +-
+ fs/exfat/namei.c | 2 +-
+ fs/ext2/namei.c | 4 +-
+ fs/ext4/extents-test.c | 9 +-
+ fs/ext4/mballoc-test.c | 9 +-
+ fs/ext4/namei.c | 4 +-
+ fs/ext4/super.c | 12 +-
+ fs/f2fs/namei.c | 4 +-
+ fs/f2fs/super.c | 6 +-
+ fs/fat/namei_msdos.c | 5 +-
+ fs/fat/namei_vfat.c | 2 +-
+ fs/fs_struct.c | 103 +++-
+ fs/fuse/dir.c | 10 +-
+ fs/gfs2/inode.c | 7 +-
+ fs/hfs/dir.c | 4 +-
+ fs/hfsplus/dir.c | 4 +-
+ fs/hostfs/hostfs_kern.c | 2 +-
+ fs/hpfs/namei.c | 6 +-
+ fs/hugetlbfs/inode.c | 4 +-
+ fs/inode.c | 23 +-
+ fs/internal.h | 1 +
+ fs/iomap/buffered-io.c | 6 +-
+ fs/iomap/direct-io.c | 293 +++++++++-
+ fs/iomap/ioend.c | 21 +-
+ fs/jffs2/dir.c | 6 +-
+ fs/jfs/namei.c | 4 +-
+ fs/kernel_read_file.c | 9 +-
+ fs/minix/namei.c | 4 +-
+ fs/namei.c | 30 +-
+ fs/namespace.c | 25 +-
+ fs/nfs/blocklayout/dev.c | 15 +-
+ fs/nfs/dir.c | 6 +-
+ fs/nfs/internal.h | 2 +-
+ fs/nilfs2/namei.c | 4 +-
+ fs/ntfs/namei.c | 4 +-
+ fs/ntfs3/namei.c | 4 +-
+ fs/nullfs.c | 14 +-
+ fs/ocfs2/dlmfs/dlmfs.c | 5 +-
+ fs/ocfs2/namei.c | 5 +-
+ fs/ocfs2/super.c | 1 -
+ fs/omfs/dir.c | 4 +-
+ fs/orangefs/namei.c | 5 +-
+ fs/overlayfs/dir.c | 18 +-
+ fs/overlayfs/inode.c | 26 +-
+ fs/overlayfs/overlayfs.h | 1 +
+ fs/overlayfs/super.c | 2 +-
+ fs/overlayfs/xattrs.c | 1 +
+ fs/posix_acl.c | 2 -
+ fs/proc/array.c | 4 +-
+ fs/proc/base.c | 8 +-
+ fs/proc_namespace.c | 4 +-
+ fs/ramfs/inode.c | 4 +-
+ fs/romfs/super.c | 10 +-
+ fs/smb/client/cifsfs.h | 2 +-
+ fs/smb/client/dir.c | 2 +-
+ fs/smb/client/inode.c | 7 +
+ fs/smb/server/mgmt/share_config.c | 4 +-
+ fs/smb/server/smb2pdu.c | 4 +-
+ fs/smb/server/vfs.c | 9 +-
+ fs/super.c | 639 ++++++++++++++-------
+ fs/ubifs/dir.c | 4 +-
+ fs/udf/namei.c | 4 +-
+ fs/ufs/namei.c | 5 +-
+ fs/vboxsf/dir.c | 4 +-
+ fs/xfs/xfs_buf.c | 2 +-
+ fs/xfs/xfs_iops.c | 7 +-
+ fs/xfs/xfs_super.c | 10 +-
+ include/linux/blk_types.h | 2 +-
+ include/linux/blkdev.h | 12 +-
+ include/linux/efs_vh.h | 54 --
+ include/linux/fs.h | 4 +-
+ include/linux/fs/super.h | 8 +
+ include/linux/fs/super_types.h | 4 +-
+ include/linux/fs_struct.h | 34 ++
+ include/linux/init_task.h | 1 +
+ include/linux/net.h | 1 +
+ include/linux/sched.h | 1 +
+ include/linux/sched/task.h | 1 +
+ include/linux/types.h | 2 +
+ include/uapi/asm-generic/errno.h | 2 +-
+ include/uapi/linux/efs_fs_sb.h | 63 --
+ init/init_task.c | 1 +
+ init/initramfs.c | 14 +-
+ init/initramfs_test.c | 220 +++----
+ init/main.c | 10 +-
+ ipc/mqueue.c | 7 +-
+ kernel/exit.c | 2 +-
+ kernel/fork.c | 53 +-
+ kernel/kcmp.c | 2 +-
+ kernel/umh.c | 6 +-
+ mm/shmem.c | 2 +-
+ net/socket.c | 25 +
+ net/unix/af_unix.c | 17 +-
+ tools/testing/selftests/bpf/bpf_experimental.h | 3 +
+ .../testing/selftests/bpf/prog_tests/sock_xattr.c | 67 +++
+ .../testing/selftests/bpf/progs/sock_read_xattr.c | 54 ++
+ tools/testing/selftests/filesystems/.gitignore | 1 +
+ tools/testing/selftests/filesystems/Makefile | 2 +-
+ .../selftests/filesystems/overlayfs/.gitignore | 1 +
+ .../selftests/filesystems/overlayfs/Makefile | 2 +
+ .../filesystems/overlayfs/idmapped_mounts.c | 501 ++++++++++++++++
+ .../filesystems/overlayfs/set_layers_via_fds.c | 16 +-
+ .../filesystems/statmount/statmount_test.c | 5 +-
+ tools/testing/selftests/filesystems/ustat_test.c | 135 +++++
+ tools/testing/selftests/proc/proc-pidns.c | 1 +
+ 148 files changed, 2536 insertions(+), 1982 deletions(-)
+ delete mode 100644 fs/efs/Kconfig
+ delete mode 100644 fs/efs/Makefile
+ delete mode 100644 fs/efs/dir.c
+ delete mode 100644 fs/efs/efs.h
+ delete mode 100644 fs/efs/file.c
+ delete mode 100644 fs/efs/inode.c
+ delete mode 100644 fs/efs/namei.c
+ delete mode 100644 fs/efs/super.c
+ delete mode 100644 fs/efs/symlink.c
+ delete mode 100644 include/linux/efs_vh.h
+ delete mode 100644 include/uapi/linux/efs_fs_sb.h
+ create mode 100644 tools/testing/selftests/bpf/prog_tests/sock_xattr.c
+ create mode 100644 tools/testing/selftests/bpf/progs/sock_read_xattr.c
+ create mode 100644 tools/testing/selftests/filesystems/overlayfs/idmapped_mounts.c
+ create mode 100644 tools/testing/selftests/filesystems/ustat_test.c
+$ git am -3 ../patches/0001-ksmbd-Fix-removal-of-type-parameter-from-vfs_path_pa.patch
+Applying: ksmbd: Fix removal of type parameter from vfs_path_parent_lookup()
+Using index info to reconstruct a base tree...
+M fs/smb/server/vfs.c
+Falling back to patching base and 3-way merge...
+Auto-merging fs/smb/server/vfs.c
+No changes -- Patch already applied.
+Merging vfs/for-next (4dda01b67c866 Merge branches 'work.dcache', 'work.dcache-d_add' and 'work.configfs' into for-next)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs.git vfs/for-next
+Merge made by the 'ort' strategy.
+Merging mm-hotfixes/mm-hotfixes-unstable (198e0efeba02b mm: mglru: fix stale batch updates after memcg reparenting)
+$ git merge -m Merge branch 'mm-hotfixes-unstable' of https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm mm-hotfixes/mm-hotfixes-unstable
+Merge made by the 'ort' strategy.
+ .mailmap | 1 +
+ Documentation/ABI/testing/sysfs-kernel-mm-damon | 174 ++++++++++++------------
+ MAINTAINERS | 3 +-
+ arch/m68k/include/asm/page_mm.h | 2 +
+ drivers/virtio/virtio_balloon.c | 5 +-
+ fs/fat/fat.h | 4 +-
+ fs/fat/fat_test.c | 4 +-
+ fs/proc/task_mmu.c | 41 +++++-
+ include/linux/damon.h | 2 -
+ include/linux/page_reporting.h | 4 +-
+ include/trace/events/memory-failure.h | 6 +-
+ lib/bug.c | 2 -
+ lib/test_hmm.c | 2 +-
+ mm/damon/core.c | 15 +-
+ mm/damon/lru_sort.c | 2 -
+ mm/damon/modules-common.c | 2 -
+ mm/damon/modules-common.h | 2 -
+ mm/damon/ops-common.c | 2 -
+ mm/damon/ops-common.h | 2 -
+ mm/damon/paddr.c | 2 -
+ mm/damon/reclaim.c | 2 -
+ mm/damon/sysfs-common.c | 2 -
+ mm/damon/sysfs-common.h | 2 -
+ mm/damon/sysfs-schemes.c | 2 -
+ mm/damon/sysfs.c | 2 -
+ mm/damon/tests/core-kunit.h | 4 -
+ mm/damon/tests/sysfs-kunit.h | 2 -
+ mm/damon/tests/vaddr-kunit.h | 4 -
+ mm/damon/vaddr.c | 2 -
+ mm/huge_memory.c | 14 +-
+ mm/hugetlb.c | 22 ++-
+ mm/hugetlb_cma.c | 2 +-
+ mm/kmemleak.c | 7 +-
+ mm/memremap.c | 1 +
+ mm/migrate.c | 6 +-
+ mm/migrate_device.c | 5 +-
+ mm/mm_init.c | 15 +-
+ mm/page_reporting.c | 24 ++--
+ mm/page_vma_mapped.c | 33 +++--
+ mm/percpu-km.c | 2 +-
+ mm/userfaultfd.c | 5 +-
+ mm/util.c | 2 +-
+ mm/vmscan.c | 41 +++++-
+ tools/testing/selftests/mm/pagemap_ioctl.c | 110 ++++++++++++++-
+ 44 files changed, 387 insertions(+), 201 deletions(-)
+Merging fs-current (ecb6a42490f8c Merge branch 'nfsd-fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/cel/linux)
+$ git merge -m Merge branch 'fs-current' of linux-next fs-current
+Merge made by the 'ort' strategy.
+ fs/btrfs/file-item.c | 26 +++++++++++++++++++++++++-
+ fs/btrfs/free-space-cache.c | 3 +++
+ fs/btrfs/ioctl.c | 18 ++++++++++++------
+ fs/btrfs/lzo.c | 15 ++++++++++++---
+ fs/btrfs/print-tree.c | 8 ++++----
+ fs/btrfs/props.c | 16 +++++++++++++---
+ fs/btrfs/relocation.c | 15 +++++++--------
+ fs/btrfs/tree-checker.c | 6 ++++++
+ fs/erofs/ishare.c | 8 +-------
+ fs/erofs/super.c | 17 ++++-------------
+ fs/erofs/zmap.c | 3 ++-
+ fs/nfsd/nfsctl.c | 7 ++++---
+ 12 files changed, 93 insertions(+), 49 deletions(-)
+Merging kbuild-current/kbuild-fixes-for-next (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'kbuild-fixes-for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/kbuild/linux.git kbuild-current/kbuild-fixes-for-next
+Already up to date.
+Merging clang-fixes/clang-fixes-for-next (175db11786bde Disable -Wattribute-alias for clang-23 and newer)
+$ git merge -m Merge branch 'clang-fixes-for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/nathan/linux.git clang-fixes/clang-fixes-for-next
+Already up to date.
+Merging arc-current/for-curr (7aaa8047eafd0 Linux 7.0-rc6)
+$ git merge -m Merge branch 'for-curr' of https://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc.git arc-current/for-curr
+Already up to date.
+Merging arm-current/fixes (009b6c6486b94 ARM: 9476/1: mm: fix kexec and hibernation with CONFIG_CPU_TTBR0_PAN)
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/rmk/linux.git arm-current/fixes
+Already up to date.
+Merging arm64-fixes/for-next/fixes (a52d6c7160f7e selftests/arm64: fix spelling errors in comments)
+$ git merge -m Merge branch 'for-next/fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux arm64-fixes/for-next/fixes
+Merge made by the 'ort' strategy.
+ Documentation/arch/arm64/cpu-hotplug.rst | 28 +++++++++-------
+ arch/arm64/include/asm/tlbbatch.h | 10 ++----
+ arch/arm64/include/asm/tlbflush.h | 49 +++++-----------------------
+ arch/arm64/kernel/acpi.c | 2 ++
+ arch/arm64/kernel/fpsimd.c | 10 ++++--
+ arch/arm64/kernel/process.c | 35 --------------------
+ arch/arm64/kernel/smp.c | 28 ++++++++--------
+ arch/arm64/mm/mmu.c | 11 +++++--
+ arch/arm64/tools/sysreg | 2 +-
+ tools/testing/selftests/arm64/gcs/libc-gcs.c | 2 +-
+ tools/testing/selftests/arm64/pauth/pac.c | 2 +-
+ 11 files changed, 61 insertions(+), 118 deletions(-)
+Merging arm-soc-fixes/arm/fixes (9c648f3554920 Merge tag 'v7.1-rockchip-arm32fixe' of https://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip into arm/fixes)
+$ git merge -m Merge branch 'arm/fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git arm-soc-fixes/arm/fixes
+Already up to date.
+Merging davinci-current/davinci/for-current (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'davinci/for-current' of https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git davinci-current/davinci/for-current
+Already up to date.
+Merging drivers-memory-fixes/fixes (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl.git drivers-memory-fixes/fixes
+Already up to date.
+Merging sophgo-fixes/fixes (19272b37aa4f8 Linux 6.16-rc1)
+$ git merge -m Merge branch 'fixes' of https://github.com/sophgo/linux.git sophgo-fixes/fixes
+Already up to date.
+Merging sophgo-soc-fixes/soc-fixes (0af2f6be1b428 Linux 6.15-rc1)
+$ git merge -m Merge branch 'soc-fixes' of https://github.com/sophgo/linux.git sophgo-soc-fixes/soc-fixes
+Already up to date.
+Merging m68k-current/for-linus (dc5200f6b1ada m68k: Correct CONFIG_MVME16x macro name in #endif comment)
+$ git merge -m Merge branch 'for-linus' of https://git.kernel.org/pub/scm/linux/kernel/git/geert/linux-m68k.git m68k-current/for-linus
+Already up to date.
+Merging powerpc-fixes/fixes (8cdeaa50eae8d Linux 7.2-rc2)
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git powerpc-fixes/fixes
+Already up to date.
+Merging s390-fixes/fixes (7d5c2f6791478 s390: Add build salt to the vDSO)
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/s390/linux.git s390-fixes/fixes
+Merge made by the 'ort' strategy.
+ arch/s390/kernel/diag/diag310.c | 7 ++++---
+ arch/s390/kernel/vdso/note.S | 3 +++
+ arch/s390/mm/mmap.c | 2 +-
+ drivers/s390/crypto/zcrypt_cex2a.c | 0
+ drivers/s390/crypto/zcrypt_cex2a.h | 0
+ drivers/s390/crypto/zcrypt_cex2c.c | 0
+ drivers/s390/crypto/zcrypt_cex2c.h | 0
+ 7 files changed, 8 insertions(+), 4 deletions(-)
+ delete mode 100644 drivers/s390/crypto/zcrypt_cex2a.c
+ delete mode 100644 drivers/s390/crypto/zcrypt_cex2a.h
+ delete mode 100644 drivers/s390/crypto/zcrypt_cex2c.c
+ delete mode 100644 drivers/s390/crypto/zcrypt_cex2c.h
+Merging net/main (2c7c88a412aa6 Merge tag 'net-7.2-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net)
+$ git merge -m Merge branch 'main' of https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git net/main
+Already up to date.
+Merging bpf/master (7cbd0c4cebe4c bpf: Fix UAF in sock clone early bailouts)
+$ git merge -m Merge branch 'master' of https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf.git/ bpf/master
+Merge made by the 'ort' strategy.
+ net/core/bpf_sk_storage.c | 2 --
+ net/core/sock.c | 3 +++
+ 2 files changed, 3 insertions(+), 2 deletions(-)
+Merging ipsec/master (f38f8cce2f7e7 xfrm: policy: preallocate inexact bins before xfrm_hash_rebuild reinsert)
+$ git merge -m Merge branch 'master' of https://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec.git ipsec/master
+Merge made by the 'ort' strategy.
+ include/net/xfrm.h | 2 ++
+ net/core/dev.c | 10 ++++++++--
+ net/ipv6/xfrm6_policy.c | 1 +
+ net/xfrm/xfrm_device.c | 13 +++++++++++--
+ net/xfrm/xfrm_iptfs.c | 1 +
+ net/xfrm/xfrm_nat_keepalive.c | 15 +++++++++------
+ net/xfrm/xfrm_policy.c | 4 ++--
+ net/xfrm/xfrm_state.c | 12 +++++++++---
+ net/xfrm/xfrm_user.c | 41 ++++++++++++++++++++++++++++++-----------
+ 9 files changed, 73 insertions(+), 26 deletions(-)
+Merging netfilter/main (2c7c88a412aa6 Merge tag 'net-7.2-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net)
+$ git merge -m Merge branch 'main' of https://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf.git netfilter/main
+Already up to date.
+Merging ipvs/main (60444706aa176 net: usb: lan78xx: disable VLAN filter in promiscuous mode)
+$ git merge -m Merge branch 'main' of https://git.kernel.org/pub/scm/linux/kernel/git/horms/ipvs.git ipvs/main
+Already up to date.
+Merging wireless/for-next (cb8afea4655ff wifi: cfg80211: bound element ID read when checking non-inheritance)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless.git wireless/for-next
+Merge made by the 'ort' strategy.
+ .../broadcom/brcm80211/brcmfmac/cyw/core.c | 6 ++
+ .../wireless/broadcom/brcm80211/brcmfmac/sdio.c | 2 +-
+ drivers/net/wireless/intel/ipw2x00/ipw2100.c | 8 +-
+ drivers/net/wireless/intel/ipw2x00/libipw_rx.c | 4 +-
+ drivers/net/wireless/intersil/p54/txrx.c | 8 ++
+ drivers/net/wireless/marvell/libertas/firmware.c | 1 +
+ drivers/net/wireless/marvell/libertas/tx.c | 7 ++
+ drivers/net/wireless/marvell/libertas_tf/main.c | 2 +-
+ drivers/net/wireless/marvell/mwifiex/cfg80211.c | 2 +-
+ drivers/net/wireless/marvell/mwifiex/join.c | 1 -
+ drivers/net/wireless/ralink/rt2x00/rt2400pci.c | 2 +-
+ drivers/net/wireless/ralink/rt2x00/rt2500pci.c | 2 +-
+ drivers/net/wireless/ralink/rt2x00/rt2800pci.c | 2 +-
+ drivers/net/wireless/ralink/rt2x00/rt2x00dev.c | 12 ++-
+ drivers/net/wireless/ralink/rt2x00/rt61pci.c | 2 +-
+ drivers/net/wireless/rsi/rsi_91x_hal.c | 8 ++
+ drivers/net/wireless/rsi/rsi_91x_mgmt.c | 12 ++-
+ drivers/net/wireless/virtual/mac80211_hwsim_main.c | 16 +++-
+ include/linux/ieee80211-eht.h | 12 +--
+ include/net/cfg80211.h | 4 +-
+ net/mac80211/cfg.c | 11 ++-
+ net/mac80211/ibss.c | 13 +--
+ net/mac80211/iface.c | 8 +-
+ net/mac80211/main.c | 3 +-
+ net/mac80211/mlme.c | 12 ++-
+ net/mac80211/nan.c | 35 +++----
+ net/mac80211/rx.c | 34 ++++++-
+ net/mac80211/sta_info.c | 15 ++-
+ net/mac80211/tx.c | 17 +++-
+ net/mac80211/util.c | 3 +
+ net/wireless/core.c | 14 +--
+ net/wireless/core.h | 4 +-
+ net/wireless/mlme.c | 105 +++++++++++++++------
+ net/wireless/nl80211.c | 25 +++--
+ net/wireless/pmsr.c | 34 +++++--
+ net/wireless/scan.c | 18 ++--
+ net/wireless/sme.c | 6 +-
+ 37 files changed, 336 insertions(+), 134 deletions(-)
+Merging ath/for-current (55f3aa06951ca wifi: ath12k: Flush the posted write after writing to PCIE_SOC_GLOBAL_RESET)
+$ git merge -m Merge branch 'for-current' of https://git.kernel.org/pub/scm/linux/kernel/git/ath/ath.git ath/for-current
+Merge made by the 'ort' strategy.
+ drivers/net/wireless/ath/ath10k/htt_rx.c | 2 ++
+ drivers/net/wireless/ath/ath11k/ahb.c | 1 +
+ drivers/net/wireless/ath/ath11k/dp_rx.c | 3 +++
+ drivers/net/wireless/ath/ath11k/pci.c | 4 ++++
+ drivers/net/wireless/ath/ath11k/qmi.c | 11 ++++++++---
+ drivers/net/wireless/ath/ath12k/pci.c | 4 ++++
+ drivers/net/wireless/ath/ath6kl/txrx.c | 2 +-
+ drivers/net/wireless/ath/ath9k/hif_usb.c | 7 +------
+ 8 files changed, 24 insertions(+), 10 deletions(-)
+Merging iwlwifi/fixes (093305d801fae wifi: iwlwifi: pcie: simplify the resume flow if fast resume is not used)
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next.git iwlwifi/fixes
+Already up to date.
+Merging wpan/master (8ce4f287524c7 net: libwx: fix firmware mailbox abnormal return)
+$ git merge -m Merge branch 'master' of https://git.kernel.org/pub/scm/linux/kernel/git/wpan/wpan.git wpan/master
+Already up to date.
+Merging rdma-fixes/for-rc (3cda0dfe8c651 RDMA/irdma: Prevent overflows in memory contiguity checks)
+$ git merge -m Merge branch 'for-rc' of https://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma.git rdma-fixes/for-rc
+Merge made by the 'ort' strategy.
+ drivers/infiniband/core/cma.c | 2 +-
+ drivers/infiniband/core/mad.c | 30 ++++++++++++++++++++++
+ drivers/infiniband/core/verbs.c | 6 ++---
+ drivers/infiniband/hw/erdma/erdma_qp.c | 2 +-
+ drivers/infiniband/hw/hns/hns_roce_hem.c | 2 +-
+ drivers/infiniband/hw/irdma/verbs.c | 26 ++++++++++---------
+ drivers/infiniband/hw/mana/wr.c | 2 +-
+ drivers/infiniband/hw/mlx5/wr.c | 16 +++++++-----
+ drivers/infiniband/sw/siw/siw_verbs.c | 44 +++++++++++++++++---------------
+ 9 files changed, 84 insertions(+), 46 deletions(-)
+Merging sound-current/for-linus (8ca0016a9b799 ALSA: hda: MAINTAINERS: Fix missing cirrus* file reference)
+$ git merge -m Merge branch 'for-linus' of https://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git sound-current/for-linus
+Auto-merging MAINTAINERS
+Merge made by the 'ort' strategy.
+ MAINTAINERS | 1 +
+ sound/firewire/bebob/bebob.h | 1 -
+ sound/firewire/dice/dice.h | 1 -
+ sound/firewire/digi00x/digi00x.h | 1 -
+ sound/firewire/fireface/ff.h | 1 -
+ sound/firewire/fireworks/fireworks.h | 1 -
+ sound/firewire/motu/motu.h | 1 -
+ sound/firewire/oxfw/oxfw.h | 1 -
+ sound/firewire/tascam/tascam.h | 1 -
+ sound/hda/codecs/realtek/alc269.c | 39 +++++++++++++++++++++++++++++--
+ sound/hda/codecs/side-codecs/Kconfig | 2 +-
+ sound/hda/core/regmap.c | 4 ++--
+ sound/usb/caiaq/device.c | 17 +++++++++++---
+ sound/usb/caiaq/input.c | 6 +++++
+ sound/usb/mixer.c | 2 +-
+ sound/usb/quirks.c | 2 ++
+ tools/testing/selftests/alsa/mixer-test.c | 5 ++--
+ 17 files changed, 67 insertions(+), 19 deletions(-)
+Merging sound-asoc-fixes/for-linus (3238c634725af ASoC: tas2562: fix deprecated 'shut-down' GPIO always cleared after lookup)
+$ git merge -m Merge branch 'for-linus' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git sound-asoc-fixes/for-linus
+Merge made by the 'ort' strategy.
+ .../bindings/sound/qcom,lpass-rx-macro.yaml | 1 +
+ .../bindings/sound/qcom,lpass-tx-macro.yaml | 1 +
+ .../bindings/sound/qcom,lpass-va-macro.yaml | 1 +
+ .../bindings/sound/qcom,lpass-wsa-macro.yaml | 1 +
+ .../devicetree/bindings/sound/qcom,sm8250.yaml | 1 +
+ sound/soc/amd/acp/Kconfig | 10 +++--
+ sound/soc/amd/acp/Makefile | 3 +-
+ sound/soc/amd/acp/amd-acp70-acpi-match.c | 47 +++++++++++++++++++++-
+ sound/soc/amd/acp/soc-acpi-amd-sdca-quirks.c | 4 --
+ sound/soc/amd/ps/pci-ps.c | 33 ++++++++++++++-
+ sound/soc/codecs/cs42l43-jack.c | 3 +-
+ sound/soc/codecs/rt712-sdca.c | 11 +++++
+ sound/soc/codecs/tas2562.c | 5 ++-
+ sound/soc/intel/boards/sof_sdw.c | 1 +
+ sound/soc/meson/aiu-fifo-spdif.c | 5 +++
+ sound/soc/qcom/sc8280xp.c | 1 +
+ 16 files changed, 113 insertions(+), 15 deletions(-)
+Merging regmap-fixes/for-linus (fabc5b59d3e64 Merge remote-tracking branch 'regmap/for-7.1' into regmap-linus)
+$ git merge -m Merge branch 'for-linus' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git regmap-fixes/for-linus
+Merge made by the 'ort' strategy.
+Merging regulator-fixes/for-linus (d38f8bd771c49 regulator: core: regulator_lock_two() should test for EDEADLK not EDEADLOCK)
+$ git merge -m Merge branch 'for-linus' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git regulator-fixes/for-linus
+Merge made by the 'ort' strategy.
+ drivers/regulator/core.c | 4 ++--
+ drivers/regulator/mt6316-regulator.c | 1 +
+ drivers/regulator/mt6363-regulator.c | 1 +
+ 3 files changed, 4 insertions(+), 2 deletions(-)
+Merging spi-fixes/for-linus (c5fe489535682 Merge remote-tracking branch 'spi/for-7.1' into spi-linus)
+$ git merge -m Merge branch 'for-linus' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git spi-fixes/for-linus
+Merge made by the 'ort' strategy.
+Merging pci-current/for-linus (34db32102439d MAINTAINERS: Drop Karthikeyan Mitran from Mobiveil PCIe entry)
+$ git merge -m Merge branch 'for-linus' of https://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git pci-current/for-linus
+Auto-merging MAINTAINERS
+Merge made by the 'ort' strategy.
+ MAINTAINERS | 1 -
+ 1 file changed, 1 deletion(-)
+Merging driver-core.current/driver-core-linus (667d0fb32149f driver core: add missing kernel-doc for union members)
+$ git merge -m Merge branch 'driver-core-linus' of https://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core.git driver-core.current/driver-core-linus
+Merge made by the 'ort' strategy.
+ include/linux/device.h | 2 ++
+ 1 file changed, 2 insertions(+)
+Merging tty.current/tty-linus (22dd2777e6c18 serial: msm: Disable DMA for kernel console UART)
+$ git merge -m Merge branch 'tty-linus' of https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tty.current/tty-linus
+Auto-merging drivers/tty/serial/max310x.c
+Merge made by the 'ort' strategy.
+ drivers/tty/serial/max310x.c | 12 ++++++++++++
+ drivers/tty/serial/msm_serial.c | 3 ++-
+ 2 files changed, 14 insertions(+), 1 deletion(-)
+Merging usb.current/usb-linus (6df47500b557e USB: core: ratelimit cabling message)
+$ git merge -m Merge branch 'usb-linus' of https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb.current/usb-linus
+Auto-merging MAINTAINERS
+Auto-merging drivers/usb/typec/tcpm/tcpci_rt1711h.c
+Merge made by the 'ort' strategy.
+ .../ABI/testing/sysfs-bus-pci-drivers-xhci_hcd | 2 +-
+ MAINTAINERS | 1 +
+ drivers/usb/atm/ueagle-atm.c | 36 +++++++++++--
+ drivers/usb/cdns3/cdnsp-mem.c | 2 +
+ drivers/usb/class/cdc-acm.c | 3 ++
+ drivers/usb/common/ulpi.c | 23 ++++----
+ drivers/usb/core/hub.c | 2 +-
+ drivers/usb/core/quirks.c | 6 +++
+ drivers/usb/dwc3/core.c | 4 +-
+ drivers/usb/dwc3/dwc3-meson-g12a.c | 14 +++--
+ drivers/usb/dwc3/gadget.c | 43 ++++++++++++---
+ drivers/usb/fotg210/fotg210-hcd.c | 6 ++-
+ drivers/usb/gadget/composite.c | 5 +-
+ drivers/usb/gadget/function/f_fs.c | 9 ++--
+ drivers/usb/gadget/function/f_printer.c | 3 +-
+ drivers/usb/gadget/function/rndis.c | 20 +++++--
+ drivers/usb/gadget/udc/core.c | 29 +++++++++-
+ drivers/usb/host/ehci-sched.c | 11 +++-
+ drivers/usb/host/sl811-hcd.c | 1 +
+ drivers/usb/host/xhci-dbgcap.c | 60 ++++++++++++++++++++-
+ drivers/usb/host/xhci-dbgcap.h | 3 ++
+ drivers/usb/host/xhci-sideband.c | 2 +
+ drivers/usb/host/xhci.c | 11 +++-
+ drivers/usb/misc/chaoskey.c | 1 -
+ drivers/usb/misc/idmouse.c | 45 ++++++++--------
+ drivers/usb/misc/iowarrior.c | 61 ++++++++++------------
+ drivers/usb/misc/ldusb.c | 38 +++++++-------
+ drivers/usb/misc/legousbtower.c | 37 ++++++-------
+ drivers/usb/misc/usbio.c | 8 ++-
+ drivers/usb/misc/uss720.c | 5 +-
+ drivers/usb/mtu3/mtu3_gadget.c | 1 +
+ drivers/usb/serial/digi_acceleport.c | 43 +++++++++++----
+ drivers/usb/serial/keyspan_pda.c | 2 +-
+ drivers/usb/serial/option.c | 16 ++++++
+ drivers/usb/storage/ene_ub6250.c | 3 +-
+ drivers/usb/storage/usb.c | 2 +-
+ drivers/usb/typec/anx7411.c | 4 +-
+ drivers/usb/typec/class.c | 1 +
+ drivers/usb/typec/mux.c | 13 +----
+ drivers/usb/typec/mux/ps883x.c | 6 +--
+ drivers/usb/typec/tcpm/tcpci_rt1711h.c | 13 +++--
+ drivers/usb/typec/tcpm/tcpm.c | 9 +++-
+ drivers/usb/typec/ucsi/displayport.c | 7 ++-
+ drivers/usb/typec/ucsi/ucsi.c | 20 +++++++
+ drivers/usb/typec/ucsi/ucsi.h | 1 +
+ drivers/usb/typec/ucsi/ucsi_acpi.c | 10 +++-
+ drivers/usb/typec/ucsi/ucsi_ccg.c | 2 +-
+ drivers/usb/typec/ucsi/ucsi_huawei_gaokun.c | 12 ++---
+ drivers/usb/usbip/vudc.h | 1 -
+ drivers/usb/usbip/vudc_dev.c | 4 +-
+ tools/usb/usbip/libsrc/usbip_common.c | 2 +
+ tools/usb/usbip/libsrc/usbip_device_driver.c | 4 ++
+ tools/usb/usbip/libsrc/vhci_driver.c | 1 +
+ 53 files changed, 463 insertions(+), 205 deletions(-)
+Merging usb-serial-fixes/usb-linus (6bfc8d01ac406 USB: serial: keyspan_pda: fix information leak)
+$ git merge -m Merge branch 'usb-linus' of https://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial.git usb-serial-fixes/usb-linus
+Already up to date.
+Merging phy/fixes (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy.git phy/fixes
+Already up to date.
+Merging staging.current/staging-linus (1463ca3ec6601 staging: rtl8723bs: fix OOB reads in rtw_get_sec_ie(), rtw_get_wapi_ie(), and rtw_get_wps_attr())
+$ git merge -m Merge branch 'staging-linus' of https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git staging.current/staging-linus
+Merge made by the 'ort' strategy.
+ drivers/staging/rtl8723bs/core/rtw_ieee80211.c | 15 +++++++++++++++
+ drivers/staging/rtl8723bs/core/rtw_mlme_ext.c | 20 +++++++++++++++++++-
+ drivers/staging/rtl8723bs/core/rtw_wlan_util.c | 23 ++++++++++++++++++-----
+ drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c | 8 ++++++++
+ drivers/staging/rtl8723bs/os_dep/xmit_linux.c | 6 ++++--
+ drivers/staging/vme_user/vme_fake.c | 8 ++++++++
+ drivers/staging/vme_user/vme_tsi148.c | 8 ++++++++
+ drivers/staging/vme_user/vme_user.c | 22 ++++++++++++++++++++++
+ 8 files changed, 102 insertions(+), 8 deletions(-)
+Merging iio-fixes/fixes-togreg (b7c969d0d445c iio: adc: max14001: add missing 'select REGMAP' to Kconfig)
+$ git merge -m Merge branch 'fixes-togreg' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git iio-fixes/fixes-togreg
+Auto-merging drivers/iio/adc/lpc32xx_adc.c
+Auto-merging drivers/iio/adc/nxp-sar-adc.c
+Auto-merging drivers/iio/adc/spear_adc.c
+Auto-merging drivers/iio/adc/ti-ads124s08.c
+Auto-merging drivers/iio/dac/mcp47feb02.c
+Auto-merging drivers/iio/light/al3010.c
+Auto-merging drivers/iio/orientation/hid-sensor-rotation.c
+Merge made by the 'ort' strategy.
+ drivers/android/binder.c | 31 +++++++--
+ drivers/android/binder/allocation.rs | 5 +-
+ drivers/android/binder/error.rs | 13 ++--
+ drivers/android/binder/freeze.rs | 11 +++-
+ drivers/android/binder/node.rs | 10 +--
+ drivers/android/binder/process.rs | 18 ++++-
+ drivers/android/binder/rust_binder_events.c | 7 +-
+ drivers/android/binder/stats.rs | 4 +-
+ drivers/android/binder/thread.rs | 65 ++++++++++++------
+ drivers/android/binder/transaction.rs | 15 ++---
+ drivers/hid/hid-sensor-hub.c | 77 ++++++++++++++++++++--
+ drivers/iio/accel/bmc150-accel-core.c | 2 +
+ drivers/iio/accel/kxsd9.c | 5 +-
+ drivers/iio/adc/Kconfig | 5 ++
+ drivers/iio/adc/lpc32xx_adc.c | 4 +-
+ drivers/iio/adc/nxp-sar-adc.c | 4 +-
+ drivers/iio/adc/spear_adc.c | 3 +-
+ drivers/iio/adc/ti-ads1119.c | 6 +-
+ drivers/iio/adc/ti-ads124s08.c | 3 +-
+ drivers/iio/common/st_sensors/st_sensors_core.c | 23 +++++--
+ drivers/iio/dac/mcp47feb02.c | 37 ++++++-----
+ drivers/iio/imu/adis_trigger.c | 2 +-
+ drivers/iio/imu/bmi160/bmi160_core.c | 3 +-
+ drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c | 4 +-
+ drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c | 9 +--
+ drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h | 1 +
+ drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c | 4 +-
+ drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 21 +++++-
+ drivers/iio/industrialio-event.c | 5 +-
+ drivers/iio/light/Kconfig | 3 +
+ drivers/iio/light/al3010.c | 2 +-
+ drivers/iio/light/gp2ap002.c | 2 +-
+ drivers/iio/light/tsl2591.c | 6 +-
+ drivers/iio/orientation/hid-sensor-rotation.c | 40 ++++++++++-
+ drivers/iio/pressure/mpl115.c | 4 +-
+ drivers/iio/temperature/Makefile | 2 +-
+ include/linux/hid-sensor-hub.h | 25 +++++++
+ 37 files changed, 364 insertions(+), 117 deletions(-)
+Merging watchdog-fixes/watchdog (7362ba0f9c96a watchdog: pretimeout: Fix UAF in watchdog_unregister_governor())
+$ git merge -m Merge branch 'watchdog' of https://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git watchdog-fixes/watchdog
+Merge made by the 'ort' strategy.
+ Documentation/watchdog/watchdog-parameters.rst | 4 ++--
+ drivers/watchdog/ni903x_wdt.c | 7 ++++++-
+ drivers/watchdog/s32g_wdt.c | 3 +--
+ drivers/watchdog/watchdog_pretimeout.c | 2 ++
+ 4 files changed, 11 insertions(+), 5 deletions(-)
+Merging counter-current/counter-current (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'counter-current' of https://git.kernel.org/pub/scm/linux/kernel/git/wbg/counter.git counter-current/counter-current
+Already up to date.
+Merging char-misc.current/char-misc-linus (3585cfd456373 Merge tag 'iio-fixes-for-7.2a' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/jic23/iio into char-misc-linus)
+$ git merge -m Merge branch 'char-misc-linus' of https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git char-misc.current/char-misc-linus
+Already up to date.
+Merging soundwire-fixes/fixes (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire.git soundwire-fixes/fixes
+Already up to date.
+Merging thunderbolt-fixes/fixes (db79679595326 thunderbolt: Bound the DROM dual link port number before indexing sw->ports)
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/westeri/thunderbolt.git thunderbolt-fixes/fixes
+Merge made by the 'ort' strategy.
+ drivers/thunderbolt/eeprom.c | 9 ++++++++-
+ drivers/thunderbolt/stream.c | 2 +-
+ drivers/thunderbolt/tb.c | 2 +-
+ 3 files changed, 10 insertions(+), 3 deletions(-)
+Merging input-current/for-linus (536394ec81419 Input: maple_keyb - set driver data before registering input device)
+$ git merge -m Merge branch 'for-linus' of https://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git input-current/for-linus
+Merge made by the 'ort' strategy.
+ drivers/input/joystick/maplecontrol.c | 3 ++-
+ drivers/input/keyboard/maple_keyb.c | 4 ++--
+ drivers/input/mouse/maplemouse.c | 9 ++++++---
+ 3 files changed, 10 insertions(+), 6 deletions(-)
+Merging crypto-current/master (6ea0ce3a19f9c crypto: tegra - fix refcount leak in tegra_se_host1x_submit())
+$ git merge -m Merge branch 'master' of https://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6.git crypto-current/master
+Already up to date.
+Merging libcrypto-fixes/libcrypto-fixes (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'libcrypto-fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git libcrypto-fixes/libcrypto-fixes
+Already up to date.
+Merging vfio-fixes/for-linus (e242e974e812e vfio: selftests: Add luuid to libvfio.mk's list of libraries, not to the Makefile)
+$ git merge -m Merge branch 'for-linus' of https://github.com/awilliam/linux-vfio.git vfio-fixes/for-linus
+Already up to date.
+Merging kselftest-fixes/fixes (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest.git kselftest-fixes/fixes
+Already up to date.
+Merging dmaengine-fixes/fixes (867621ba20302 dmaengine: qcom: bam_dma: Fix command element mask field for BAM v1.6.0+)
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine.git dmaengine-fixes/fixes
+Merge made by the 'ort' strategy.
+ drivers/dma/idxd/cdev.c | 4 +++-
+ drivers/dma/idxd/init.c | 36 +++++-------------------------------
+ drivers/dma/sun6i-dma.c | 11 ++++-------
+ drivers/dma/switchtec_dma.c | 2 +-
+ include/linux/dma/qcom_bam_dma.h | 21 ++++++++++++++++-----
+ 5 files changed, 29 insertions(+), 45 deletions(-)
+Merging backlight-fixes/for-backlight-fixes (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'for-backlight-fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight.git backlight-fixes/for-backlight-fixes
+Already up to date.
+Merging mtd-fixes/mtd/fixes (2b533e775aec5 Revert "mtd: maps: remove uclinux map driver")
+$ git merge -m Merge branch 'mtd/fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git mtd-fixes/mtd/fixes
+Merge made by the 'ort' strategy.
+ drivers/mtd/devices/mchp23k256.c | 2 +-
+ drivers/mtd/maps/Kconfig | 6 ++
+ drivers/mtd/maps/Makefile | 1 +
+ drivers/mtd/maps/uclinux.c | 118 +++++++++++++++++++++++++++++
+ drivers/mtd/mtd_virt_concat.c | 8 +-
+ drivers/mtd/mtdcore.c | 23 +++++-
+ drivers/mtd/mtdpart.c | 8 ++
+ drivers/mtd/mtdswap.c | 5 +-
+ drivers/mtd/nand/ecc-mtk.c | 24 ++++--
+ drivers/mtd/nand/onenand/onenand_samsung.c | 7 +-
+ drivers/mtd/nand/raw/Kconfig | 1 +
+ drivers/mtd/nand/raw/fsl_ifc_nand.c | 9 ++-
+ drivers/mtd/nand/raw/ingenic/ingenic_ecc.c | 7 +-
+ drivers/mtd/nand/raw/lpc32xx_mlc.c | 12 ++-
+ drivers/mtd/nand/raw/lpc32xx_slc.c | 12 ++-
+ drivers/mtd/nand/raw/ndfc.c | 2 +-
+ drivers/mtd/nand/spi/core.c | 2 +-
+ 17 files changed, 224 insertions(+), 23 deletions(-)
+ create mode 100644 drivers/mtd/maps/uclinux.c
+Merging mfd-fixes/for-mfd-fixes (d5d2d7a8d8be1 MAINTAINERS: Add a mailing list entry to MFD)
+$ git merge -m Merge branch 'for-mfd-fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git mfd-fixes/for-mfd-fixes
+Already up to date.
+Merging v4l-dvb-fixes/fixes (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'fixes' of git://linuxtv.org/media-ci/media-pending.git v4l-dvb-fixes/fixes
+Already up to date.
+Merging reset-fixes/reset/fixes (71827776667f4 reset: imx7: Correct polarity of MIPI CSI resets on i.MX8MQ)
+$ git merge -m Merge branch 'reset/fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/pza/linux reset-fixes/reset/fixes
+Merge made by the 'ort' strategy.
+ drivers/reset/reset-imx7.c | 6 ++++++
+ drivers/reset/reset-sunxi.c | 4 +++-
+ drivers/reset/spacemit/reset-spacemit-k3.c | 2 +-
+ include/dt-bindings/reset/altr,rst-mgr-s10.h | 2 +-
+ 4 files changed, 11 insertions(+), 3 deletions(-)
+Merging mips-fixes/mips-fixes (8cdeaa50eae8d Linux 7.2-rc2)
+$ git merge -m Merge branch 'mips-fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/mips/linux.git mips-fixes/mips-fixes
+Already up to date.
+Merging at91-fixes/at91-fixes (765aaba18413a ARM: dts: microchip: sam9x7: fix GMAC clock configuration)
+$ git merge -m Merge branch 'at91-fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/at91/linux.git at91-fixes/at91-fixes
+Already up to date.
+Merging omap-fixes/fixes (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-omap.git omap-fixes/fixes
+Already up to date.
+Merging kvm-fixes/master (098e32cba334d x86/apic: KVM: Use cpu_physical_id() to get APIC ID of running vCPU for AVIC)
+$ git merge -m Merge branch 'master' of git://git.kernel.org/pub/scm/virt/kvm/kvm.git kvm-fixes/master
+Already up to date.
+Merging kvms390-fixes/master (3e3aa6da87d30 KVM: s390: pci: Fix handling of AIF enable without AISB)
+$ git merge -m Merge branch 'master' of https://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux.git kvms390-fixes/master
+Merge made by the 'ort' strategy.
+ arch/s390/kvm/dat.c | 2 ++
+ arch/s390/kvm/gmap.c | 7 ++++++-
+ arch/s390/kvm/kvm-s390.c | 6 ++++--
+ arch/s390/kvm/pci.c | 12 +++++++++---
+ 4 files changed, 21 insertions(+), 6 deletions(-)
+Merging kvm-arm-fixes/fixes (8d187d4b33c26 KVM: arm64: Fix propagation of TLBI level in kvm_pgtable_stage2_relax_perms())
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm.git kvm-arm-fixes/fixes
+Auto-merging MAINTAINERS
+Auto-merging arch/arm64/include/asm/kvm_nested.h
+Auto-merging arch/arm64/kvm/at.c
+Auto-merging arch/arm64/kvm/hyp/include/hyp/switch.h
+Auto-merging arch/arm64/kvm/hyp/pgtable.c
+Auto-merging arch/arm64/kvm/nested.c
+Auto-merging arch/arm64/kvm/vgic/vgic-its.c
+Auto-merging drivers/firmware/arm_ffa/driver.c
+Auto-merging include/linux/arm_ffa.h
+Auto-merging tools/testing/selftests/kvm/Makefile.kvm
+Auto-merging virt/kvm/kvm_main.c
+Merge made by the 'ort' strategy.
+ MAINTAINERS | 1 +
+ arch/arm64/include/asm/kvm_nested.h | 8 +
+ arch/arm64/kvm/at.c | 8 -
+ arch/arm64/kvm/emulate-nested.c | 41 +++-
+ arch/arm64/kvm/hyp/include/hyp/switch.h | 11 +-
+ arch/arm64/kvm/hyp/nvhe/ffa.c | 44 ++--
+ arch/arm64/kvm/hyp/nvhe/pkvm.c | 3 +-
+ arch/arm64/kvm/hyp/nvhe/sys_regs.c | 3 +-
+ arch/arm64/kvm/hyp/pgtable.c | 15 +-
+ arch/arm64/kvm/inject_fault.c | 18 +-
+ arch/arm64/kvm/mmio.c | 7 +-
+ arch/arm64/kvm/nested.c | 164 +++++++-------
+ arch/arm64/kvm/pkvm.c | 2 +-
+ arch/arm64/kvm/vgic/vgic-its.c | 2 +
+ arch/arm64/kvm/vgic/vgic.c | 20 +-
+ drivers/firmware/arm_ffa/driver.c | 25 ++-
+ include/linux/arm_ffa.h | 9 +-
+ tools/testing/selftests/kvm/Makefile.kvm | 1 +
+ tools/testing/selftests/kvm/arm64/mmio_sign_ext.c | 255 ++++++++++++++++++++++
+ virt/kvm/kvm_main.c | 16 +-
+ 20 files changed, 482 insertions(+), 171 deletions(-)
+ create mode 100644 tools/testing/selftests/kvm/arm64/mmio_sign_ext.c
+Merging hwmon-fixes/hwmon (f151d0143ac4e hwmon: (nzxt-kraken3) Stop device IO before calling hid_hw_stop)
+$ git merge -m Merge branch 'hwmon' of https://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git hwmon-fixes/hwmon
+Merge made by the 'ort' strategy.
+ drivers/hwmon/corsair-cpro.c | 1 +
+ drivers/hwmon/corsair-psu.c | 1 +
+ drivers/hwmon/gigabyte_waterforce.c | 4 +++-
+ drivers/hwmon/nzxt-kraken3.c | 6 ++++--
+ drivers/hwmon/nzxt-smart2.c | 2 +-
+ 5 files changed, 10 insertions(+), 4 deletions(-)
+Merging nvdimm-fixes/libnvdimm-fixes (a8aec14230322 nvdimm/bus: Fix potential use after free in asynchronous initialization)
+$ git merge -m Merge branch 'libnvdimm-fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm.git nvdimm-fixes/libnvdimm-fixes
+Already up to date.
+Merging cxl-fixes/fixes (d90f236f8b9e3 cxl/test: Update mock dev array before calling platform_device_add())
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl.git cxl-fixes/fixes
+Already up to date.
+Merging dma-mapping-fixes/dma-mapping-fixes (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'dma-mapping-fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/mszyprowski/linux.git dma-mapping-fixes/dma-mapping-fixes
+Already up to date.
+Merging drivers-x86-fixes/fixes (2726b5758f80a platform/x86: amd-pmc: Use correct IP block table for AMD 1Ah M80H SoC)
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86.git drivers-x86-fixes/fixes
+Merge made by the 'ort' strategy.
+ drivers/platform/x86/amd/pmc/pmc.c | 36 ++++++++++++++++++++++++++-------
+ drivers/platform/x86/asus-armoury.h | 10 ++++-----
+ drivers/platform/x86/bitland-mifs-wmi.c | 8 ++++++++
+ 3 files changed, 42 insertions(+), 12 deletions(-)
+Merging samsung-krzk-fixes/fixes (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux.git samsung-krzk-fixes/fixes
+Already up to date.
+Merging pinctrl-samsung-fixes/fixes (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/pinctrl/samsung.git pinctrl-samsung-fixes/fixes
+Already up to date.
+Merging pinctrl-qcom-fixes/pinctrl-qcom/for-current (437a8d2aa1aa4 pinctrl: qcom: sc8280xp: Add missing wakeup entries for GPIO143/151)
+$ git merge -m Merge branch 'pinctrl-qcom/for-current' of https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git pinctrl-qcom-fixes/pinctrl-qcom/for-current
+Merge made by the 'ort' strategy.
+ drivers/pinctrl/qcom/pinctrl-msm.c | 8 ++++----
+ drivers/pinctrl/qcom/pinctrl-sc8280xp.c | 21 +++++++++++----------
+ 2 files changed, 15 insertions(+), 14 deletions(-)
+Merging devicetree-fixes/dt/linus (b39a6b2e9d5bd dt-bindings: mfd: khadas,mcu: Drop type reference from "fan-supply")
+$ git merge -m Merge branch 'dt/linus' of https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git devicetree-fixes/dt/linus
+Already up to date.
+Merging dt-krzk-fixes/fixes (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-dt.git dt-krzk-fixes/fixes
+Already up to date.
+Merging scsi-fixes/fixes (5d5221f8a4064 scsi: devinfo: Broaden Promise VTrak E310/E610 identification)
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git scsi-fixes/fixes
+Already up to date.
+Merging drm-fixes/drm-fixes (6763a0aea6d65 nouveau/vmm: fix another SPT/LPT race)
+$ git merge -m Merge branch 'drm-fixes' of https://gitlab.freedesktop.org/drm/kernel.git drm-fixes/drm-fixes
+Merge made by the 'ort' strategy.
+ drivers/accel/amdxdna/aie2_ctx.c | 19 ++---
+ drivers/accel/amdxdna/aie2_message.c | 4 +-
+ drivers/accel/amdxdna/amdxdna_ctx.c | 56 ++++++++++---
+ drivers/accel/amdxdna/amdxdna_gem.c | 50 ++++++++----
+ drivers/accel/amdxdna/amdxdna_gem.h | 12 ++-
+ drivers/accel/amdxdna/amdxdna_pci_drv.c | 21 ++++-
+ drivers/gpu/buddy.c | 67 +++++++++++-----
+ drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 3 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c | 2 +
+ drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 5 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 9 +++
+ drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 27 +++----
+ drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c | 9 +++
+ drivers/gpu/drm/amd/amdgpu/soc21.c | 3 +-
+ .../gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 6 ++
+ .../gpu/drm/amd/amdkfd/kfd_device_queue_manager.h | 2 +
+ drivers/gpu/drm/amd/amdkfd/kfd_events.c | 5 +-
+ drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 3 +-
+ drivers/gpu/drm/amd/amdkfd/kfd_process.c | 2 +-
+ .../gpu/drm/amd/amdkfd/kfd_process_queue_manager.c | 37 +++++----
+ drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 1 +
+ .../gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 28 ++++---
+ drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c | 1 +
+ .../gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c | 3 +-
+ drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 +
+ drivers/gpu/drm/drm_fb_helper.c | 92 +++++++++++++++++++++-
+ drivers/gpu/drm/drm_ioctl.c | 14 +++-
+ drivers/gpu/drm/i915/display/intel_dp.c | 8 +-
+ drivers/gpu/drm/i915/display/intel_lt_phy.c | 6 +-
+ drivers/gpu/drm/i915/display/intel_psr.c | 3 -
+ drivers/gpu/drm/i915/gem/i915_gem_context.c | 24 +++---
+ .../gpu/drm/i915/gt/intel_execlists_submission.c | 19 ++---
+ drivers/gpu/drm/imagination/pvr_context.c | 4 +-
+ drivers/gpu/drm/imagination/pvr_fw_trace.c | 2 +-
+ drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c | 31 ++++----
+ drivers/gpu/drm/tests/drm_exec_test.c | 28 ++++---
+ drivers/gpu/drm/v3d/v3d_submit.c | 2 +
+ drivers/gpu/drm/xe/tests/xe_pci.c | 1 -
+ drivers/gpu/drm/xe/xe_exec.c | 22 ++++--
+ drivers/gpu/drm/xe/xe_pt.c | 19 ++++-
+ drivers/gpu/drm/xe/xe_vm_madvise.c | 2 +-
+ include/drm/drm_exec.h | 34 ++++----
+ 42 files changed, 486 insertions(+), 204 deletions(-)
+Merging drm-intel-fixes/for-linux-next-fixes (3d04d9f390eea Revert "drm/i915/psr: Allow SCL=0 on platforms with always-on VRR TG")
+$ git merge -m Merge branch 'for-linux-next-fixes' of https://gitlab.freedesktop.org/drm/i915/kernel.git drm-intel-fixes/for-linux-next-fixes
+Already up to date.
+Merging mmc-fixes/fixes (86152fef52cac mmc: block: fix RPMB device unregister ordering)
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc.git mmc-fixes/fixes
+Merge made by the 'ort' strategy.
+ Documentation/devicetree/bindings/mmc/mtk-sd.yaml | 29 +++++++++++++++++-
+ drivers/memstick/core/ms_block.c | 4 +++
+ drivers/mmc/core/block.c | 3 +-
+ drivers/mmc/core/mmc_test.c | 18 +++++++-----
+ drivers/mmc/host/sdhci-of-dwcmshc.c | 14 +++++----
+ drivers/mmc/host/vub300.c | 36 +++++++++++++++--------
+ 6 files changed, 77 insertions(+), 27 deletions(-)
+Merging rtc-fixes/rtc-fixes (254f49634ee16 Linux 7.1-rc1)
+$ git merge -m Merge branch 'rtc-fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux.git rtc-fixes/rtc-fixes
+Already up to date.
+Merging gnss-fixes/gnss-linus (5d6919055dec1 Linux 7.1-rc3)
+$ git merge -m Merge branch 'gnss-linus' of https://git.kernel.org/pub/scm/linux/kernel/git/johan/gnss.git gnss-fixes/gnss-linus
+Already up to date.
+Merging hyperv-fixes/hyperv-fixes (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'hyperv-fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux.git hyperv-fixes/hyperv-fixes
+Already up to date.
+Merging risc-v-fixes/fixes (a2ac823d8a228 selftests/rseq: Fix a building error for riscv arch)
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux.git risc-v-fixes/fixes
+Merge made by the 'ort' strategy.
+ Documentation/arch/riscv/hwprobe.rst | 204 +++++++++++----------
+ .../devicetree/bindings/riscv/extensions.yaml | 184 +++++++++----------
+ arch/riscv/Kconfig.socs | 6 +
+ arch/riscv/configs/defconfig | 1 +
+ arch/riscv/kernel/machine_kexec.c | 3 +
+ .../selftests/riscv/vector/validate_v_ptrace.c | 5 +-
+ tools/testing/selftests/rseq/Makefile | 6 +-
+ 7 files changed, 217 insertions(+), 192 deletions(-)
+Merging riscv-dt-fixes/riscv-dt-fixes (0df8aa2b9aec5 riscv: dts: microchip: fix icicle i2c pinctrl configuration)
+$ git merge -m Merge branch 'riscv-dt-fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux.git riscv-dt-fixes/riscv-dt-fixes
+Already up to date.
+Merging riscv-soc-fixes/riscv-soc-fixes (75ef233975589 soc: microchip: mpfs-sys-controller: fix resource leak on probe error)
+$ git merge -m Merge branch 'riscv-soc-fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux.git riscv-soc-fixes/riscv-soc-fixes
+Already up to date.
+Merging fpga-fixes/fixes (19272b37aa4f8 Linux 6.16-rc1)
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/fpga/linux-fpga.git fpga-fixes/fixes
+Already up to date.
+Merging spdx/spdx-linus (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'spdx-linus' of https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/spdx.git spdx/spdx-linus
+Already up to date.
+Merging gpio-brgl-fixes/gpio/for-current (b11c513ad943f gpio: mvebu: free generic chips on unbind)
+$ git merge -m Merge branch 'gpio/for-current' of https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git gpio-brgl-fixes/gpio/for-current
+Merge made by the 'ort' strategy.
+ drivers/gpio/gpio-dwapb.c | 100 +++++++++++++++++++++++++++-----
+ drivers/gpio/gpio-mvebu.c | 1 +
+ drivers/gpio/gpio-palmas.c | 19 ++++++
+ drivers/gpio/gpio-shared-proxy.c | 66 ++++++++++-----------
+ drivers/gpio/gpiolib-shared.h | 3 +-
+ tools/testing/selftests/gpio/.gitignore | 1 +
+ 6 files changed, 141 insertions(+), 49 deletions(-)
+Merging gpio-intel-fixes/fixes (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-gpio-intel.git gpio-intel-fixes/fixes
+Already up to date.
+Merging pinctrl-intel-fixes/fixes (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/pinctrl/intel.git pinctrl-intel-fixes/fixes
+Already up to date.
+Merging auxdisplay-fixes/fixes (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-auxdisplay.git auxdisplay-fixes/fixes
+Already up to date.
+Merging kunit-fixes/kunit-fixes (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'kunit-fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest.git kunit-fixes/kunit-fixes
+Already up to date.
+Merging memblock-fixes/fixes (2ebce860bdd7a mm/mm_init: handle alloc_percpu failure in free_area_init_core_hotplug)
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/rppt/memblock.git memblock-fixes/fixes
+Auto-merging mm/mm_init.c
+Merge made by the 'ort' strategy.
+ include/linux/memory_hotplug.h | 2 +-
+ mm/memory_hotplug.c | 3 ++-
+ mm/mm_init.c | 19 +++++++++++++------
+ 3 files changed, 16 insertions(+), 8 deletions(-)
+Merging renesas-fixes/fixes (8a78d1c454b3c Merge branch 'renesas-pinctrl-fixes-for-v7.1' into renesas-fixes)
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-devel.git renesas-fixes/fixes
+Merge made by the 'ort' strategy.
+Merging perf-current/perf-tools (558ef39aeb9a0 Merge tag 'dmaengine-7.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine)
+$ git merge -m Merge branch 'perf-tools' of https://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools.git perf-current/perf-tools
+Already up to date.
+Merging efi-fixes/urgent (d8809f6931065 efi: sysfb_efi: Extend quirk to cover IdeaPad Duet 3 10IGL5-LTE)
+$ git merge -m Merge branch 'urgent' of https://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git efi-fixes/urgent
+Already up to date.
+Merging battery-fixes/fixes (254f49634ee16 Linux 7.1-rc1)
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply.git battery-fixes/fixes
+Already up to date.
+Merging iommufd-fixes/for-rc (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'for-rc' of https://git.kernel.org/pub/scm/linux/kernel/git/jgg/iommufd.git iommufd-fixes/for-rc
+Already up to date.
+Merging rust-fixes/rust-fixes (4688cf884b3ab rust: allow `clippy::unwrap_or_default` globally)
+$ git merge -m Merge branch 'rust-fixes' of https://github.com/Rust-for-Linux/linux.git rust-fixes/rust-fixes
+Auto-merging Makefile
+Merge made by the 'ort' strategy.
+ Makefile | 5 +++++
+ init/Kconfig | 3 +++
+ rust/bindings/lib.rs | 4 ++++
+ rust/uapi/lib.rs | 4 ++++
+ 4 files changed, 16 insertions(+)
+Merging w1-fixes/fixes (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-w1.git w1-fixes/fixes
+Already up to date.
+Merging pmdomain-fixes/fixes (25e252bcf1593 pmdomain: imx: Fix i.MX8MP VC8000E power up sequence)
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm.git pmdomain-fixes/fixes
+Merge made by the 'ort' strategy.
+ drivers/pmdomain/imx/imx8m-blk-ctrl.c | 46 +++++++++++++++++++++-
+ drivers/pmdomain/imx/imx93-blk-ctrl.c | 60 ++++++++++++++++++++++++++++-
+ include/dt-bindings/power/fsl,imx93-power.h | 1 +
+ 3 files changed, 103 insertions(+), 4 deletions(-)
+Merging i2c-andi-fixes/i2c/i2c-fixes (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'i2c/i2c-fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux.git i2c-andi-fixes/i2c/i2c-fixes
+Already up to date.
+Merging i2c-rust-fixes/rust-i2c-fixes (4eb422482ca5d rust: i2c: fix I2cAdapter refcounts double increment)
+$ git merge -m Merge branch 'rust-i2c-fixes' of https://github.com/ikrtn/rust-for-linux i2c-rust-fixes/rust-i2c-fixes
+Already up to date.
+Merging sparc-fixes/for-linus (254f49634ee16 Linux 7.1-rc1)
+$ git merge -m Merge branch 'for-linus' of https://git.kernel.org/pub/scm/linux/kernel/git/alarsson/linux-sparc.git sparc-fixes/for-linus
+Already up to date.
+Merging clk-fixes/clk-fixes (8cdeaa50eae8d Linux 7.2-rc2)
+$ git merge -m Merge branch 'clk-fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git clk-fixes/clk-fixes
+Already up to date.
+Merging thead-clk-fixes/thead-clk-fixes (8f0b4cce4481f Linux 6.19-rc1)
+$ git merge -m Merge branch 'thead-clk-fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/fustini/linux.git thead-clk-fixes/thead-clk-fixes
+Already up to date.
+Merging tenstorrent-clk-fixes/tenstorrent-clk-fixes (6de23f81a5e08 Linux 7.0-rc1)
+$ git merge -m Merge branch 'tenstorrent-clk-fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/tenstorrent/linux.git tenstorrent-clk-fixes/tenstorrent-clk-fixes
+Already up to date.
+Merging fustini-config-fixes/riscv-config-fixes (254f49634ee16 Linux 7.1-rc1)
+$ git merge -m Merge branch 'riscv-config-fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/fustini/linux.git fustini-config-fixes/riscv-config-fixes
+Already up to date.
+Merging pwrseq-fixes/pwrseq/for-current (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'pwrseq/for-current' of https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git pwrseq-fixes/pwrseq/for-current
+Already up to date.
+Merging thead-dt-fixes/thead-dt-fixes (254f49634ee16 Linux 7.1-rc1)
+$ git merge -m Merge branch 'thead-dt-fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/fustini/linux.git thead-dt-fixes/thead-dt-fixes
+Already up to date.
+Merging ftrace-fixes/ftrace/fixes (1650a1b6cb1ae fgraph: Check ftrace_pids_enabled on registration for early filtering)
+$ git merge -m Merge branch 'ftrace/fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace.git ftrace-fixes/ftrace/fixes
+Already up to date.
+Merging ring-buffer-fixes/ring-buffer/fixes (057caace5214d tracing: Create output file from cmd_check_undefined)
+$ git merge -m Merge branch 'ring-buffer/fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace.git ring-buffer-fixes/ring-buffer/fixes
+Already up to date.
+Merging trace-fixes/trace/fixes (05074bb90af94 tracing/synthetic: Free type string on error path)
+$ git merge -m Merge branch 'trace/fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace.git trace-fixes/trace/fixes
+Merge made by the 'ort' strategy.
+ drivers/ufs/core/ufs_trace.h | 36 +++++++++++++++++++++++--------
+ include/linux/glob.h | 1 +
+ include/linux/tracepoint.h | 12 ++++++++++-
+ kernel/trace/ring_buffer.c | 5 +++--
+ kernel/trace/trace.c | 3 +--
+ kernel/trace/trace_events_filter.c | 6 ++----
+ kernel/trace/trace_events_synth.c | 10 ++++++---
+ kernel/trace/trace_events_user.c | 43 ++++++++++++++++++++++++++++++--------
+ kernel/trace/trace_functions.c | 8 +++----
+ kernel/trace/trace_osnoise.c | 4 +++-
+ kernel/trace/trace_preemptirq.c | 2 +-
+ lib/glob.c | 31 +++++++++++++++++++++++++--
+ samples/ftrace/ftrace-ops.c | 4 ++--
+ 13 files changed, 125 insertions(+), 40 deletions(-)
+Merging tracefs-fixes/tracefs/fixes (07004a8c4b572 eventfs: Hold eventfs_mutex and SRCU when remount walks events)
+$ git merge -m Merge branch 'tracefs/fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace.git tracefs-fixes/tracefs/fixes
+Already up to date.
+Merging spacemit-fixes/fixes (eb525edd48907 clk: spacemit: k3: set hdma clock as critical)
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/spacemit/linux spacemit-fixes/fixes
+Merge made by the 'ort' strategy.
+ drivers/clk/spacemit/ccu-k3.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+Merging tip-fixes/tip/urgent (5ec0167664ba2 Merge branch into tip/master: 'x86/urgent')
+$ git merge -m Merge branch 'tip/urgent' of https://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git tip-fixes/tip/urgent
+Merge made by the 'ort' strategy.
+ arch/x86/events/amd/core.c | 12 ++-
+ arch/x86/video/video-common.c | 23 +++---
+ arch/x86/virt/svm/sev.c | 2 +
+ fs/resctrl/rdtgroup.c | 33 ++++++--
+ kernel/events/core.c | 2 +
+ kernel/exit.c | 7 +-
+ kernel/signal.c | 10 ++-
+ kernel/time/posix-cpu-timers.c | 173 +++++++++++++++++++++++++++--------------
+ 8 files changed, 182 insertions(+), 80 deletions(-)
+Merging slab-fixes/slab/for-next-fixes (af9ea231c0b45 mm/slub: fix lost local objects when bulk remote free batch fills)
+$ git merge -m Merge branch 'slab/for-next-fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/vbabka/slab.git slab-fixes/slab/for-next-fixes
+Merge made by the 'ort' strategy.
+ mm/slub.c | 12 +++++-------
+ 1 file changed, 5 insertions(+), 7 deletions(-)
+Merging kexec-fixes/kexec-fixes (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'kexec-fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/liveupdate/linux.git kexec-fixes/kexec-fixes
+Already up to date.
+Merging liveupdate-fixes/fixes (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/liveupdate/linux.git liveupdate-fixes/fixes
+Already up to date.
+Merging drm-msm-fixes/msm-fixes (db339b6bc9f23 dt-bindings: display/msm: Fix typo in clock-names property)
+$ git merge -m Merge branch 'msm-fixes' of https://gitlab.freedesktop.org/drm/msm.git drm-msm-fixes/msm-fixes
+Already up to date.
+Merging uml-fixes/fixes (254f49634ee16 Linux 7.1-rc1)
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/uml/linux.git uml-fixes/fixes
+Already up to date.
+Merging fwctl-fixes/for-rc (4549871118cf6 Linux 7.1-rc7)
+$ git merge -m Merge branch 'for-rc' of https://git.kernel.org/pub/scm/linux/kernel/git/fwctl/fwctl.git fwctl-fixes/for-rc
+Already up to date.
+Merging devsec-tsm-fixes/fixes (c3fd16c3b98ed virt: tdx-guest: Fix handling of host controlled 'quote' buffer length)
+$ git merge -m Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/devsec/tsm.git devsec-tsm-fixes/fixes
+Already up to date.
+Merging drm-rust-fixes/for-linux-next-fixes (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'for-linux-next-fixes' of https://gitlab.freedesktop.org/drm/rust/kernel.git drm-rust-fixes/for-linux-next-fixes
+Already up to date.
+Merging tenstorrent-dt-fixes/tenstorrent-dt-fixes (6de23f81a5e08 Linux 7.0-rc1)
+$ git merge -m Merge branch 'tenstorrent-dt-fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/tenstorrent/linux.git tenstorrent-dt-fixes/tenstorrent-dt-fixes
+Already up to date.
+Merging nfc-fixes/for-linus (e87faad807329 nfc: nci: fix out-of-bounds write in nci_target_auto_activated())
+$ git merge -m Merge branch 'for-linus' of https://codeberg.org/linux-nfc/linux.git nfc-fixes/for-linus
+Merge made by the 'ort' strategy.
+ net/nfc/digital_technology.c | 2 ++
+ net/nfc/llcp_commands.c | 18 ++++++++++++++++--
+ net/nfc/llcp_core.c | 29 +++++++++++++++++++++--------
+ net/nfc/llcp_sock.c | 14 +++++++++++---
+ net/nfc/nci/data.c | 10 +++++-----
+ net/nfc/nci/ntf.c | 32 ++++++++++++++++++++++++++++----
+ net/nfc/nci/rsp.c | 28 ++++++++++++++++++++++++++--
+ 7 files changed, 109 insertions(+), 24 deletions(-)
+Merging drm-misc-fixes/for-linux-next-fixes (cf385cf6e713e drm/imagination: fix error checking of pvr_vm_context_lookup())
+$ git merge -m Merge branch 'for-linux-next-fixes' of https://gitlab.freedesktop.org/drm/misc/kernel.git drm-misc-fixes/for-linux-next-fixes
+Already up to date.
+Merging rust/rust-next (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'rust-next' of https://github.com/Rust-for-Linux/linux.git rust/rust-next
+Already up to date.
+Merging rust-interop/interop-next (05f7e89ab9731 Linux 6.19)
+$ git merge -m Merge branch 'interop-next' of https://github.com/Rust-for-Linux/linux.git rust-interop/interop-next
+Already up to date.
+Merging rust-alloc/alloc-next (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'alloc-next' of https://github.com/Rust-for-Linux/linux.git rust-alloc/alloc-next
+Already up to date.
+Merging rust-io/io-next (86731a2a651e5 Linux 6.16-rc3)
+$ git merge -m Merge branch 'io-next' of https://github.com/Rust-for-Linux/linux.git rust-io/io-next
+Already up to date.
+Merging rust-pin-init/pin-init-next (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'pin-init-next' of https://github.com/Rust-for-Linux/linux.git rust-pin-init/pin-init-next
+Already up to date.
+Merging rust-timekeeping/timekeeping-next (ddb1444d33351 hrtimer: add usage examples to documentation)
+$ git merge -m Merge branch 'timekeeping-next' of https://github.com/Rust-for-Linux/linux.git rust-timekeeping/timekeeping-next
+Already up to date.
+Merging rust-xarray/xarray-next (c455f19bbe610 rust: xarray: add __rust_helper to helpers)
+$ git merge -m Merge branch 'xarray-next' of https://github.com/Rust-for-Linux/linux.git rust-xarray/xarray-next
+Already up to date.
+Merging rust-analyzer/rust-analyzer-next (5f45afb8ab04d scripts: generate_rust_analyzer.py: pass cfg to macros crate)
+$ git merge -m Merge branch 'rust-analyzer-next' of https://github.com/Rust-for-Linux/linux.git rust-analyzer/rust-analyzer-next
+Auto-merging scripts/generate_rust_analyzer.py
+Merge made by the 'ort' strategy.
+ scripts/generate_rust_analyzer.py | 1 +
+ 1 file changed, 1 insertion(+)
+Merging mm-stable/mm-stable (0e35b9b6ec0ff Merge tag 'mm-hotfixes-stable-2026-07-06-17-49' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm)
+$ git merge -m Merge branch 'mm-stable' of https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm mm-stable/mm-stable
+Already up to date.
+Merging mm-nonmm-stable/mm-nonmm-stable (0e35b9b6ec0ff Merge tag 'mm-hotfixes-stable-2026-07-06-17-49' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm)
+$ git merge -m Merge branch 'mm-nonmm-stable' of https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm mm-nonmm-stable/mm-nonmm-stable
+Already up to date.
+Merging mm-unstable/mm-unstable (4a6c88e10a079 mm: nommu: fix the error path when vma_iter_prealloc() fails)
+ 854fb5793cfe6 ("mm/mm_init: handle alloc_percpu failure in free_area_init_core_hotplug")
+$ git merge -m Merge branch 'mm-unstable' of https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm mm-unstable/mm-unstable
+Auto-merging MAINTAINERS
+Auto-merging init/Kconfig
+Auto-merging mm/memory_hotplug.c
+Auto-merging mm/mm_init.c
+Auto-merging mm/slub.c
+Merge made by the 'ort' strategy.
+ CREDITS | 4 +
+ Documentation/ABI/testing/sysfs-block-zram | 6 +-
+ Documentation/ABI/testing/sysfs-kernel-mm-damon | 40 +
+ Documentation/admin-guide/cgroup-v1/cpusets.rst | 2 +-
+ Documentation/admin-guide/kernel-parameters.txt | 7 +-
+ Documentation/admin-guide/mm/damon/usage.rst | 8 +-
+ Documentation/admin-guide/mm/pagemap.rst | 13 +-
+ Documentation/admin-guide/mm/transhuge.rst | 2 +-
+ Documentation/admin-guide/mm/userfaultfd.rst | 269 +++++-
+ Documentation/admin-guide/sysctl/vm.rst | 83 +-
+ Documentation/core-api/maple_tree.rst | 21 +-
+ Documentation/core-api/mm-api.rst | 3 +-
+ Documentation/driver-api/basics.rst | 3 +
+ Documentation/filesystems/proc.rst | 1 +
+ Documentation/mm/damon/design.rst | 18 +-
+ Documentation/mm/page_owner.rst | 78 +-
+ MAINTAINERS | 28 +-
+ arch/arm64/Kconfig | 3 +-
+ arch/arm64/include/asm/pgtable-prot.h | 8 +-
+ arch/arm64/include/asm/pgtable.h | 51 +-
+ arch/arm64/mm/hugetlbpage.c | 2 +-
+ arch/csky/abiv1/inc/abi/cacheflush.h | 7 +-
+ arch/loongarch/Kconfig | 3 +-
+ arch/loongarch/include/asm/pgtable.h | 4 +-
+ arch/powerpc/include/asm/book3s/64/pgtable.h | 10 +-
+ arch/powerpc/mm/book3s64/radix_pgtable.c | 7 +-
+ arch/powerpc/mm/hugetlbpage.c | 13 +-
+ arch/powerpc/platforms/Kconfig.cputype | 3 +-
+ arch/riscv/Kconfig | 3 +-
+ arch/riscv/include/asm/pgtable-bits.h | 12 +-
+ arch/riscv/include/asm/pgtable.h | 67 +-
+ arch/s390/Kconfig | 3 +-
+ arch/s390/include/asm/hugetlb.h | 12 +-
+ arch/s390/include/asm/pgtable.h | 6 +-
+ arch/sparc/include/asm/pgtable_64.h | 4 -
+ arch/x86/Kconfig | 3 +-
+ arch/x86/events/intel/ds.c | 6 +-
+ arch/x86/include/asm/pgtable.h | 58 +-
+ arch/x86/include/asm/pgtable_types.h | 16 +-
+ arch/x86/kvm/vmx/vmx.c | 2 +-
+ arch/x86/virt/hw.c | 2 +-
+ drivers/base/arch_numa.c | 4 -
+ drivers/misc/sgi-xp/xpc_uv.c | 5 +-
+ drivers/net/ethernet/fungible/funeth/funeth_rx.c | 2 +-
+ fs/proc/task_mmu.c | 119 ++-
+ include/asm-generic/fixmap.h | 4 +-
+ include/asm-generic/getorder.h | 4 +-
+ include/asm-generic/hugetlb.h | 18 +-
+ include/asm-generic/memory_model.h | 6 +-
+ include/asm-generic/mmu.h | 2 +-
+ include/asm-generic/pgtable-nop4d.h | 4 +-
+ include/asm-generic/pgtable-nopmd.h | 4 +-
+ include/asm-generic/pgtable-nopud.h | 4 +-
+ include/asm-generic/pgtable_uffd.h | 32 +-
+ include/linux/alloc_tag.h | 4 +-
+ include/linux/cpuset.h | 4 +-
+ include/linux/damon.h | 24 +-
+ include/linux/gfp.h | 54 +-
+ include/linux/gfp_types.h | 12 +-
+ include/linux/huge_mm.h | 9 +-
+ include/linux/hugetlb.h | 53 +-
+ include/linux/hugetlb_cgroup.h | 2 +-
+ include/linux/leafops.h | 32 +-
+ include/linux/lockdep.h | 3 +
+ include/linux/lockdep_types.h | 3 +-
+ include/linux/maple_tree.h | 14 +-
+ include/linux/migrate.h | 6 +-
+ include/linux/migrate_mode.h | 1 +
+ include/linux/mm.h | 95 ++-
+ include/linux/mm_inline.h | 8 +-
+ include/linux/mm_types.h | 1 +
+ include/linux/mmzone.h | 43 +-
+ include/linux/oom.h | 2 +-
+ include/linux/page-flags.h | 14 -
+ include/linux/page_owner.h | 7 +-
+ include/linux/percpu-defs.h | 4 +-
+ include/linux/percpu-refcount.h | 5 +-
+ include/linux/pfn.h | 2 +-
+ include/linux/pgtable.h | 71 +-
+ include/linux/radix-tree.h | 5 +-
+ include/linux/sched.h | 1 +
+ include/linux/skbuff.h | 2 +-
+ include/linux/swap.h | 83 +-
+ include/linux/swapops.h | 10 +-
+ include/linux/userfaultfd_k.h | 100 ++-
+ include/linux/vmalloc.h | 4 +-
+ include/linux/vmpressure.h | 48 +-
+ include/linux/writeback.h | 2 +-
+ include/trace/events/damon.h | 8 +-
+ include/trace/events/huge_memory.h | 2 +-
+ include/trace/events/migrate.h | 11 +-
+ include/trace/events/mmflags.h | 17 +-
+ include/trace/events/pagemap.h | 8 +
+ include/uapi/linux/fs.h | 1 +
+ include/uapi/linux/mempolicy.h | 2 +-
+ include/uapi/linux/userfaultfd.h | 54 +-
+ init/Kconfig | 8 +
+ kernel/cgroup/cpuset.c | 2 +-
+ kernel/locking/lockdep.c | 58 +-
+ lib/Kconfig.debug | 28 -
+ lib/Makefile | 1 -
+ lib/maple_tree.c | 361 +++++---
+ lib/percpu-refcount.c | 2 +-
+ lib/radix-tree.c | 7 +-
+ lib/test_hmm.c | 2 +-
+ mm/Kconfig | 17 +-
+ mm/Kconfig.debug | 28 +
+ mm/Makefile | 3 +-
+ {lib => mm}/alloc_tag.c | 23 +-
+ mm/cma.c | 3 +-
+ mm/compaction.c | 8 +-
+ mm/damon/core.c | 424 ++++++----
+ mm/damon/lru_sort.c | 11 +-
+ mm/damon/paddr.c | 9 +-
+ mm/damon/reclaim.c | 11 +-
+ mm/damon/stat.c | 2 +-
+ mm/damon/sysfs-schemes.c | 31 +-
+ mm/damon/sysfs.c | 163 ++--
+ mm/damon/tests/core-kunit.h | 144 +++-
+ mm/damon/vaddr.c | 12 +-
+ mm/debug_vm_pgtable.c | 16 +-
+ mm/filemap.c | 43 +-
+ mm/{swap.c => folio.c} | 68 +-
+ mm/hmm.c | 4 +-
+ mm/huge_memory.c | 194 +++--
+ mm/hugetlb.c | 712 +++++++++-------
+ mm/hugetlb_cma.c | 140 +++-
+ mm/hugetlb_cma.h | 8 +-
+ mm/hugetlb_vmemmap.c | 137 +--
+ mm/hugetlb_vmemmap.h | 5 -
+ mm/internal.h | 372 +++------
+ mm/kasan/hw_tags.c | 2 +-
+ mm/khugepaged.c | 41 +-
+ mm/kmemleak.c | 91 +-
+ mm/kmsan/init.c | 2 +-
+ mm/ksm.c | 17 +-
+ mm/madvise.c | 6 +-
+ mm/memcontrol-v1.c | 300 +++++++
+ mm/memcontrol-v1.h | 6 -
+ mm/memcontrol.c | 17 +-
+ mm/memfd.c | 1 +
+ mm/memory-failure.c | 109 ++-
+ mm/memory.c | 210 +++--
+ mm/memory_hotplug.c | 1 +
+ mm/mempolicy.c | 32 +-
+ mm/migrate.c | 95 ++-
+ mm/migrate_device.c | 42 +-
+ mm/mincore.c | 11 +-
+ mm/mlock.c | 2 +-
+ mm/mm_init.c | 87 +-
+ mm/mmzone.c | 5 +-
+ mm/mprotect.c | 101 ++-
+ mm/mremap.c | 17 +-
+ mm/nommu.c | 43 +-
+ mm/page_alloc.c | 354 ++++----
+ mm/page_alloc.h | 312 +++++++
+ mm/page_frag_cache.c | 6 +-
+ mm/page_isolation.c | 1 +
+ mm/page_owner.c | 295 +++++--
+ mm/page_reporting.c | 1 +
+ mm/page_table_check.c | 8 +-
+ mm/page_vma_mapped.c | 8 +-
+ mm/percpu-km.c | 9 +-
+ mm/percpu-vm.c | 48 +-
+ mm/percpu.c | 20 +-
+ mm/rmap.c | 58 +-
+ mm/shmem.c | 16 +-
+ mm/show_mem.c | 10 +-
+ mm/shuffle.c | 1 +
+ mm/slab.h | 2 +-
+ mm/slub.c | 17 +-
+ mm/sparse-vmemmap.c | 26 +-
+ mm/sparse.c | 50 +-
+ mm/swap.h | 6 +-
+ mm/swap_state.c | 52 +-
+ mm/swapfile.c | 25 +-
+ mm/userfaultfd.c | 399 ++++++++-
+ mm/vmalloc.c | 31 +-
+ mm/vmpressure.c | 301 +------
+ mm/vmscan.c | 20 +-
+ mm/vmstat.c | 3 +-
+ mm/zsmalloc.c | 230 +++++-
+ mm/zswap.c | 2 +-
+ samples/damon/Kconfig | 2 +-
+ samples/damon/mtier.c | 9 +-
+ samples/damon/prcl.c | 9 +-
+ samples/damon/wsse.c | 9 +-
+ scripts/gdb/linux/page_owner.py | 4 +-
+ tools/include/linux/gfp_types.h | 7 -
+ tools/include/uapi/linux/fs.h | 1 +
+ tools/include/uapi/linux/userfaultfd.h | 54 +-
+ tools/mm/.gitignore | 1 +
+ tools/mm/Makefile | 4 +-
+ tools/mm/page_owner_filter.c | 310 +++++++
+ tools/mm/page_owner_sort.c | 87 +-
+ tools/testing/radix-tree/maple.c | 4 +-
+ tools/testing/selftests/damon/Makefile | 1 +
+ tools/testing/selftests/damon/_damon_sysfs.py | 23 +-
+ .../selftests/damon/damos_apply_interval.py | 2 +-
+ tools/testing/selftests/damon/damos_quota_goal.py | 2 +-
+ .../testing/selftests/damon/damos_tried_regions.py | 4 +-
+ .../selftests/damon/drgn_dump_damon_status.py | 3 +-
+ tools/testing/selftests/damon/sysfs.py | 35 +-
+ tools/testing/selftests/damon/sysfs.sh | 79 +-
+ tools/testing/selftests/damon/sysfs_refresh.py | 75 ++
+ ..._update_schemes_tried_regions_wss_estimation.py | 2 +-
+ tools/testing/selftests/mm/Makefile | 4 +
+ tools/testing/selftests/mm/hwpoison-panic.sh | 255 ++++++
+ tools/testing/selftests/mm/pkey-helpers.h | 4 +-
+ tools/testing/selftests/mm/pkey-powerpc.h | 2 +-
+ tools/testing/selftests/mm/pkey_sighandler_tests.c | 115 +--
+ tools/testing/selftests/mm/pkey_util.c | 90 ++
+ tools/testing/selftests/mm/protection_keys.c | 99 +--
+ tools/testing/selftests/mm/uffd-common.c | 9 +-
+ tools/testing/selftests/mm/uffd-unit-tests.c | 919 +++++++++++++++++++++
+ tools/testing/shared/linux/kmemleak.h | 1 +
+ 216 files changed, 7485 insertions(+), 3276 deletions(-)
+ rename {lib => mm}/alloc_tag.c (97%)
+ rename mm/{swap.c => folio.c} (95%)
+ create mode 100644 mm/page_alloc.h
+ create mode 100644 tools/mm/page_owner_filter.c
+ create mode 100755 tools/testing/selftests/damon/sysfs_refresh.py
+ create mode 100755 tools/testing/selftests/mm/hwpoison-panic.sh
+$ git am -3 ../patches/0001-mm-Fix-up-build-for-uninitialised-pte.patch
+Applying: mm: Fix up build for uninitialised pte
+Using index info to reconstruct a base tree...
+M mm/khugepaged.c
+Falling back to patching base and 3-way merge...
+Auto-merging mm/khugepaged.c
+No changes -- Patch already applied.
+Merging mm-nonmm-unstable/mm-nonmm-unstable (d9a23f527f674 rapidio: clear mport->net when rio_add_net() fails)
+$ git merge -m Merge branch 'mm-nonmm-unstable' of https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm mm-nonmm-unstable/mm-nonmm-unstable
+Auto-merging arch/riscv/include/asm/pgtable.h
+Auto-merging kernel/signal.c
+Auto-merging lib/Kconfig.debug
+Auto-merging mm/sparse-vmemmap.c
+Merge made by the 'ort' strategy.
+ .get_maintainer.ignore | 1 +
+ .mailmap | 1 +
+ Documentation/accounting/delay-accounting.rst | 45 +++-
+ arch/riscv/include/asm/cacheflush.h | 15 +-
+ arch/riscv/include/asm/pgtable.h | 13 +-
+ arch/riscv/kernel/entry.S | 11 +-
+ arch/riscv/mm/init.c | 6 +
+ drivers/media/v4l2-core/v4l2-vp9.c | 30 +--
+ drivers/pps/clients/pps-gpio.c | 66 +++---
+ drivers/pps/kc.c | 10 +
+ drivers/pps/pps.c | 10 +-
+ drivers/rapidio/rio-scan.c | 1 +
+ fs/fat/misc.c | 4 +
+ fs/ocfs2/cluster/heartbeat.c | 43 ++--
+ fs/ocfs2/cluster/nodemanager.c | 19 +-
+ fs/ocfs2/cluster/nodemanager.h | 2 +
+ fs/ocfs2/dir.c | 20 +-
+ fs/ocfs2/dlm/dlmmaster.c | 6 +
+ fs/ocfs2/dlm/dlmrecovery.c | 9 +
+ fs/ocfs2/inode.c | 6 +-
+ fs/ocfs2/namei.c | 17 +-
+ fs/ocfs2/xattr.c | 215 +++++++++++++++++--
+ fs/ocfs2/xattr.h | 2 +
+ fs/ramfs/file-nommu.c | 3 +
+ include/linux/nmi.h | 4 +-
+ include/linux/pps_kernel.h | 1 +
+ include/linux/taskstats_kern.h | 1 -
+ ipc/ipc_sysctl.c | 2 +-
+ kernel/fork.c | 2 +-
+ kernel/panic.c | 7 +-
+ kernel/params.c | 4 +-
+ kernel/reboot.c | 169 +++++++--------
+ kernel/resource.c | 2 +-
+ kernel/signal.c | 51 ++---
+ kernel/watchdog.c | 16 +-
+ lib/Kconfig | 6 -
+ lib/Kconfig.debug | 26 +++
+ lib/idr.c | 55 +++--
+ lib/math/tests/Makefile | 1 +
+ lib/math/tests/polynomial_kunit.c | 270 ++++++++++++++++++++++++
+ lib/random32.c | 184 +----------------
+ lib/string.c | 3 +-
+ lib/test_ida.c | 14 ++
+ lib/tests/Makefile | 3 +-
+ lib/tests/random32_kunit.c | 182 ++++++++++++++++
+ lib/xz/xz_dec_bcj.c | 2 +-
+ lib/xz/xz_dec_lzma2.c | 63 +++---
+ lib/xz/xz_dec_stream.c | 4 +-
+ lib/xz/xz_lzma2.h | 2 +-
+ mm/sparse-vmemmap.c | 8 +
+ scripts/checkpatch.pl | 6 +
+ tools/accounting/delaytop.c | 286 ++++++++++++++++++++++----
+ tools/accounting/getdelays.c | 5 +
+ tools/include/linux/compiler.h | 2 +-
+ 54 files changed, 1387 insertions(+), 549 deletions(-)
+ create mode 100644 lib/math/tests/polynomial_kunit.c
+ create mode 100644 lib/tests/random32_kunit.c
+Merging kbuild/kbuild-for-next (fba1a1acb42c0 kbuild: remove srctree path from CHECK output)
+$ git merge -m Merge branch 'kbuild-for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/kbuild/linux.git kbuild/kbuild-for-next
+Auto-merging Makefile
+Merge made by the 'ort' strategy.
+ Makefile | 6 ++++++
+ arch/arm64/include/asm/module.lds.h | 13 -------------
+ scripts/Makefile.build | 4 ++--
+ 3 files changed, 8 insertions(+), 15 deletions(-)
+Merging clang-format/clang-format (8f0b4cce4481f Linux 6.19-rc1)
+$ git merge -m Merge branch 'clang-format' of https://github.com/ojeda/linux.git clang-format/clang-format
+Already up to date.
+Merging perf/perf-tools-next (8c5f60344b07f perf dso: Fix kallsyms DSO detection with fallback logic)
+$ git merge -m Merge branch 'perf-tools-next' of https://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools-next.git perf/perf-tools-next
+Merge made by the 'ort' strategy.
+ tools/lib/api/fd/array.c | 6 +
+ tools/perf/Documentation/perf-test.txt | 6 +-
+ tools/perf/Makefile.perf | 9 +-
+ tools/perf/arch/arm/util/cs-etm.c | 10 +-
+ tools/perf/arch/arm64/util/arm-spe.c | 8 +-
+ tools/perf/arch/arm64/util/hisi-ptt.c | 2 +-
+ tools/perf/arch/x86/tests/amd-ibs-period.c | 20 +-
+ tools/perf/arch/x86/tests/hybrid.c | 22 +-
+ tools/perf/arch/x86/tests/topdown.c | 4 +-
+ tools/perf/arch/x86/util/auxtrace.c | 2 +-
+ tools/perf/arch/x86/util/intel-bts.c | 6 +-
+ tools/perf/arch/x86/util/intel-pt.c | 9 +-
+ tools/perf/arch/x86/util/iostat.c | 14 +-
+ tools/perf/bench/evlist-open-close.c | 29 +-
+ tools/perf/builtin-annotate.c | 7 +-
+ tools/perf/builtin-ftrace.c | 14 +-
+ tools/perf/builtin-inject.c | 9 +-
+ tools/perf/builtin-kvm.c | 123 +-
+ tools/perf/builtin-kwork.c | 8 +-
+ tools/perf/builtin-lock.c | 4 +-
+ tools/perf/builtin-record.c | 95 +-
+ tools/perf/builtin-report.c | 6 +-
+ tools/perf/builtin-sched.c | 46 +-
+ tools/perf/builtin-script.c | 16 +-
+ tools/perf/builtin-stat.c | 110 +-
+ tools/perf/builtin-timechart.c | 212 +-
+ tools/perf/builtin-top.c | 104 +-
+ tools/perf/builtin-trace.c | 65 +-
+ .../arch/x86/amdzen5/floating-point.json | 160 +-
+ .../pmu-events/arch/x86/amdzen5/load-store.json | 8 +-
+ .../arch/x86/amdzen6/floating-point.json | 34 +-
+ .../perf/pmu-events/arch/x86/arrowlake/cache.json | 30 +-
+ .../arch/x86/arrowlake/floating-point.json | 45 +
+ .../perf/pmu-events/arch/x86/arrowlake/memory.json | 18 +
+ .../pmu-events/arch/x86/arrowlake/pipeline.json | 129 +-
+ .../pmu-events/arch/x86/emeraldrapids/cache.json | 9 +
+ .../x86/graniterapids/uncore-interconnect.json | 10 +
+ .../arch/x86/graniterapids/uncore-memory.json | 2 +-
+ .../perf/pmu-events/arch/x86/lunarlake/cache.json | 2 +-
+ .../pmu-events/arch/x86/lunarlake/pipeline.json | 27 +-
+ .../arch/x86/lunarlake/uncore-memory.json | 208 +-
+ tools/perf/pmu-events/arch/x86/mapfile.csv | 12 +-
+ .../pmu-events/arch/x86/pantherlake/counter.json | 5 +
+ .../pmu-events/arch/x86/pantherlake/pipeline.json | 29 +-
+ .../arch/x86/pantherlake/uncore-interconnect.json | 10 +
+ .../arch/x86/pantherlake/uncore-memory.json | 221 +-
+ tools/perf/python/perf.pyi | 672 ++++++
+ tools/perf/python/perf_live.py | 59 +
+ tools/perf/scripts/python/arm-cs-trace-disasm.py | 9 +-
+ tools/perf/scripts/python/powerpc-hcalls.py | 137 +-
+ tools/perf/tests/backward-ring-buffer.c | 26 +-
+ tools/perf/tests/builtin-test.c | 182 +-
+ tools/perf/tests/code-reading.c | 14 +-
+ tools/perf/tests/event-times.c | 6 +-
+ tools/perf/tests/event_update.c | 4 +-
+ tools/perf/tests/evsel-roundtrip-name.c | 8 +-
+ tools/perf/tests/evsel-tp-sched.c | 4 +-
+ tools/perf/tests/expand-cgroup.c | 15 +-
+ tools/perf/tests/hists_cumulate.c | 2 +-
+ tools/perf/tests/hists_filter.c | 2 +-
+ tools/perf/tests/hists_link.c | 2 +-
+ tools/perf/tests/hists_output.c | 2 +-
+ tools/perf/tests/hwmon_pmu.c | 7 +-
+ tools/perf/tests/keep-tracking.c | 10 +-
+ tools/perf/tests/mmap-basic.c | 24 +-
+ tools/perf/tests/openat-syscall-all-cpus.c | 6 +-
+ tools/perf/tests/openat-syscall-tp-fields.c | 26 +-
+ tools/perf/tests/openat-syscall.c | 6 +-
+ tools/perf/tests/parse-events.c | 150 +-
+ tools/perf/tests/parse-metric.c | 11 +-
+ tools/perf/tests/parse-no-sample-id-all.c | 2 +-
+ tools/perf/tests/perf-record.c | 38 +-
+ tools/perf/tests/perf-time-to-tsc.c | 12 +-
+ tools/perf/tests/pfm.c | 12 +-
+ tools/perf/tests/pmu-events.c | 21 +-
+ tools/perf/tests/pmu.c | 4 +-
+ tools/perf/tests/sample-parsing.c | 45 +-
+ tools/perf/tests/shell/coresight/callchain.sh | 172 ++
+ .../shell/coresight/test_arm_coresight_disasm.sh | 4 +-
+ tools/perf/tests/shell/inject_aslr.sh | 10 +-
+ tools/perf/tests/shell/jitdump-python.sh | 69 +-
+ tools/perf/tests/shell/kvm.sh | 71 +-
+ .../perf/tests/shell/lib/perf_metric_validation.py | 11 +-
+ tools/perf/tests/shell/lib/perf_record.sh | 58 +
+ tools/perf/tests/shell/lib/setup_python.sh | 13 +
+ tools/perf/tests/shell/lock_contention.sh | 32 +-
+ tools/perf/tests/shell/pipe_test.sh | 4 +-
+ tools/perf/tests/shell/record.sh | 216 +-
+ tools/perf/tests/shell/record_lbr.sh | 50 +-
+ tools/perf/tests/shell/record_offcpu.sh | 14 +-
+ tools/perf/tests/shell/stat.sh | 12 +
+ tools/perf/tests/shell/stat_all_metrics.sh | 77 +-
+ tools/perf/tests/shell/stat_bpf_counters.sh | 28 +-
+ tools/perf/tests/shell/stat_metrics_values.sh | 9 +-
+ tools/perf/tests/shell/test_brstack.sh | 99 +-
+ tools/perf/tests/shell/timechart.sh | 24 +-
+ tools/perf/tests/shell/trace_record_replay.sh | 38 +-
+ tools/perf/tests/sw-clock.c | 20 +-
+ tools/perf/tests/switch-tracking.c | 11 +-
+ tools/perf/tests/task-exit.c | 20 +-
+ tools/perf/tests/tests.h | 1 +
+ tools/perf/tests/time-utils-test.c | 14 +-
+ tools/perf/tests/tool_pmu.c | 7 +-
+ tools/perf/tests/topology.c | 4 +-
+ tools/perf/tests/uncore-event-sorting.c | 6 +-
+ tools/perf/tests/workloads/Build | 2 +
+ tools/perf/tests/workloads/callchain.c | 33 +
+ tools/perf/tests/workloads/noploop.c | 17 +-
+ tools/perf/tests/workloads/thloop.c | 16 +-
+ tools/perf/ui/browsers/annotate.c | 2 +-
+ tools/perf/ui/browsers/hists.c | 22 +-
+ tools/perf/util/Build | 1 -
+ tools/perf/util/amd-sample-raw.c | 2 +-
+ tools/perf/util/annotate-data.c | 2 +-
+ tools/perf/util/annotate.c | 10 +-
+ tools/perf/util/aslr.c | 1 +
+ tools/perf/util/auxtrace.c | 14 +-
+ tools/perf/util/block-info.c | 4 +-
+ tools/perf/util/bpf_counter.c | 2 +-
+ tools/perf/util/bpf_counter_cgroup.c | 14 +-
+ tools/perf/util/bpf_ftrace.c | 9 +-
+ tools/perf/util/bpf_lock_contention.c | 12 +-
+ tools/perf/util/bpf_off_cpu.c | 44 +-
+ tools/perf/util/bpf_trace_augment.c | 8 +-
+ tools/perf/util/cgroup.c | 26 +-
+ tools/perf/util/cs-etm.c | 382 +--
+ tools/perf/util/data-convert-bt.c | 2 +-
+ tools/perf/util/data-convert-json.c | 1 +
+ tools/perf/util/data.c | 27 +-
+ tools/perf/util/data.h | 4 +-
+ tools/perf/util/dso.h | 57 +-
+ tools/perf/util/evlist.c | 494 ++--
+ tools/perf/util/evlist.h | 273 ++-
+ tools/perf/util/evsel.c | 39 +-
+ tools/perf/util/evsel.h | 42 +-
+ tools/perf/util/expr.c | 2 +-
+ tools/perf/util/header.c | 69 +-
+ tools/perf/util/header.h | 2 +-
+ tools/perf/util/intel-pt.c | 8 +-
+ tools/perf/util/intel-tpebs.c | 7 +-
+ tools/perf/util/iostat.c | 2 +-
+ tools/perf/util/iostat.h | 2 +-
+ tools/perf/util/kvm-stat-arch/book3s_hv_exits.h | 4 +-
+ tools/perf/util/kvm-stat-arch/kvm-stat-powerpc.c | 31 +-
+ tools/perf/util/kvm-stat-arch/kvm-stat-x86.c | 35 +-
+ tools/perf/util/kvm-stat.c | 41 +
+ tools/perf/util/kvm-stat.h | 18 +-
+ tools/perf/util/map.h | 9 +-
+ tools/perf/util/metricgroup.c | 38 +-
+ tools/perf/util/metricgroup.h | 4 +-
+ tools/perf/util/parse-events.c | 40 +-
+ tools/perf/util/parse-events.h | 17 +-
+ tools/perf/util/parse-events.y | 2 +-
+ tools/perf/util/perf_api_probe.c | 20 +-
+ tools/perf/util/pfm.c | 4 +-
+ tools/perf/util/pmu.c | 6 +-
+ tools/perf/util/pmus.c | 2 +
+ tools/perf/util/print-events.c | 2 +-
+ tools/perf/util/probe-file.c | 2 +
+ tools/perf/util/python.c | 2503 +++++++++++++++++---
+ tools/perf/util/record.c | 11 +-
+ tools/perf/util/s390-sample-raw.c | 22 +-
+ tools/perf/util/sample-raw.c | 4 +-
+ tools/perf/util/sample.c | 19 +-
+ tools/perf/util/session.c | 69 +-
+ tools/perf/util/session.h | 2 +
+ tools/perf/util/setup.py | 5 +
+ tools/perf/util/sideband_evlist.c | 54 +-
+ tools/perf/util/sort.c | 2 +-
+ tools/perf/util/stat-display.c | 6 +-
+ tools/perf/util/stat-shadow.c | 24 +-
+ tools/perf/util/stat.c | 22 +-
+ tools/perf/util/stream.c | 4 +-
+ tools/perf/util/symbol-elf.c | 4 +
+ tools/perf/util/symbol.c | 4 +-
+ tools/perf/util/symbol.h | 12 +
+ tools/perf/util/synthetic-events.c | 11 +-
+ tools/perf/util/time-utils.c | 12 +-
+ tools/perf/util/top.c | 4 +-
+ 179 files changed, 7083 insertions(+), 2177 deletions(-)
+ create mode 100644 tools/perf/pmu-events/arch/x86/pantherlake/uncore-interconnect.json
+ create mode 100644 tools/perf/python/perf.pyi
+ create mode 100755 tools/perf/python/perf_live.py
+ create mode 100755 tools/perf/tests/shell/coresight/callchain.sh
+ create mode 100644 tools/perf/tests/shell/lib/perf_record.sh
+ create mode 100644 tools/perf/tests/workloads/callchain.c
+Merging compiler-attributes/compiler-attributes (8f0b4cce4481f Linux 6.19-rc1)
+$ git merge -m Merge branch 'compiler-attributes' of https://github.com/ojeda/linux.git compiler-attributes/compiler-attributes
+Already up to date.
+Merging dma-mapping/dma-mapping-for-next (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'dma-mapping-for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/mszyprowski/linux.git dma-mapping/dma-mapping-for-next
+Already up to date.
+Merging asm-generic/master (adbbd9714f805 scripts: headers_install.sh: Remove config leak ignore machinery)
+$ git merge -m Merge branch 'master' of https://git.kernel.org/pub/scm/linux/kernel/git/arnd/asm-generic asm-generic/master
+Already up to date.
+Merging alpha/alpha-next (d58041d2c63e0 MAINTAINERS: Add Magnus Lindholm as maintainer for alpha port)
+$ git merge -m Merge branch 'alpha-next' of https://git.kernel.org/pub/scm/linux/kernel/git/mattst88/alpha.git alpha/alpha-next
+Already up to date.
+Merging arm/for-next (75ca78c7d982a Merge branches 'fixes' and 'misc' into for-next)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/rmk/linux.git arm/for-next
+Merge made by the 'ort' strategy.
+ arch/arm/probes/kprobes/test-core.c | 14 +++-----------
+ 1 file changed, 3 insertions(+), 11 deletions(-)
+Merging arm64/for-next/core (36fa5ffa60344 arm64: mm: Defer read-only remap of data/bss linear alias)
+$ git merge -m Merge branch 'for-next/core' of https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux arm64/for-next/core
+Already up to date.
+Merging arm-perf/for-next/perf (5936245125f78 perf/arm-cmn: Fix DVM node events)
+$ git merge -m Merge branch 'for-next/perf' of https://git.kernel.org/pub/scm/linux/kernel/git/will/linux.git arm-perf/for-next/perf
+Already up to date.
+Merging arm-soc/for-next (972ea78305bdd soc: document merges)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git arm-soc/for-next
+Merge made by the 'ort' strategy.
+ arch/arm/arm-soc-for-next-contents.txt | 200 +++++++++++++++++++++++++++++++++
+ 1 file changed, 200 insertions(+)
+ create mode 100644 arch/arm/arm-soc-for-next-contents.txt
+Merging amlogic/for-next (4336e970ec689 Merge branch 'v7.3/arm64-dt' into for-next)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/amlogic/linux.git amlogic/for-next
+Merge made by the 'ort' strategy.
+ .../soc/amlogic/amlogic,meson-gx-clk-measure.yaml | 2 +
+ arch/arm64/boot/dts/amlogic/amlogic-a9.dtsi | 140 +++++++++++
+ arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi | 5 +
+ arch/arm64/boot/dts/amlogic/meson-a1.dtsi | 5 +
+ drivers/soc/amlogic/meson-clk-measure.c | 272 +++++++++++++++++++++
+ 5 files changed, 424 insertions(+)
+Merging asahi-soc/asahi-soc/for-next (a23ce286383c9 Merge branch 'apple-soc/drivers-7.3' into asahi-soc/for-next)
+$ git merge -m Merge branch 'asahi-soc/for-next' of https://github.com/AsahiLinux/linux.git asahi-soc/asahi-soc/for-next
+Merge made by the 'ort' strategy.
+ arch/arm64/boot/dts/apple/t8122.dtsi | 30 +++++++++++++++---------------
+ drivers/soc/apple/sart.c | 9 +++++++--
+ 2 files changed, 22 insertions(+), 17 deletions(-)
+Merging at91/at91-next (6d892f8d5cd9f Merge branch 'clk-microchip-fixes' into at91-next)
+$ git merge -m Merge branch 'at91-next' of https://git.kernel.org/pub/scm/linux/kernel/git/at91/linux.git at91/at91-next
+Merge made by the 'ort' strategy.
+Merging bmc/for-next (40ae2e16214ad Merge branch 'nuvoton/arm/dt' into for-next)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/bmc/linux.git bmc/for-next
+Merge made by the 'ort' strategy.
+ arch/arm/boot/dts/nuvoton/nuvoton-common-npcm7xx.dtsi | 9 +++------
+ 1 file changed, 3 insertions(+), 6 deletions(-)
+Merging broadcom/next (f705b0c80bab1 arm: dts: bcm2711: Fix typo in gpio-line-names)
+$ git merge -m Merge branch 'next' of https://github.com/Broadcom/stblinux.git broadcom/next
+Merge made by the 'ort' strategy.
+Merging cix/for-next (a0cffbd8878c5 Merge remote-tracking branch 'cix/dt' into for-next)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/cix.git cix/for-next
+Merge made by the 'ort' strategy.
+Merging davinci/davinci/for-next (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'davinci/for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git davinci/davinci/for-next
+Already up to date.
+Merging drivers-memory/for-next (8111c7f3723f4 memory: tegra: Guard against NULL mc_regs in IRQ handler)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl.git drivers-memory/for-next
+Auto-merging drivers/memory/stm32_omm.c
+Auto-merging drivers/memory/tegra/tegra186-emc.c
+CONFLICT (content): Merge conflict in drivers/memory/tegra/tegra186-emc.c
+Resolved 'drivers/memory/tegra/tegra186-emc.c' using previous resolution.
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit --no-edit -v -a
+[master abae3a6429ff0] Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl.git
+$ git diff -M --stat --summary HEAD^..
+ drivers/memory/stm32_omm.c | 2 +-
+ drivers/memory/tegra/mc.c | 48 ++++++++++++++++++++-----
+ drivers/memory/tegra/mc.h | 37 +++++++++++++++++++
+ drivers/memory/tegra/tegra186-emc.c | 71 ++++++++++++++++++++++++++++---------
+ 4 files changed, 132 insertions(+), 26 deletions(-)
+Merging fsl/soc_fsl (4b265b93b4e0e powerpc: Move CONFIG_QE_GPIO to SoC)
+$ git merge -m Merge branch 'soc_fsl' of https://git.kernel.org/pub/scm/linux/kernel/git/chleroy/linux.git fsl/soc_fsl
+Merge made by the 'ort' strategy.
+ arch/powerpc/platforms/Kconfig | 8 --------
+ drivers/soc/fsl/qe/Kconfig | 8 ++++++++
+ drivers/soc/fsl/qe/qe_ports_ic.c | 15 +++++++++------
+ 3 files changed, 17 insertions(+), 14 deletions(-)
+$ git reset --hard HEAD^
+HEAD is now at abae3a6429ff0 Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl.git
+Merging next-20260709 version of fsl
+$ git merge -m next-20260709/fsl dc59e4fea9d83f03bad6bddf3fa2e52491777482
+Already up to date.
+Merging imx-mxs/for-next (10e06b5bd4be8 Merge branches 'imx/dt', 'imx/dt64' and 'imx/soc' into for-next)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/frank.li/linux.git imx-mxs/for-next
+Merge made by the 'ort' strategy.
+ Documentation/devicetree/bindings/arm/fsl.yaml | 18 +
+ .../bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml | 39 +
+ arch/arm/boot/dts/nxp/imx/imx6qdl-sabresd.dtsi | 2 +
+ arch/arm/boot/dts/nxp/imx/imx6sx-sdb.dtsi | 2 +
+ arch/arm/boot/dts/nxp/imx/imx7d-pico.dtsi | 23 +
+ arch/arm/boot/dts/nxp/ls/ls1021a-twr.dts | 2 +-
+ arch/arm/mach-imx/avic.c | 2 +
+ arch/arm/mach-imx/common.h | 7 -
+ arch/arm/mach-imx/src.c | 3 +
+ arch/arm/mach-imx/system.c | 8 -
+ arch/arm64/boot/dts/freescale/Makefile | 17 +
+ arch/arm64/boot/dts/freescale/imx8dxl-evk.dts | 3 +
+ arch/arm64/boot/dts/freescale/imx8mm-evk.dtsi | 2 +
+ .../boot/dts/freescale/imx8mm-var-som-symphony.dts | 12 +
+ arch/arm64/boot/dts/freescale/imx8mp-ab2.dts | 4 +
+ .../boot/dts/freescale/imx8mp-evk-flexcan2.dtso | 15 +
+ arch/arm64/boot/dts/freescale/imx8mp-evk.dts | 97 +-
+ arch/arm64/boot/dts/freescale/imx8mp-frdm.dts | 2 +
+ ...imx8mp-tqma8mpqs-mb-smarc-2-lvds-g133han01.dtso | 81 ++
+ ...8mp-tqma8mpqs-mb-smarc-2-lvds0-tm070jvhg33.dtso | 43 +
+ ...8mp-tqma8mpqs-mb-smarc-2-lvds1-tm070jvhg33.dtso | 43 +
+ .../dts/freescale/imx8mp-tqma8mpqs-mb-smarc-2.dts | 380 +++++++
+ .../arm64/boot/dts/freescale/imx8mp-tqma8mpqs.dtsi | 1178 ++++++++++++++++++++
+ .../boot/dts/freescale/imx8mp-var-dart-sonata.dts | 733 ++++++++++++
+ arch/arm64/boot/dts/freescale/imx8mp-var-dart.dtsi | 475 ++++++++
+ .../boot/dts/freescale/imx8mp-var-som-symphony.dts | 389 ++++++-
+ arch/arm64/boot/dts/freescale/imx8mp-var-som.dtsi | 12 +-
+ arch/arm64/boot/dts/freescale/imx8mq-evk.dts | 84 ++
+ arch/arm64/boot/dts/freescale/imx8qm-mek.dts | 3 +
+ arch/arm64/boot/dts/freescale/imx8qxp-mek.dts | 3 +
+ .../freescale/imx93-11x11-evk-dy1212w-4856.dtso | 81 ++
+ .../boot/dts/freescale/imx93-kontron-osm-s.dtsi | 4 +-
+ arch/arm64/boot/dts/freescale/imx93.dtsi | 39 +-
+ arch/arm64/boot/dts/freescale/imx94.dtsi | 16 +-
+ arch/arm64/boot/dts/freescale/imx943-evk.dts | 14 +-
+ arch/arm64/boot/dts/freescale/imx943.dtsi | 16 +-
+ arch/arm64/boot/dts/freescale/imx95-15x15-evk.dts | 4 +-
+ arch/arm64/boot/dts/freescale/imx95-19x19-evk.dts | 8 +-
+ .../boot/dts/freescale/imx95-toradex-smarc.dtsi | 1 +
+ arch/arm64/boot/dts/freescale/imx95-var-dart.dtsi | 10 +
+ arch/arm64/boot/dts/freescale/imx95.dtsi | 62 +-
+ arch/arm64/boot/dts/freescale/s32g2.dtsi | 21 +-
+ arch/arm64/boot/dts/freescale/s32g3.dtsi | 21 +-
+ drivers/firmware/imx/sm-misc.c | 3 +
+ 44 files changed, 3912 insertions(+), 70 deletions(-)
+ create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-flexcan2.dtso
+ create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-tqma8mpqs-mb-smarc-2-lvds-g133han01.dtso
+ create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-tqma8mpqs-mb-smarc-2-lvds0-tm070jvhg33.dtso
+ create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-tqma8mpqs-mb-smarc-2-lvds1-tm070jvhg33.dtso
+ create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-tqma8mpqs-mb-smarc-2.dts
+ create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-tqma8mpqs.dtsi
+ create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-var-dart-sonata.dts
+ create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-var-dart.dtsi
+ create mode 100644 arch/arm64/boot/dts/freescale/imx93-11x11-evk-dy1212w-4856.dtso
+Merging mediatek/for-next (03168882793c8 Merge branch 'v7.2-next/dts64' into for-next)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/mediatek/linux.git mediatek/for-next
+Merge made by the 'ort' strategy.
+ arch/arm/boot/dts/mediatek/mt8127.dtsi | 2 +-
+ arch/arm64/boot/dts/mediatek/mt6795.dtsi | 4 +-
+ .../boot/dts/mediatek/mt8183-kukui-kodama.dtsi | 6 +-
+ .../dts/mediatek/mt8183-kukui-krane-sku176.dts | 4 +-
+ arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi | 2 +
+ arch/arm64/boot/dts/mediatek/mt8183.dtsi | 22 ++++
+ arch/arm64/boot/dts/mediatek/mt8186.dtsi | 132 ++++++++++++---------
+ arch/arm64/boot/dts/mediatek/mt8188-geralt.dtsi | 1 +
+ arch/arm64/boot/dts/mediatek/mt8188.dtsi | 33 ++++++
+ arch/arm64/boot/dts/mediatek/mt8192.dtsi | 17 +++
+ arch/arm64/boot/dts/mediatek/mt8195.dtsi | 37 ++++++
+ .../boot/dts/mediatek/mt8390-genio-common.dtsi | 2 +-
+ .../boot/dts/mediatek/mt8390-tungsten-smarc.dtsi | 4 -
+ 13 files changed, 197 insertions(+), 69 deletions(-)
+Merging mvebu/for-next (3ea0dabfa4500 Merge branch 'mvebu/dt64' into mvebu/for-next)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/gclement/mvebu.git mvebu/for-next
+Merge made by the 'ort' strategy.
+ arch/arm64/boot/dts/marvell/armada-37xx.dtsi | 1 +
+ 1 file changed, 1 insertion(+)
+Merging omap/for-next (ba251bb5ce2db Merge branch 'omap-for-v7.3/drivers' into tmp/omap-next-20260706.114259)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-omap.git omap/for-next
+Merge made by the 'ort' strategy.
+ arch/arm/boot/dts/ti/davinci/da850-lcdk.dts | 2 +-
+ arch/arm/boot/dts/ti/omap/Makefile | 4 +
+ .../dts/ti/omap/am335x-icev2-prueth-overlay.dtso | 156 +++++++++++++++++++++
+ arch/arm/boot/dts/ti/omap/am33xx-l4.dtsi | 15 +-
+ arch/arm/boot/dts/ti/omap/am3517-evm.dts | 2 +-
+ arch/arm/boot/dts/ti/omap/am4372.dtsi | 11 ++
+ arch/arm/boot/dts/ti/omap/am437x-idk-evm.dts | 103 +++++++++++++-
+ arch/arm/boot/dts/ti/omap/am437x-l4.dtsi | 2 +-
+ arch/arm/boot/dts/ti/omap/am57-pruss.dtsi | 11 ++
+ arch/arm/boot/dts/ti/omap/am571x-idk.dts | 8 +-
+ arch/arm/boot/dts/ti/omap/am5729-beagleboneai.dts | 2 +-
+ arch/arm/boot/dts/ti/omap/am572x-idk.dts | 10 +-
+ arch/arm/boot/dts/ti/omap/am574x-idk.dts | 10 +-
+ arch/arm/boot/dts/ti/omap/am57xx-idk-common.dtsi | 61 ++++++++
+ arch/arm/boot/dts/ti/omap/dm8148-evm.dts | 4 +-
+ arch/arm/boot/dts/ti/omap/dm814x.dtsi | 2 +-
+ arch/arm/boot/dts/ti/omap/dm816x-clocks.dtsi | 2 +-
+ arch/arm/boot/dts/ti/omap/dm816x.dtsi | 2 +-
+ arch/arm/boot/dts/ti/omap/dra7-l4.dtsi | 4 +-
+ .../boot/dts/ti/omap/motorola-mapphone-common.dtsi | 10 +-
+ arch/arm/boot/dts/ti/omap/omap2430.dtsi | 2 +-
+ arch/arm/boot/dts/ti/omap/omap3-cm-t3x30.dtsi | 2 +-
+ arch/arm/boot/dts/ti/omap/omap3-n950-n9.dtsi | 2 +-
+ .../boot/dts/ti/omap/omap3-overo-common-lcd35.dtsi | 2 +-
+ .../boot/dts/ti/omap/omap3-overo-common-lcd43.dtsi | 2 +-
+ arch/arm/boot/dts/ti/omap/omap3.dtsi | 2 +-
+ arch/arm/boot/dts/ti/omap/omap4-epson-embt2ws.dts | 13 +-
+ arch/arm/boot/dts/ti/omap/omap4-l4.dtsi | 2 +-
+ arch/arm/boot/dts/ti/omap/omap4-panda-es.dts | 2 +-
+ arch/arm/boot/dts/ti/omap/omap4-var-som-om44.dtsi | 14 ++
+ arch/arm/boot/dts/ti/omap/omap5-l4.dtsi | 6 +-
+ arch/arm/configs/multi_v7_defconfig | 2 +
+ arch/arm/configs/omap2plus_defconfig | 13 ++
+ arch/arm/mach-omap2/omap_hwmod.c | 26 ++--
+ arch/arm/mach-omap2/sleep44xx.S | 5 +-
+ drivers/bus/ti-sysc.c | 12 +-
+ 36 files changed, 472 insertions(+), 56 deletions(-)
+ create mode 100644 arch/arm/boot/dts/ti/omap/am335x-icev2-prueth-overlay.dtso
+Merging qcom/for-next (076bbf9ad4df1 Merge branches 'arm32-for-7.3', 'arm64-defconfig-for-7.3', 'arm64-fixes-for-7.2', 'arm64-for-7.3', 'clk-fixes-for-7.2', 'clk-for-7.3' and 'drivers-for-7.3' into for-next)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux.git qcom/for-next
+Auto-merging MAINTAINERS
+Auto-merging drivers/clk/qcom/dispcc-eliza.c
+Auto-merging drivers/clk/qcom/gcc-glymur.c
+Auto-merging drivers/clk/qcom/gcc-qcs8300.c
+Auto-merging drivers/clk/qcom/gxclkctl-kaanapali.c
+Auto-merging drivers/soc/qcom/qcom_pd_mapper.c
+Merge made by the 'ort' strategy.
+ Documentation/devicetree/bindings/arm/qcom.yaml | 526 +--
+ .../devicetree/bindings/cache/qcom,llcc.yaml | 63 +-
+ .../bindings/clock/qcom,glymur-evacc.yaml | 72 +
+ .../devicetree/bindings/clock/qcom,rpmcc.yaml | 65 +-
+ .../devicetree/bindings/clock/qcom,shikra-gcc.yaml | 70 +
+ .../bindings/clock/qcom,sm8450-videocc.yaml | 3 +
+ .../devicetree/bindings/firmware/qcom,scm.yaml | 2 +
+ .../bindings/soc/qcom/qcom,aoss-qmp.yaml | 1 +
+ .../bindings/soc/qcom/qcom,pmic-glink.yaml | 1 +
+ .../devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml | 1 +
+ Documentation/devicetree/bindings/sram/sram.yaml | 2 +
+ .../devicetree/bindings/vendor-prefixes.yaml | 2 +
+ MAINTAINERS | 9 +
+ arch/arm/boot/dts/qcom/Makefile | 1 +
+ arch/arm/boot/dts/qcom/msm8226-motorola-titan.dts | 350 ++
+ arch/arm/boot/dts/qcom/pm8921.dtsi | 12 +
+ arch/arm/boot/dts/qcom/qcom-apq8064-pins.dtsi | 2 +-
+ arch/arm/boot/dts/qcom/qcom-ipq8064.dtsi | 4 +-
+ arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548.dtsi | 2 +-
+ .../dts/qcom/qcom-msm8960-samsung-expressatt.dts | 54 +
+ arch/arm/boot/dts/qcom/qcom-msm8974.dtsi | 2 +-
+ arch/arm/boot/dts/qcom/qcom-msm8974pro-htc-m8.dts | 94 +-
+ arch/arm/boot/dts/qcom/qcom-sdx55-t55.dts | 2 -
+ .../boot/dts/qcom/qcom-sdx55-telit-fn980-tlb.dts | 2 -
+ arch/arm/boot/dts/qcom/qcom-sdx55.dtsi | 3 +
+ arch/arm/boot/dts/qcom/qcom-sdx65-mtp.dts | 2 +-
+ arch/arm64/boot/dts/qcom/Makefile | 18 +-
+ arch/arm64/boot/dts/qcom/apq8016-sbc-usb-host.dtso | 2 +-
+ arch/arm64/boot/dts/qcom/eliza-cqs-evk.dts | 14 +
+ arch/arm64/boot/dts/qcom/eliza-cqs-som.dtsi | 399 ++
+ arch/arm64/boot/dts/qcom/eliza-evk.dtsi | 20 +
+ arch/arm64/boot/dts/qcom/eliza-mtp.dts | 5 +
+ arch/arm64/boot/dts/qcom/eliza.dtsi | 100 +-
+ arch/arm64/boot/dts/qcom/glymur-crd.dts | 399 --
+ arch/arm64/boot/dts/qcom/glymur-crd.dtsi | 532 +++
+ arch/arm64/boot/dts/qcom/glymur.dtsi | 854 +++-
+ arch/arm64/boot/dts/qcom/hamoa-iot-evk.dts | 16 +
+ arch/arm64/boot/dts/qcom/hamoa.dtsi | 124 +-
+ arch/arm64/boot/dts/qcom/ipq5018.dtsi | 10 +
+ arch/arm64/boot/dts/qcom/ipq5332-rdp-common.dtsi | 24 +-
+ arch/arm64/boot/dts/qcom/ipq5332-rdp441.dts | 16 +-
+ arch/arm64/boot/dts/qcom/ipq5332.dtsi | 53 +-
+ arch/arm64/boot/dts/qcom/ipq5424-rdp466.dts | 12 +-
+ arch/arm64/boot/dts/qcom/ipq5424.dtsi | 24 +-
+ arch/arm64/boot/dts/qcom/ipq6018.dtsi | 10 +
+ arch/arm64/boot/dts/qcom/ipq9574.dtsi | 34 +-
+ arch/arm64/boot/dts/qcom/kaanapali.dtsi | 615 +++
+ arch/arm64/boot/dts/qcom/kodiak.dtsi | 36 +-
+ arch/arm64/boot/dts/qcom/lemans-auto.dtsi | 104 -
+ arch/arm64/boot/dts/qcom/lemans-evk-camera.dtso | 2 +-
+ arch/arm64/boot/dts/qcom/lemans-evk.dts | 251 +-
+ arch/arm64/boot/dts/qcom/lemans-ride-common.dtsi | 4 +-
+ arch/arm64/boot/dts/qcom/lemans.dtsi | 55 +-
+ arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts | 29 +-
+ .../boot/dts/qcom/milos-nothing-asteroids.dts | 38 -
+ arch/arm64/boot/dts/qcom/milos.dtsi | 280 +-
+ arch/arm64/boot/dts/qcom/monaco-arduino-monza.dts | 114 +-
+ arch/arm64/boot/dts/qcom/monaco.dtsi | 86 +-
+ .../arm64/boot/dts/qcom/msm8953-flipkart-rimob.dts | 138 +-
+ arch/arm64/boot/dts/qcom/msm8996-xiaomi-gemini.dts | 2 +-
+ arch/arm64/boot/dts/qcom/msm8996.dtsi | 41 +
+ arch/arm64/boot/dts/qcom/pm7550-eliza.dtsi | 61 +
+ arch/arm64/boot/dts/qcom/pm8010-kaanapali.dtsi | 20 +
+ arch/arm64/boot/dts/qcom/pm8010.dtsi | 20 +
+ arch/arm64/boot/dts/qcom/pm8550vs-d-eliza.dtsi | 63 +
+ arch/arm64/boot/dts/qcom/pm8550vs-g-eliza.dtsi | 63 +
+ arch/arm64/boot/dts/qcom/pmk8550-eliza.dtsi | 87 +
+ arch/arm64/boot/dts/qcom/pmr735d-eliza.dtsi | 63 +
+ arch/arm64/boot/dts/qcom/purwa.dtsi | 12 +
+ arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts | 64 +-
+ .../boot/dts/qcom/qcm6490-particle-tachyon.dts | 16 +-
+ arch/arm64/boot/dts/qcom/qcm6490-shift-otter.dts | 7 +-
+ arch/arm64/boot/dts/qcom/qcs615-ride.dts | 6 +-
+ .../boot/dts/qcom/qcs6490-radxa-dragon-q6a.dts | 20 +-
+ arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts | 7 +-
+ .../dts/qcom/qcs6490-thundercomm-minipc-g1iot.dts | 18 +-
+ .../boot/dts/qcom/qcs6490-thundercomm-rubikpi3.dts | 20 +-
+ arch/arm64/boot/dts/qcom/qcs8550-rb5gen2.dts | 1573 +++++++
+ arch/arm64/boot/dts/qcom/qdu1000.dtsi | 2 +-
+ .../dts/qcom/qrb2210-rb1-vision-mezzanine.dtso | 4 +-
+ arch/arm64/boot/dts/qcom/qrb4210-rb2.dts | 6 +
+ arch/arm64/boot/dts/qcom/sa8295p-adp.dts | 32 +-
+ arch/arm64/boot/dts/qcom/sa8540p-ride.dts | 16 +-
+ arch/arm64/boot/dts/qcom/sa8775p-ride-r3.dts | 17 -
+ arch/arm64/boot/dts/qcom/sa8775p-ride.dts | 17 -
+ arch/arm64/boot/dts/qcom/sar2130p.dtsi | 2 +-
+ arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi | 5 +
+ arch/arm64/boot/dts/qcom/sc7180.dtsi | 2 +-
+ .../boot/dts/qcom/sc7280-herobrine-lte-sku.dtsi | 2 +
+ arch/arm64/boot/dts/qcom/sc7280-herobrine.dtsi | 5 +
+ arch/arm64/boot/dts/qcom/sc7280-idp.dtsi | 5 +-
+ .../arm64/boot/dts/qcom/sc8180x-lenovo-flex-5g.dts | 57 +-
+ arch/arm64/boot/dts/qcom/sc8180x-primus.dts | 56 +-
+ arch/arm64/boot/dts/qcom/sc8180x.dtsi | 2 +-
+ arch/arm64/boot/dts/qcom/sc8280xp-crd.dts | 22 +-
+ .../boot/dts/qcom/sc8280xp-huawei-gaokun3.dts | 16 +-
+ .../dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts | 38 +-
+ .../boot/dts/qcom/sc8280xp-microsoft-arcata.dts | 301 +-
+ .../boot/dts/qcom/sc8280xp-microsoft-blackrock.dts | 25 +-
+ arch/arm64/boot/dts/qcom/sc8280xp.dtsi | 347 +-
+ arch/arm64/boot/dts/qcom/sdm670-google-common.dtsi | 5 +
+ arch/arm64/boot/dts/qcom/sdm670.dtsi | 2 +-
+ arch/arm64/boot/dts/qcom/sdm845-google-common.dtsi | 8 +-
+ arch/arm64/boot/dts/qcom/sdm845-lg-common.dtsi | 3 -
+ arch/arm64/boot/dts/qcom/sdm845-mtp.dts | 2 -
+ .../arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi | 4 +-
+ .../boot/dts/qcom/sdm845-samsung-starqltechn.dts | 2 -
+ arch/arm64/boot/dts/qcom/sdm845-shift-axolotl.dts | 2 -
+ .../dts/qcom/sdm845-xiaomi-beryllium-common.dtsi | 2 -
+ arch/arm64/boot/dts/qcom/sdm845-xiaomi-polaris.dts | 2 -
+ arch/arm64/boot/dts/qcom/sdm845.dtsi | 5 +-
+ .../dts/qcom/sdm850-huawei-matebook-e-2019.dts | 2 -
+ .../boot/dts/qcom/sdm850-lenovo-yoga-c630.dts | 6 +-
+ arch/arm64/boot/dts/qcom/sdm850-samsung-w737.dts | 3 +-
+ arch/arm64/boot/dts/qcom/sdx75.dtsi | 2 +-
+ arch/arm64/boot/dts/qcom/shikra-cqm-evk.dts | 40 +
+ arch/arm64/boot/dts/qcom/shikra-cqm-som.dtsi | 156 +
+ arch/arm64/boot/dts/qcom/shikra-cqs-evk.dts | 40 +
+ arch/arm64/boot/dts/qcom/shikra-evk.dtsi | 14 +
+ arch/arm64/boot/dts/qcom/shikra-iqs-evk.dts | 40 +
+ arch/arm64/boot/dts/qcom/shikra-iqs-som.dtsi | 170 +
+ arch/arm64/boot/dts/qcom/shikra.dtsi | 842 ++++
+ arch/arm64/boot/dts/qcom/sm4450.dtsi | 2 +-
+ arch/arm64/boot/dts/qcom/sm6115-fxtec-pro1x.dts | 2 +-
+ arch/arm64/boot/dts/qcom/sm6115.dtsi | 65 +
+ .../boot/dts/qcom/sm6125-xiaomi-ginkgo-common.dtsi | 64 +-
+ .../boot/dts/qcom/sm6125-xiaomi-laurel-sprout.dts | 2 +-
+ arch/arm64/boot/dts/qcom/sm6125.dtsi | 168 +-
+ arch/arm64/boot/dts/qcom/sm6350.dtsi | 19 +-
+ arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts | 5 +-
+ .../dts/qcom/sm7325-motorola-dubai-common.dtsi | 1454 +++++++
+ .../boot/dts/qcom/sm7325-motorola-dubai-csot.dts | 13 +
+ .../boot/dts/qcom/sm7325-motorola-dubai-tianma.dts | 13 +
+ arch/arm64/boot/dts/qcom/sm7325-motorola-dubai.dts | 3 -
+ .../boot/dts/qcom/sm7325-nothing-spacewar.dts | 2 -
+ arch/arm64/boot/dts/qcom/sm7325-xiaomi-taoyao.dts | 913 ++++
+ arch/arm64/boot/dts/qcom/sm8150.dtsi | 2 +-
+ .../boot/dts/qcom/sm8250-xiaomi-elish-common.dtsi | 153 +
+ arch/arm64/boot/dts/qcom/sm8250.dtsi | 21 +-
+ arch/arm64/boot/dts/qcom/sm8350-hdk.dts | 11 +-
+ .../dts/qcom/sm8350-microsoft-surface-duo2.dts | 2 -
+ arch/arm64/boot/dts/qcom/sm8350-mtp.dts | 2 -
+ .../boot/dts/qcom/sm8350-sony-xperia-sagami.dtsi | 3 +-
+ arch/arm64/boot/dts/qcom/sm8350.dtsi | 86 +-
+ arch/arm64/boot/dts/qcom/sm8450.dtsi | 2 +-
+ arch/arm64/boot/dts/qcom/sm8550-hdk.dts | 4 +-
+ arch/arm64/boot/dts/qcom/sm8550-qrd.dts | 4 +-
+ arch/arm64/boot/dts/qcom/sm8550.dtsi | 28 +-
+ arch/arm64/boot/dts/qcom/sm8650-hdk.dts | 3 +-
+ arch/arm64/boot/dts/qcom/sm8650-qrd.dts | 3 +-
+ arch/arm64/boot/dts/qcom/sm8650.dtsi | 131 +-
+ arch/arm64/boot/dts/qcom/sm8750.dtsi | 89 +-
+ arch/arm64/boot/dts/qcom/talos-evk-som.dtsi | 8 +
+ arch/arm64/boot/dts/qcom/talos.dtsi | 140 +-
+ arch/arm64/boot/dts/qcom/x1-crd.dtsi | 16 +
+ .../dts/qcom/x1e80100-honor-magicbook-art-14.dts | 1341 ++++++
+ .../boot/dts/qcom/x1p42100-microsoft-sp12in.dts | 1194 ++++++
+ arch/arm64/configs/defconfig | 3 +
+ drivers/bus/qcom-ebi2.c | 10 +-
+ drivers/clk/qcom/Kconfig | 35 +-
+ drivers/clk/qcom/Makefile | 3 +
+ drivers/clk/qcom/clk-regmap-phy-mux.c | 58 +-
+ drivers/clk/qcom/clk-smd-rpm.c | 5 +
+ drivers/clk/qcom/common.c | 2 +-
+ drivers/clk/qcom/dispcc-eliza.c | 2 +-
+ drivers/clk/qcom/evacc-glymur.c | 455 ++
+ drivers/clk/qcom/gcc-glymur.c | 32 +-
+ drivers/clk/qcom/gcc-ipq5424.c | 11 -
+ drivers/clk/qcom/gcc-qcs8300.c | 8 +-
+ drivers/clk/qcom/gcc-shikra.c | 4431 ++++++++++++++++++++
+ drivers/clk/qcom/gcc-sm6115.c | 1 +
+ drivers/clk/qcom/gdsc.c | 47 +-
+ drivers/clk/qcom/gdsc.h | 1 +
+ drivers/clk/qcom/gxclkctl-kaanapali.c | 12 +-
+ drivers/clk/qcom/videocc-hawi.c | 840 ++++
+ drivers/firmware/qcom/Kconfig | 22 +-
+ drivers/firmware/qcom/Makefile | 2 +
+ drivers/firmware/qcom/qcom_pas.c | 298 ++
+ drivers/firmware/qcom/qcom_pas.h | 50 +
+ drivers/firmware/qcom/qcom_pas_tee.c | 479 +++
+ drivers/firmware/qcom/qcom_scm.c | 335 +-
+ drivers/soc/qcom/Kconfig | 12 +-
+ drivers/soc/qcom/cmd-db.c | 2 +-
+ drivers/soc/qcom/ice.c | 4 +-
+ drivers/soc/qcom/llcc-qcom.c | 29 +
+ drivers/soc/qcom/qcom_pd_mapper.c | 38 +
+ drivers/soc/qcom/qcom_stats.c | 2 +
+ drivers/soc/qcom/socinfo.c | 1 +
+ drivers/soc/qcom/ubwc_config.c | 370 +-
+ include/dt-bindings/arm/qcom,ids.h | 1 +
+ include/dt-bindings/clock/qcom,glymur-evacc.h | 38 +
+ include/dt-bindings/clock/qcom,hawi-videocc.h | 64 +
+ include/dt-bindings/clock/qcom,shikra-gcc.h | 263 ++
+ include/linux/firmware/qcom/qcom_pas.h | 43 +
+ include/linux/soc/qcom/ubwc.h | 83 +-
+ 195 files changed, 22081 insertions(+), 2238 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/clock/qcom,glymur-evacc.yaml
+ create mode 100644 Documentation/devicetree/bindings/clock/qcom,shikra-gcc.yaml
+ create mode 100644 arch/arm/boot/dts/qcom/msm8226-motorola-titan.dts
+ create mode 100644 arch/arm64/boot/dts/qcom/eliza-cqs-evk.dts
+ create mode 100644 arch/arm64/boot/dts/qcom/eliza-cqs-som.dtsi
+ create mode 100644 arch/arm64/boot/dts/qcom/eliza-evk.dtsi
+ delete mode 100644 arch/arm64/boot/dts/qcom/lemans-auto.dtsi
+ create mode 100644 arch/arm64/boot/dts/qcom/pm7550-eliza.dtsi
+ create mode 100644 arch/arm64/boot/dts/qcom/pm8550vs-d-eliza.dtsi
+ create mode 100644 arch/arm64/boot/dts/qcom/pm8550vs-g-eliza.dtsi
+ create mode 100644 arch/arm64/boot/dts/qcom/pmk8550-eliza.dtsi
+ create mode 100644 arch/arm64/boot/dts/qcom/pmr735d-eliza.dtsi
+ create mode 100644 arch/arm64/boot/dts/qcom/qcs8550-rb5gen2.dts
+ delete mode 100644 arch/arm64/boot/dts/qcom/sa8775p-ride-r3.dts
+ delete mode 100644 arch/arm64/boot/dts/qcom/sa8775p-ride.dts
+ create mode 100644 arch/arm64/boot/dts/qcom/shikra-cqm-evk.dts
+ create mode 100644 arch/arm64/boot/dts/qcom/shikra-cqm-som.dtsi
+ create mode 100644 arch/arm64/boot/dts/qcom/shikra-cqs-evk.dts
+ create mode 100644 arch/arm64/boot/dts/qcom/shikra-evk.dtsi
+ create mode 100644 arch/arm64/boot/dts/qcom/shikra-iqs-evk.dts
+ create mode 100644 arch/arm64/boot/dts/qcom/shikra-iqs-som.dtsi
+ create mode 100644 arch/arm64/boot/dts/qcom/shikra.dtsi
+ create mode 100644 arch/arm64/boot/dts/qcom/sm7325-motorola-dubai-common.dtsi
+ create mode 100644 arch/arm64/boot/dts/qcom/sm7325-motorola-dubai-csot.dts
+ create mode 100644 arch/arm64/boot/dts/qcom/sm7325-motorola-dubai-tianma.dts
+ create mode 100644 arch/arm64/boot/dts/qcom/sm7325-xiaomi-taoyao.dts
+ create mode 100644 arch/arm64/boot/dts/qcom/x1e80100-honor-magicbook-art-14.dts
+ create mode 100644 arch/arm64/boot/dts/qcom/x1p42100-microsoft-sp12in.dts
+ create mode 100644 drivers/clk/qcom/evacc-glymur.c
+ create mode 100644 drivers/clk/qcom/gcc-shikra.c
+ create mode 100644 drivers/clk/qcom/videocc-hawi.c
+ create mode 100644 drivers/firmware/qcom/qcom_pas.c
+ create mode 100644 drivers/firmware/qcom/qcom_pas.h
+ create mode 100644 drivers/firmware/qcom/qcom_pas_tee.c
+ create mode 100644 include/dt-bindings/clock/qcom,glymur-evacc.h
+ create mode 100644 include/dt-bindings/clock/qcom,hawi-videocc.h
+ create mode 100644 include/dt-bindings/clock/qcom,shikra-gcc.h
+ create mode 100644 include/linux/firmware/qcom/qcom_pas.h
+Merging renesas/next (30d3a7db74710 Merge branch 'renesas-dts-for-v7.3' into renesas-next)
+$ git merge -m Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-devel.git renesas/next
+Merge made by the 'ort' strategy.
+ arch/arm/boot/dts/renesas/r8a7740.dtsi | 12 +-
+ .../arm/boot/dts/renesas/r9a06g032-rzn1d400-eb.dts | 25 +
+ arch/arm/boot/dts/renesas/r9a06g032.dtsi | 84 ++++
+ arch/arm/mach-shmobile/regulator-quirk-rcar-gen2.c | 10 +-
+ arch/arm/mach-shmobile/setup-rcar-gen2.c | 9 +-
+ arch/arm64/boot/dts/renesas/r8a774a1.dtsi | 2 +-
+ arch/arm64/boot/dts/renesas/r8a774b1.dtsi | 2 +-
+ arch/arm64/boot/dts/renesas/r8a774e1.dtsi | 2 +-
+ arch/arm64/boot/dts/renesas/r8a77960.dtsi | 2 +-
+ arch/arm64/boot/dts/renesas/r8a77961.dtsi | 2 +-
+ .../arm64/boot/dts/renesas/r8a77965-salvator-x.dts | 4 +
+ .../boot/dts/renesas/r8a77965-salvator-xs.dts | 4 +
+ arch/arm64/boot/dts/renesas/r8a77965-ulcb.dts | 4 +
+ arch/arm64/boot/dts/renesas/r8a77965.dtsi | 2 +-
+ arch/arm64/boot/dts/renesas/r8a77970.dtsi | 2 +-
+ arch/arm64/boot/dts/renesas/r8a77980.dtsi | 2 +-
+ arch/arm64/boot/dts/renesas/r8a77995.dtsi | 2 +-
+ arch/arm64/boot/dts/renesas/r8a779g0.dtsi | 17 +
+ arch/arm64/boot/dts/renesas/r8a78000.dtsi | 32 ++
+ arch/arm64/boot/dts/renesas/r9a08g046.dtsi | 69 +++
+ arch/arm64/boot/dts/renesas/r9a08g046l48-smarc.dts | 78 +++
+ arch/arm64/boot/dts/renesas/r9a09g047.dtsi | 523 ++++++++++++++++++++-
+ arch/arm64/boot/dts/renesas/r9a09g047e57-smarc.dts | 114 ++++-
+ arch/arm64/boot/dts/renesas/r9a09g056.dtsi | 20 +-
+ arch/arm64/boot/dts/renesas/r9a09g057.dtsi | 20 +-
+ .../boot/dts/renesas/r9a09g077m44-rzt2h-evk.dts | 144 ++++--
+ .../boot/dts/renesas/r9a09g087m44-rzn2h-evk.dts | 144 ++++--
+ arch/arm64/boot/dts/renesas/rzg3e-smarc-som.dtsi | 44 ++
+ .../boot/dts/renesas/rzt2h-n2h-evk-common.dtsi | 14 +
+ 29 files changed, 1270 insertions(+), 119 deletions(-)
+Merging reset/reset/next (d373605cd5148 Merge tag 'reset-fixes-for-v7.0-2' into reset/next)
+$ git merge -m Merge branch 'reset/next' of https://git.kernel.org/pub/scm/linux/kernel/git/pza/linux reset/reset/next
+Already up to date.
+Merging rockchip/for-next (f5ed1537219ae Merge branch 'v7.3-armsoc/dts64' into for-next)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git rockchip/for-next
+Auto-merging Documentation/devicetree/bindings/vendor-prefixes.yaml
+Merge made by the 'ort' strategy.
+ .../devicetree/bindings/arm/rockchip.yaml | 10 +
+ .../devicetree/bindings/arm/rockchip/pmu.yaml | 8 +-
+ .../devicetree/bindings/soc/rockchip/grf.yaml | 7 +-
+ .../devicetree/bindings/vendor-prefixes.yaml | 2 +
+ arch/arm64/boot/dts/rockchip/Makefile | 2 +
+ arch/arm64/boot/dts/rockchip/px30-cobra.dtsi | 2 +-
+ arch/arm64/boot/dts/rockchip/px30-pp1516.dtsi | 2 +-
+ .../rockchip/px30-ringneck-haikou-video-demo.dtso | 10 +-
+ arch/arm64/boot/dts/rockchip/px30-ringneck.dtsi | 2 +-
+ arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi | 2 +-
+ .../boot/dts/rockchip/rk3528-hinlink-h28k.dts | 318 ++++++
+ .../boot/dts/rockchip/rk3568-9tripod-x3568-v4.dts | 60 +-
+ arch/arm64/boot/dts/rockchip/rk3576.dtsi | 28 +
+ arch/arm64/boot/dts/rockchip/rk3588-base.dtsi | 4 +-
+ arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi | 4 +-
+ .../rockchip/rk3588-friendlyelec-cm3588-nas.dts | 31 +
+ arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi | 14 +-
+ .../boot/dts/rockchip/rk3588-youyeetoo-yy3588.dts | 1190 ++++++++++++++++++++
+ .../boot/dts/rockchip/rk3588s-radxa-cm5-io.dts | 19 +
+ arch/arm64/boot/dts/rockchip/rk3588s-roc-pc.dts | 23 +-
+ drivers/clk/rockchip/clk-rk3588.c | 10 +-
+ 21 files changed, 1707 insertions(+), 41 deletions(-)
+ create mode 100644 arch/arm64/boot/dts/rockchip/rk3528-hinlink-h28k.dts
+ create mode 100644 arch/arm64/boot/dts/rockchip/rk3588-youyeetoo-yy3588.dts
+Merging samsung-krzk/for-next (cf776975e6d8a Merge branch 'next/drivers' into for-next)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux.git samsung-krzk/for-next
+Merge made by the 'ort' strategy.
+ .../bindings/soc/samsung/exynos-pmu.yaml | 27 ++++++++++++--
+ .../soc/samsung/samsung,exynos-sysreg.yaml | 1 +
+ arch/arm/boot/dts/samsung/exynos5250-manta.dts | 41 +++++++++++++++++++++-
+ arch/arm/mach-s3c/map-base.h | 2 +-
+ arch/arm64/boot/dts/exynos/exynosautov920.dtsi | 6 ++++
+ drivers/soc/samsung/exynos-pmu.c | 4 +--
+ include/linux/serial_s3c.h | 4 +--
+ 7 files changed, 76 insertions(+), 9 deletions(-)
+Merging scmi/for-linux-next (2edd29cc765fe Merge branches 'for-next/scmi/updates' and 'for-next/scmi/fixes', tag 'ffa-fixes-7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux)
+$ git merge -m Merge branch 'for-linux-next' of https://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux.git scmi/for-linux-next
+Auto-merging drivers/firmware/arm_ffa/driver.c
+Merge made by the 'ort' strategy.
+ drivers/firmware/arm_ffa/driver.c | 29 +++++++++++++++-------
+ drivers/firmware/arm_scmi/Kconfig | 4 ++--
+ drivers/firmware/arm_scmi/clock.c | 13 ++++++----
+ drivers/firmware/arm_scmi/notify.c | 49 ++++++++++++++++----------------------
+ 4 files changed, 51 insertions(+), 44 deletions(-)
+Merging sophgo/for-next (f7337210bede6 Merge branch 'dt/riscv' into for-next)
+$ git merge -m Merge branch 'for-next' of https://github.com/sophgo/linux.git sophgo/for-next
+Merge made by the 'ort' strategy.
+Merging sophgo-soc/soc-for-next (c8754c7deab4c soc: sophgo: cv1800: rtcsys: New driver (handling RTC only))
+$ git merge -m Merge branch 'soc-for-next' of https://github.com/sophgo/linux.git sophgo-soc/soc-for-next
+Already up to date.
+Merging spacemit/for-next (eb525edd48907 clk: spacemit: k3: set hdma clock as critical)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/spacemit/linux spacemit/for-next
+Already up to date.
+Merging stm32/stm32-next (fba4a31a7f3b6 arm64: dts: st: Fix SAI addresses on stm32mp251)
+$ git merge -m Merge branch 'stm32-next' of https://git.kernel.org/pub/scm/linux/kernel/git/atorgue/stm32.git stm32/stm32-next
+Already up to date.
+Merging sunxi/sunxi/for-next (36078904c9908 Merge branches 'sunxi/clk-for-7.3', 'sunxi/config-for-7.3' and 'sunxi/dt-for-7.3' into sunxi/for-next)
+$ git merge -m Merge branch 'sunxi/for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/sunxi/linux.git sunxi/sunxi/for-next
+Auto-merging Documentation/devicetree/bindings/vendor-prefixes.yaml
+Auto-merging arch/arm64/configs/defconfig
+Merge made by the 'ort' strategy.
+ Documentation/devicetree/bindings/arm/sunxi.yaml | 7 +
+ .../input/allwinner,sun4i-a10-lradc-keys.yaml | 1 +
+ .../bindings/rtc/allwinner,sun6i-a31-rtc.yaml | 13 ++
+ .../devicetree/bindings/vendor-prefixes.yaml | 2 +
+ arch/arm/boot/dts/allwinner/Makefile | 5 +
+ .../boot/dts/allwinner/sun8i-h3-nanopi-duo2.dts | 4 +-
+ .../allwinner/sun8i-t113s-netcube-dobermann.dts | 149 ++++++++++++++++
+ arch/arm64/boot/dts/allwinner/Makefile | 1 +
+ arch/arm64/boot/dts/allwinner/sun50i-a100.dtsi | 10 ++
+ .../allwinner/sun50i-a133-helperboard-core.dtsi | 197 +++++++++++++++++++++
+ .../boot/dts/allwinner/sun50i-a133-helperboard.dts | 148 ++++++++++++++++
+ arch/arm64/configs/defconfig | 1 +
+ arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi | 6 +
+ drivers/clk/sunxi-ng/ccu-sun6i-rtc.c | 38 ++--
+ drivers/clk/sunxi-ng/ccu_common.c | 12 +-
+ drivers/clk/sunxi-ng/ccu_common.h | 1 +
+ drivers/clk/sunxi-ng/ccu_mux.c | 1 -
+ include/dt-bindings/clock/sun6i-rtc.h | 4 +
+ 18 files changed, 564 insertions(+), 36 deletions(-)
+ create mode 100644 arch/arm/boot/dts/allwinner/sun8i-t113s-netcube-dobermann.dts
+ create mode 100644 arch/arm64/boot/dts/allwinner/sun50i-a133-helperboard-core.dtsi
+ create mode 100644 arch/arm64/boot/dts/allwinner/sun50i-a133-helperboard.dts
+Merging tee/next (a3067938fd192 Merge branches 'qcomtee_for_v7.3', 'optee_fix_for_v7.2' and 'jw-korg' into next)
+$ git merge -m Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/jenswi/linux-tee.git tee/next
+Auto-merging .mailmap
+Auto-merging MAINTAINERS
+Merge made by the 'ort' strategy.
+ .mailmap | 1 +
+ MAINTAINERS | 6 +++---
+ drivers/tee/optee/ffa_abi.c | 3 +++
+ drivers/tee/qcomtee/call.c | 7 ++++++-
+ 4 files changed, 13 insertions(+), 4 deletions(-)
+Merging tegra/for-next (75767942c9895 Merge branch for-7.2/arm64/dt into for-next)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux.git tegra/for-next
+Auto-merging drivers/gpu/drm/tegra/sor.c
+Auto-merging drivers/soc/tegra/fuse/tegra-apbmisc.c
+Merge made by the 'ort' strategy.
+ arch/arm64/boot/dts/nvidia/tegra234.dtsi | 24 ++++++++++++------------
+ arch/arm64/boot/dts/nvidia/tegra264.dtsi | 4 ++--
+ drivers/gpu/drm/tegra/sor.c | 6 ++----
+ drivers/soc/tegra/fuse/tegra-apbmisc.c | 2 +-
+ include/soc/tegra/pmc.h | 5 ++++-
+ 5 files changed, 21 insertions(+), 20 deletions(-)
+Merging tenstorrent-dt/tenstorrent-dt-for-next (33583baeb1ba7 dt-bindings: iommu: riscv: Add bindings for Tenstorrent RISC-V IOMMU)
+$ git merge -m Merge branch 'tenstorrent-dt-for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/tenstorrent/linux.git tenstorrent-dt/tenstorrent-dt-for-next
+Already up to date.
+Merging fustini-config/riscv-config-for-next (fd52109054693 riscv: defconfig: thead: enable PCA953X GPIO driver)
+$ git merge -m Merge branch 'riscv-config-for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/fustini/linux.git fustini-config/riscv-config-for-next
+Auto-merging arch/riscv/configs/defconfig
+Merge made by the 'ort' strategy.
+ arch/riscv/configs/defconfig | 2 ++
+ 1 file changed, 2 insertions(+)
+Merging thead-dt/thead-dt-for-next (3a5791956edbf riscv: dts: thead: Enable wifi on the BeagleV-Ahead)
+$ git merge -m Merge branch 'thead-dt-for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/fustini/linux.git thead-dt/thead-dt-for-next
+Already up to date.
+Merging ti/ti-next (1b98f483adfd9 Merge branches 'ti-drivers-soc-next' and 'ti-k3-maintainer-next' into ti-next)
+$ git merge -m Merge branch 'ti-next' of https://git.kernel.org/pub/scm/linux/kernel/git/ti/linux.git ti/ti-next
+Auto-merging MAINTAINERS
+Merge made by the 'ort' strategy.
+ MAINTAINERS | 1 +
+ drivers/firmware/ti_sci.c | 4 ++++
+ 2 files changed, 5 insertions(+)
+Merging xilinx/for-next (b881149621b23 arm64: dts: xilinx: zynqmp-sck: Correct indentation)
+$ git merge -m Merge branch 'for-next' of https://github.com/Xilinx/linux-xlnx.git xilinx/for-next
+Merge made by the 'ort' strategy.
+ arch/arm/boot/dts/xilinx/zynq-ebaz4205.dts | 1 -
+ arch/arm/boot/dts/xilinx/zynq-zc702.dts | 2 --
+ arch/arm/boot/dts/xilinx/zynq-zc706.dts | 2 --
+ .../boot/dts/xilinx/zynqmp-sck-kv-g-revA.dtso | 37 +++++++++++-----------
+ .../boot/dts/xilinx/zynqmp-sck-kv-g-revB.dtso | 1 -
+ .../boot/dts/xilinx/zynqmp-zc1751-xm015-dc1.dts | 4 ---
+ .../boot/dts/xilinx/zynqmp-zc1751-xm019-dc5.dts | 2 --
+ arch/arm64/boot/dts/xilinx/zynqmp-zcu100-revC.dts | 1 -
+ arch/arm64/boot/dts/xilinx/zynqmp-zcu102-revA.dts | 2 --
+ arch/arm64/boot/dts/xilinx/zynqmp-zcu104-revA.dts | 1 -
+ arch/arm64/boot/dts/xilinx/zynqmp-zcu104-revC.dts | 1 -
+ arch/arm64/boot/dts/xilinx/zynqmp-zcu106-revA.dts | 2 --
+ arch/arm64/boot/dts/xilinx/zynqmp-zcu111-revA.dts | 1 -
+ 13 files changed, 18 insertions(+), 39 deletions(-)
+Merging socfpga/for-next (39ea7cb401924 ARM: dts: intel: arria10: Correct indentation)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/dinguyen/linux.git socfpga/for-next
+Merge made by the 'ort' strategy.
+ Documentation/devicetree/bindings/arm/altera.yaml | 6 +
+ .../bindings/net/altr,socfpga-stmmac.yaml | 46 +++++-
+ .../boot/dts/intel/socfpga/socfpga_arria10.dtsi | 2 +-
+ arch/arm64/boot/dts/intel/Makefile | 1 +
+ arch/arm64/boot/dts/intel/keembay-soc.dtsi | 2 +-
+ arch/arm64/boot/dts/intel/socfpga_agilex5.dtsi | 112 ++++++++++++++-
+ arch/arm64/boot/dts/intel/socfpga_agilex72.dtsi | 156 +++++++++++++++++++++
+ .../boot/dts/intel/socfpga_agilex72_socdk.dts | 27 ++++
+ 8 files changed, 342 insertions(+), 10 deletions(-)
+ create mode 100644 arch/arm64/boot/dts/intel/socfpga_agilex72.dtsi
+ create mode 100644 arch/arm64/boot/dts/intel/socfpga_agilex72_socdk.dts
+Merging clk/clk-next (8cdeaa50eae8d Linux 7.2-rc2)
+$ git merge -m Merge branch 'clk-next' of https://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git clk/clk-next
+Already up to date.
+Merging clk-imx/for-next (b3dcc8c608fbb clk: imx: Add audio PLL debugfs for K-divider control)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/abelvesa/linux.git clk-imx/for-next
+Merge made by the 'ort' strategy.
+ drivers/clk/imx/clk-imx8mm.c | 6 +++
+ drivers/clk/imx/clk-pll14xx.c | 119 +++++++++++++++++++++++++++++++++++++++++-
+ drivers/clk/imx/clk.h | 1 +
+ 3 files changed, 125 insertions(+), 1 deletion(-)
+Merging clk-renesas/renesas-clk (91fb464395437 dt-bindings: clock: renesas,versaclock7: Update maintainer)
+$ git merge -m Merge branch 'renesas-clk' of https://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers.git clk-renesas/renesas-clk
+Auto-merging MAINTAINERS
+Auto-merging drivers/clk/renesas/renesas-cpg-mssr.c
+Auto-merging drivers/clk/renesas/rzv2h-cpg.c
+Merge made by the 'ort' strategy.
+ .../bindings/clock/renesas,rzv2h-cpg.yaml | 6 +
+ .../bindings/clock/renesas,versaclock7.yaml | 2 +-
+ MAINTAINERS | 6 +-
+ drivers/clk/renesas/Kconfig | 6 +
+ drivers/clk/renesas/Makefile | 1 +
+ drivers/clk/renesas/r9a08g046-cpg.c | 130 +++++++
+ drivers/clk/renesas/r9a09g047-cpg.c | 123 ++++++-
+ drivers/clk/renesas/r9a09g077-cpg.c | 375 ++++++++++++++++++++-
+ drivers/clk/renesas/renesas-cpg-mssr.c | 20 +-
+ drivers/clk/renesas/rzv2h-cpg-lib.c | 217 ++++++++++++
+ drivers/clk/renesas/rzv2h-cpg.c | 203 -----------
+ .../dt-bindings/clock/renesas,r9a09g077-cpg-mssr.h | 2 +
+ .../dt-bindings/clock/renesas,r9a09g087-cpg-mssr.h | 2 +
+ include/linux/clk/renesas.h | 34 +-
+ 14 files changed, 904 insertions(+), 223 deletions(-)
+ create mode 100644 drivers/clk/renesas/rzv2h-cpg-lib.c
+Merging thead-clk/thead-clk-for-next (baf4fc7c03bd0 clk: thead: th1520-ap: Support CPU frequency scaling)
+$ git merge -m Merge branch 'thead-clk-for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/fustini/linux.git thead-clk/thead-clk-for-next
+Already up to date.
+Merging tenstorrent-clk/tenstorrent-clk-for-next (23c8ebc952849 clk: tenstorrent: Add Atlantis clock controller driver)
+$ git merge -m Merge branch 'tenstorrent-clk-for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/tenstorrent/linux.git tenstorrent-clk/tenstorrent-clk-for-next
+Already up to date.
+Merging csky/linux-next (abb81e5ce7d99 csky: Fix a4/a5 restoration in syscall trace path)
+$ git merge -m Merge branch 'linux-next' of https://github.com/c-sky/csky-linux.git csky/linux-next
+Merge made by the 'ort' strategy.
+ arch/csky/kernel/entry.S | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+Merging loongarch/loongarch-next (262a3b4fa1792 selftests/bpf: Test jited inline of bpf_get_smp_processor_id() for LoongArch)
+$ git merge -m Merge branch 'loongarch-next' of https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson.git loongarch/loongarch-next
+Already up to date.
+Merging m68k/for-next (dc5200f6b1ada m68k: Correct CONFIG_MVME16x macro name in #endif comment)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/geert/linux-m68k.git m68k/for-next
+Already up to date.
+Merging m68knommu/for-next (1b57914105506 m68k: defconfig: add config for M5282EVB board)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/gerg/m68knommu.git m68knommu/for-next
+Merge made by the 'ort' strategy.
+ arch/m68k/coldfire/m523x.c | 2 +-
+ arch/m68k/coldfire/m528x.c | 6 ++---
+ arch/m68k/configs/m5235evb_defconfig | 52 ++++++++++++++++++++++++++++++++++++
+ arch/m68k/configs/m5282evb_defconfig | 51 +++++++++++++++++++++++++++++++++++
+ 4 files changed, 107 insertions(+), 4 deletions(-)
+ create mode 100644 arch/m68k/configs/m5235evb_defconfig
+ create mode 100644 arch/m68k/configs/m5282evb_defconfig
+Merging microblaze/next (6de23f81a5e08 Linux 7.0-rc1)
+$ git merge -m Merge branch 'next' of git://git.monstr.eu/linux-2.6-microblaze.git microblaze/next
+Already up to date.
+Merging mips/mips-next (8cdeaa50eae8d Linux 7.2-rc2)
+$ git merge -m Merge branch 'mips-next' of https://git.kernel.org/pub/scm/linux/kernel/git/mips/linux.git mips/mips-next
+Already up to date.
+Merging openrisc/for-next (aca063c902452 openrisc: Fix jump_label smp syncing)
+$ git merge -m Merge branch 'for-next' of https://github.com/openrisc/linux.git openrisc/for-next
+Already up to date.
+Merging parisc-hd/for-next (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux.git parisc-hd/for-next
+Already up to date.
+Merging powerpc/next (8cdeaa50eae8d Linux 7.2-rc2)
+$ git merge -m Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git powerpc/next
+Already up to date.
+Merging risc-v/for-next (a2ac823d8a228 selftests/rseq: Fix a building error for riscv arch)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux.git risc-v/for-next
+Already up to date.
+Merging riscv-dt/riscv-dt-for-next (82ab962ef6c2a Merge branch 'k230-basic' into riscv-dt-for-next)
+$ git merge -m Merge branch 'riscv-dt-for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux.git riscv-dt/riscv-dt-for-next
+Auto-merging Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml
+Auto-merging Documentation/devicetree/bindings/timer/sifive,clint.yaml
+Merge made by the 'ort' strategy.
+ .../interrupt-controller/sifive,plic-1.0.0.yaml | 1 +
+ .../devicetree/bindings/riscv/canaan.yaml | 8 +-
+ .../devicetree/bindings/timer/sifive,clint.yaml | 1 +
+ arch/riscv/boot/dts/canaan/Makefile | 2 +
+ arch/riscv/boot/dts/canaan/k230-canmv.dts | 343 +++++++++++++++++++++
+ arch/riscv/boot/dts/canaan/k230-evb.dts | 39 +++
+ arch/riscv/boot/dts/canaan/k230-pinctrl.h | 18 ++
+ arch/riscv/boot/dts/canaan/k230.dtsi | 167 ++++++++++
+ 8 files changed, 578 insertions(+), 1 deletion(-)
+ create mode 100644 arch/riscv/boot/dts/canaan/k230-canmv.dts
+ create mode 100644 arch/riscv/boot/dts/canaan/k230-evb.dts
+ create mode 100644 arch/riscv/boot/dts/canaan/k230-pinctrl.h
+ create mode 100644 arch/riscv/boot/dts/canaan/k230.dtsi
+Merging riscv-soc/riscv-soc-for-next (dfceff38cea2b Merge branches 'riscv-soc-drivers-for-next' and 'cache-for-next' into riscv-soc-for-next)
+$ git merge -m Merge branch 'riscv-soc-for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux.git riscv-soc/riscv-soc-for-next
+Merge made by the 'ort' strategy.
+Merging s390/for-next (d87e492ce6f44 Merge branch 'features' into for-next)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/s390/linux.git s390/for-next
+Auto-merging MAINTAINERS
+Auto-merging arch/s390/Kconfig
+Auto-merging arch/s390/include/asm/hugetlb.h
+Merge made by the 'ort' strategy.
+ MAINTAINERS | 8 +++
+ arch/s390/Kconfig | 5 ++
+ arch/s390/configs/debug_defconfig | 2 +
+ arch/s390/configs/defconfig | 2 +
+ arch/s390/include/asm/hugetlb.h | 4 +-
+ arch/s390/include/asm/processor.h | 4 --
+ arch/s390/include/asm/thread_info.h | 1 +
+ arch/s390/kernel/idle.c | 1 -
+ arch/s390/kernel/irq.c | 4 --
+ arch/s390/kernel/smp.c | 1 -
+ arch/s390/kernel/traps.c | 41 ++++++++++++-
+ arch/s390/mm/hugetlbpage.c | 10 ++--
+ drivers/cpuidle/Kconfig | 5 ++
+ drivers/cpuidle/Kconfig.s390 | 11 ++++
+ drivers/cpuidle/Makefile | 4 ++
+ drivers/cpuidle/cpuidle-s390.c | 115 ++++++++++++++++++++++++++++++++++++
+ include/linux/tick.h | 3 -
+ kernel/time/tick-sched.c | 7 +--
+ 18 files changed, 204 insertions(+), 24 deletions(-)
+ create mode 100644 drivers/cpuidle/Kconfig.s390
+ create mode 100644 drivers/cpuidle/cpuidle-s390.c
+Merging sh/for-next (b0aa5e4b087b6 sh: Fix fallout from ZERO_PAGE consolidation)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/glaubitz/sh-linux.git sh/for-next
+Already up to date.
+Merging sparc/for-next (5b2a3b1a98fb4 sparc: Remove remaining defconfig references to the pktcdvd driver)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/alarsson/linux-sparc.git sparc/for-next
+Already up to date.
+Merging uml/next (254f49634ee16 Linux 7.1-rc1)
+$ git merge -m Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/uml/linux.git uml/next
+Already up to date.
+Merging xtensa/xtensa-for-next (a7c958e8721eb xtensa: correct CONFIG_XTENSA_CALIBRATE_CCOUNT macro name in comment)
+$ git merge -m Merge branch 'xtensa-for-next' of https://github.com/jcmvbkbc/linux-xtensa.git xtensa/xtensa-for-next
+Merge made by the 'ort' strategy.
+ arch/xtensa/include/asm/platform.h | 2 +-
+ arch/xtensa/platforms/iss/console.c | 5 +++--
+ 2 files changed, 4 insertions(+), 3 deletions(-)
+Merging fs-next (6565eb0f84455 Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs.git)
+$ git merge -m Merge branch 'fs-next' of linux-next fs-next
+Auto-merging MAINTAINERS
+Auto-merging fs/ocfs2/namei.c
+Auto-merging include/linux/sched.h
+Auto-merging kernel/exit.c
+Auto-merging kernel/fork.c
+Auto-merging mm/shmem.c
+Merge made by the 'ort' strategy.
+ Documentation/filesystems/locking.rst | 2 +-
+ Documentation/filesystems/overlayfs.rst | 16 +
+ Documentation/filesystems/porting.rst | 10 +-
+ Documentation/filesystems/vfs.rst | 2 +-
+ MAINTAINERS | 6 +-
+ block/bdev.c | 125 +++-
+ drivers/base/devtmpfs.c | 2 +-
+ drivers/block/rnbd/rnbd-srv.c | 4 +-
+ drivers/char/misc_minor_kunit.c | 25 +-
+ drivers/crypto/ccp/sev-dev.c | 12 +-
+ drivers/mtd/ubi/ubi.h | 9 +-
+ drivers/target/target_core_alua.c | 11 +-
+ drivers/target/target_core_pr.c | 4 +-
+ fs/9p/vfs_inode.c | 5 +-
+ fs/9p/vfs_inode_dotl.c | 4 +-
+ fs/Kconfig | 1 -
+ fs/Makefile | 1 -
+ fs/affs/affs.h | 2 +-
+ fs/affs/namei.c | 4 +-
+ fs/afs/dir.c | 6 +-
+ fs/autofs/root.c | 2 +-
+ fs/bad_inode.c | 2 +-
+ fs/bfs/dir.c | 2 +-
+ fs/bpf_fs_kfuncs.c | 37 ++
+ fs/btrfs/dev-replace.c | 65 +-
+ fs/btrfs/inode.c | 4 +-
+ fs/btrfs/ioctl.c | 4 +-
+ fs/btrfs/volumes.c | 116 +++-
+ fs/btrfs/volumes.h | 6 +-
+ fs/ceph/dir.c | 3 +-
+ fs/coda/dir.c | 9 +-
+ fs/coredump.c | 11 +-
+ fs/cramfs/inode.c | 2 +-
+ fs/crypto/crypto.c | 40 +-
+ fs/crypto/fscrypt_private.h | 5 +-
+ fs/crypto/keyring.c | 21 +-
+ fs/crypto/keysetup.c | 26 +-
+ fs/crypto/policy.c | 17 +-
+ fs/ecryptfs/inode.c | 2 +-
+ fs/efivarfs/inode.c | 2 +-
+ fs/efs/Kconfig | 16 -
+ fs/efs/Makefile | 8 -
+ fs/efs/dir.c | 105 ----
+ fs/efs/efs.h | 144 -----
+ fs/efs/file.c | 42 --
+ fs/efs/inode.c | 315 ----------
+ fs/efs/namei.c | 120 ----
+ fs/efs/super.c | 368 -----------
+ fs/efs/symlink.c | 50 --
+ fs/erofs/super.c | 35 +-
+ fs/exfat/exfat_fs.h | 2 +-
+ fs/exfat/file.c | 219 +++++--
+ fs/exfat/iomap.c | 22 +-
+ fs/exfat/namei.c | 2 +-
+ fs/ext2/namei.c | 4 +-
+ fs/ext4/extents-test.c | 9 +-
+ fs/ext4/mballoc-test.c | 9 +-
+ fs/ext4/namei.c | 4 +-
+ fs/ext4/super.c | 12 +-
+ fs/f2fs/namei.c | 4 +-
+ fs/f2fs/super.c | 6 +-
+ fs/fat/namei_msdos.c | 5 +-
+ fs/fat/namei_vfat.c | 2 +-
+ fs/fs_struct.c | 103 ++-
+ fs/fuse/dir.c | 10 +-
+ fs/gfs2/inode.c | 7 +-
+ fs/hfs/dir.c | 4 +-
+ fs/hfsplus/dir.c | 4 +-
+ fs/hostfs/hostfs_kern.c | 2 +-
+ fs/hpfs/namei.c | 6 +-
+ fs/hugetlbfs/inode.c | 4 +-
+ fs/inode.c | 23 +-
+ fs/internal.h | 1 +
+ fs/iomap/buffered-io.c | 6 +-
+ fs/iomap/direct-io.c | 293 ++++++++-
+ fs/iomap/ioend.c | 21 +-
+ fs/jffs2/dir.c | 6 +-
+ fs/jfs/namei.c | 4 +-
+ fs/kernel_read_file.c | 9 +-
+ fs/lockd/svc.c | 4 +-
+ fs/lockd/svc4proc.c | 4 +-
+ fs/lockd/svclock.c | 42 +-
+ fs/lockd/svcproc.c | 4 +-
+ fs/lockd/svcsubs.c | 105 +++-
+ fs/minix/namei.c | 4 +-
+ fs/namei.c | 30 +-
+ fs/namespace.c | 25 +-
+ fs/nfs/blocklayout/dev.c | 15 +-
+ fs/nfs/callback.c | 4 +-
+ fs/nfs/dir.c | 8 +-
+ fs/nfs/internal.h | 14 +-
+ fs/nfs/pnfs_nfs.c | 2 +-
+ fs/nfs/write.c | 14 +-
+ fs/nfs_common/nfslocalio.c | 16 +-
+ fs/nfsd/filecache.c | 143 +++--
+ fs/nfsd/flexfilelayoutxdr.c | 20 +-
+ fs/nfsd/localio.c | 8 +-
+ fs/nfsd/lockd.c | 6 +-
+ fs/nfsd/netns.h | 29 +-
+ fs/nfsd/nfs2acl.c | 21 +-
+ fs/nfsd/nfs3acl.c | 17 +-
+ fs/nfsd/nfs4callback.c | 113 +++-
+ fs/nfsd/nfs4layouts.c | 39 +-
+ fs/nfsd/nfs4proc.c | 84 ++-
+ fs/nfsd/nfs4recover.c | 48 +-
+ fs/nfsd/nfs4state.c | 330 +++++++---
+ fs/nfsd/nfs4xdr.c | 27 +-
+ fs/nfsd/nfscache.c | 4 +-
+ fs/nfsd/nfsctl.c | 79 ++-
+ fs/nfsd/nfsfh.c | 12 +-
+ fs/nfsd/nfsproc.c | 7 +
+ fs/nfsd/nfssvc.c | 61 +-
+ fs/nfsd/state.h | 4 +-
+ fs/nfsd/trace.h | 18 +-
+ fs/nfsd/vfs.c | 48 +-
+ fs/nilfs2/namei.c | 4 +-
+ fs/notify/fanotify/fanotify.c | 1 +
+ fs/ntfs/aops.c | 17 +-
+ fs/ntfs/attrib.c | 36 +-
+ fs/ntfs/attrlist.c | 9 +
+ fs/ntfs/dir.c | 20 +-
+ fs/ntfs/index.c | 5 +-
+ fs/ntfs/inode.c | 9 +
+ fs/ntfs/mft.c | 11 +-
+ fs/ntfs/namei.c | 66 +-
+ fs/ntfs/reparse.c | 6 +-
+ fs/ntfs3/namei.c | 4 +-
+ fs/nullfs.c | 14 +-
+ fs/ocfs2/dlmfs/dlmfs.c | 5 +-
+ fs/ocfs2/namei.c | 5 +-
+ fs/ocfs2/super.c | 1 -
+ fs/omfs/dir.c | 4 +-
+ fs/orangefs/namei.c | 5 +-
+ fs/overlayfs/dir.c | 18 +-
+ fs/overlayfs/inode.c | 26 +-
+ fs/overlayfs/overlayfs.h | 1 +
+ fs/overlayfs/super.c | 2 +-
+ fs/overlayfs/xattrs.c | 1 +
+ fs/posix_acl.c | 2 -
+ fs/proc/array.c | 4 +-
+ fs/proc/base.c | 8 +-
+ fs/proc_namespace.c | 4 +-
+ fs/ramfs/inode.c | 4 +-
+ fs/romfs/super.c | 10 +-
+ fs/smb/client/cifs_fs_sb.h | 1 +
+ fs/smb/client/cifsacl.c | 2 +-
+ fs/smb/client/cifsfs.c | 12 +
+ fs/smb/client/cifsfs.h | 2 +-
+ fs/smb/client/cifsglob.h | 1 +
+ fs/smb/client/cifsproto.h | 2 +-
+ fs/smb/client/cifssmb.c | 36 --
+ fs/smb/client/connect.c | 3 +-
+ fs/smb/client/dfs_cache.c | 12 +-
+ fs/smb/client/dir.c | 2 +-
+ fs/smb/client/file.c | 7 +-
+ fs/smb/client/inode.c | 20 +-
+ fs/smb/client/link.c | 17 +-
+ fs/smb/client/misc.c | 14 +-
+ fs/smb/client/readdir.c | 4 +-
+ fs/smb/client/reparse.c | 17 +-
+ fs/smb/client/smb1ops.c | 28 +-
+ fs/smb/client/smb2file.c | 19 +-
+ fs/smb/client/smb2misc.c | 32 +-
+ fs/smb/client/smb2ops.c | 19 +-
+ fs/smb/client/smb2pdu.c | 26 +-
+ fs/smb/client/smb2proto.h | 2 +-
+ fs/smb/server/compress.c | 3 +-
+ fs/smb/server/connection.c | 16 +-
+ fs/smb/server/ksmbd_netlink.h | 1 +
+ fs/smb/server/mgmt/share_config.c | 4 +-
+ fs/smb/server/smb2pdu.c | 178 +++++-
+ fs/smb/server/smbacl.c | 147 +++--
+ fs/smb/server/smbacl.h | 3 +-
+ fs/smb/server/vfs.c | 17 +-
+ fs/super.c | 639 +++++++++++++------
+ fs/ubifs/dir.c | 4 +-
+ fs/udf/balloc.c | 12 +-
+ fs/udf/inode.c | 26 +-
+ fs/udf/namei.c | 4 +-
+ fs/udf/partition.c | 2 +-
+ fs/udf/super.c | 23 +-
+ fs/udf/truncate.c | 2 +-
+ fs/udf/udfdecl.h | 3 +-
+ fs/ufs/namei.c | 5 +-
+ fs/vboxsf/dir.c | 4 +-
+ fs/xfs/xfs_buf.c | 2 +-
+ fs/xfs/xfs_iops.c | 7 +-
+ fs/xfs/xfs_log_cil.c | 2 +-
+ fs/xfs/xfs_log_recover.c | 26 +-
+ fs/xfs/xfs_super.c | 10 +-
+ fs/xfs/xfs_sysfs.c | 28 +-
+ fs/xfs/xfs_sysfs.h | 2 +
+ fs/xfs/xfs_zone_alloc.c | 8 +
+ include/linux/blk_types.h | 2 +-
+ include/linux/blkdev.h | 12 +-
+ include/linux/efs_vh.h | 54 --
+ include/linux/fs.h | 4 +-
+ include/linux/fs/super.h | 8 +
+ include/linux/fs/super_types.h | 4 +-
+ include/linux/fs_struct.h | 34 +
+ include/linux/init_task.h | 1 +
+ include/linux/lockd/bind.h | 12 +-
+ include/linux/net.h | 1 +
+ include/linux/sched.h | 1 +
+ include/linux/sched/task.h | 1 +
+ include/linux/sunrpc/bc_xprt.h | 5 +
+ include/linux/sunrpc/clnt.h | 1 +
+ include/linux/sunrpc/svc.h | 1 +
+ include/linux/sunrpc/svc_rdma_pcl.h | 4 +-
+ include/linux/types.h | 2 +
+ include/uapi/asm-generic/errno.h | 2 +-
+ include/uapi/linux/efs_fs_sb.h | 63 --
+ include/uapi/linux/fscrypt.h | 1 -
+ init/init_task.c | 1 +
+ init/initramfs.c | 14 +-
+ init/initramfs_test.c | 220 ++++---
+ init/main.c | 10 +-
+ ipc/mqueue.c | 7 +-
+ kernel/exit.c | 2 +-
+ kernel/fork.c | 53 +-
+ kernel/kcmp.c | 2 +-
+ kernel/umh.c | 6 +-
+ mm/shmem.c | 2 +-
+ net/socket.c | 25 +
+ net/sunrpc/auth_gss/auth_gss.c | 6 +-
+ net/sunrpc/auth_gss/gss_krb5_unseal.c | 3 +
+ net/sunrpc/auth_gss/gss_krb5_wrap.c | 13 +-
+ net/sunrpc/auth_gss/gss_rpc_upcall.c | 6 -
+ net/sunrpc/auth_gss/gss_rpc_upcall.h | 1 -
+ net/sunrpc/auth_gss/gss_rpc_xdr.c | 15 +-
+ net/sunrpc/auth_gss/svcauth_gss.c | 8 +-
+ net/sunrpc/backchannel_rqst.c | 38 +-
+ net/sunrpc/cache.c | 7 +-
+ net/sunrpc/clnt.c | 19 +-
+ net/sunrpc/sunrpc_syms.c | 1 +
+ net/sunrpc/svc.c | 81 ++-
+ net/sunrpc/svcauth_unix.c | 4 +-
+ net/sunrpc/xdr.c | 2 +-
+ net/sunrpc/xprtrdma/ib_client.c | 42 +-
+ net/sunrpc/xprtrdma/svc_rdma_pcl.c | 63 +-
+ net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | 24 +-
+ net/sunrpc/xprtrdma/svc_rdma_rw.c | 52 +-
+ net/sunrpc/xprtrdma/svc_rdma_transport.c | 69 +-
+ net/sunrpc/xprtsock.c | 16 +-
+ net/unix/af_unix.c | 17 +-
+ tools/include/uapi/linux/fscrypt.h | 1 -
+ tools/testing/selftests/Makefile | 1 +
+ tools/testing/selftests/bpf/bpf_experimental.h | 3 +
+ .../testing/selftests/bpf/prog_tests/sock_xattr.c | 67 ++
+ .../testing/selftests/bpf/progs/sock_read_xattr.c | 54 ++
+ tools/testing/selftests/filesystems/.gitignore | 1 +
+ tools/testing/selftests/filesystems/Makefile | 2 +-
+ tools/testing/selftests/filesystems/ceph/Makefile | 7 +
+ tools/testing/selftests/filesystems/ceph/README | 84 +++
+ .../filesystems/ceph/reset_corner_cases.sh | 646 +++++++++++++++++++
+ .../selftests/filesystems/ceph/reset_stress.sh | 694 +++++++++++++++++++++
+ .../selftests/filesystems/ceph/run_validation.sh | 350 +++++++++++
+ tools/testing/selftests/filesystems/ceph/settings | 1 +
+ .../filesystems/ceph/validate_consistency.py | 297 +++++++++
+ .../selftests/filesystems/overlayfs/.gitignore | 1 +
+ .../selftests/filesystems/overlayfs/Makefile | 2 +
+ .../filesystems/overlayfs/idmapped_mounts.c | 501 +++++++++++++++
+ .../filesystems/overlayfs/set_layers_via_fds.c | 16 +-
+ .../filesystems/statmount/statmount_test.c | 5 +-
+ tools/testing/selftests/filesystems/ustat_test.c | 135 ++++
+ tools/testing/selftests/proc/proc-pidns.c | 1 +
+ 266 files changed, 6790 insertions(+), 2921 deletions(-)
+ delete mode 100644 fs/efs/Kconfig
+ delete mode 100644 fs/efs/Makefile
+ delete mode 100644 fs/efs/dir.c
+ delete mode 100644 fs/efs/efs.h
+ delete mode 100644 fs/efs/file.c
+ delete mode 100644 fs/efs/inode.c
+ delete mode 100644 fs/efs/namei.c
+ delete mode 100644 fs/efs/super.c
+ delete mode 100644 fs/efs/symlink.c
+ delete mode 100644 include/linux/efs_vh.h
+ delete mode 100644 include/uapi/linux/efs_fs_sb.h
+ create mode 100644 tools/testing/selftests/bpf/prog_tests/sock_xattr.c
+ create mode 100644 tools/testing/selftests/bpf/progs/sock_read_xattr.c
+ create mode 100644 tools/testing/selftests/filesystems/ceph/Makefile
+ create mode 100644 tools/testing/selftests/filesystems/ceph/README
+ create mode 100755 tools/testing/selftests/filesystems/ceph/reset_corner_cases.sh
+ create mode 100755 tools/testing/selftests/filesystems/ceph/reset_stress.sh
+ create mode 100755 tools/testing/selftests/filesystems/ceph/run_validation.sh
+ create mode 100644 tools/testing/selftests/filesystems/ceph/settings
+ create mode 100755 tools/testing/selftests/filesystems/ceph/validate_consistency.py
+ create mode 100644 tools/testing/selftests/filesystems/overlayfs/idmapped_mounts.c
+ create mode 100644 tools/testing/selftests/filesystems/ustat_test.c
+Merging printk/for-next (04a68c4b40960 Merge branch 'for-7.3-trivial' into for-next)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/printk/linux.git printk/for-next
+Merge made by the 'ort' strategy.
+ kernel/printk/printk.c | 11 +++++++++--
+ lib/tests/test_ratelimit.c | 29 +++++++++++++++++++----------
+ lib/vsprintf.c | 4 ++++
+ 3 files changed, 32 insertions(+), 12 deletions(-)
+Merging pci/next (5d9f1dd3b3e7b Merge branch 'pci/controller/rzg3s-host')
+$ git merge -m Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git pci/next
+Auto-merging MAINTAINERS
+Auto-merging drivers/pci/controller/dwc/pci-meson.c
+Merge made by the 'ort' strategy.
+ .../devicetree/bindings/pci/fsl,imx6q-pcie.yaml | 25 +++
+ .../devicetree/bindings/pci/qcom,hawi-pcie.yaml | 201 ++++++++++++++++++
+ .../devicetree/bindings/pci/qcom,pcie-ipq9574.yaml | 15 ++
+ .../bindings/pci/renesas,r9a08g045-pcie.yaml | 34 ++-
+ MAINTAINERS | 1 +
+ arch/powerpc/kernel/pci-common.c | 9 +-
+ drivers/pci/controller/cadence/pcie-cadence-plat.c | 1 +
+ drivers/pci/controller/dwc/Kconfig | 2 +
+ drivers/pci/controller/dwc/pci-imx6.c | 25 ++-
+ drivers/pci/controller/dwc/pci-meson.c | 2 +-
+ drivers/pci/controller/dwc/pcie-qcom.c | 38 ++++
+ drivers/pci/controller/pci-host-common.c | 29 +--
+ drivers/pci/controller/pcie-rzg3s-host.c | 233 +++++++++++++++++++--
+ drivers/pci/pci-sysfs.c | 38 +++-
+ 14 files changed, 589 insertions(+), 64 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/pci/qcom,hawi-pcie.yaml
+Merging pstore/for-next/pstore (24b8f8dcb9a13 pstore/ftrace: Factor KASLR offset in the core kernel instruction addresses)
+$ git merge -m Merge branch 'for-next/pstore' of https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git pstore/for-next/pstore
+Already up to date.
+Merging hid/for-next (194a485768438 Merge branch 'for-7.2/upstream-fixes' into for-next)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git hid/for-next
+Merge made by the 'ort' strategy.
+ drivers/hid/Kconfig | 9 ++
+ drivers/hid/hid-core.c | 7 +
+ drivers/hid/hid-ids.h | 2 +
+ drivers/hid/hid-nintendo.c | 1 -
+ drivers/hid/hid-roccat-kone.c | 65 ++++++++-
+ drivers/hid/hid-sony.c | 245 +++++++++++++++++----------------
+ drivers/hid/hid-steelseries.c | 313 ++++++++++++++++++++++++++++++++++++++++--
+ drivers/hid/wacom_wac.c | 8 +-
+ 8 files changed, 516 insertions(+), 134 deletions(-)
+Merging i2c/i2c/for-next (8cd9520d35a6c Linux 7.1)
+$ git merge -m Merge branch 'i2c/for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git i2c/i2c/for-next
+Already up to date.
+$ git am -3 ../patches/0001-i2c-Fix-up-the-rest-of-the-merge.patch
+Applying: i2c: Fix up the rest of the merge
+Using index info to reconstruct a base tree...
+M drivers/i2c/i2c-core-base.c
+Falling back to patching base and 3-way merge...
+Auto-merging drivers/i2c/i2c-core-base.c
+No changes -- Patch already applied.
+Merging i2c-andi/i2c/i2c-next (04e9bf1648f84 i2c: nomadik: Use generic definitions for bus frequencies)
+$ git merge -m Merge branch 'i2c/i2c-next' of https://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux.git i2c-andi/i2c/i2c-next
+Auto-merging drivers/i2c/busses/i2c-amd-asf-plat.c
+Merge made by the 'ort' strategy.
+ .../bindings/i2c/altr,softip-i2c-v1.0.yaml | 62 ++++
+ .../devicetree/bindings/i2c/i2c-altera.txt | 39 ---
+ .../devicetree/bindings/i2c/i2c-axxia.txt | 30 --
+ .../devicetree/bindings/i2c/lsi,api2c.yaml | 52 ++++
+ .../bindings/i2c/qcom,sa8255p-geni-i2c.yaml | 64 ++++
+ drivers/i2c/busses/Kconfig | 2 +-
+ drivers/i2c/busses/i2c-amd-asf-plat.c | 4 +
+ drivers/i2c/busses/i2c-davinci.c | 4 +-
+ drivers/i2c/busses/i2c-k1.c | 183 +++++++++++-
+ drivers/i2c/busses/i2c-microchip-corei2c.c | 4 +-
+ drivers/i2c/busses/i2c-nomadik.c | 4 +-
+ drivers/i2c/busses/i2c-octeon-core.h | 2 +-
+ drivers/i2c/busses/i2c-pnx.c | 3 +-
+ drivers/i2c/busses/i2c-qcom-geni.c | 328 ++++++++++-----------
+ drivers/i2c/i2c-core-acpi.c | 6 +-
+ 15 files changed, 522 insertions(+), 265 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/i2c/altr,softip-i2c-v1.0.yaml
+ delete mode 100644 Documentation/devicetree/bindings/i2c/i2c-altera.txt
+ delete mode 100644 Documentation/devicetree/bindings/i2c/i2c-axxia.txt
+ create mode 100644 Documentation/devicetree/bindings/i2c/lsi,api2c.yaml
+ create mode 100644 Documentation/devicetree/bindings/i2c/qcom,sa8255p-geni-i2c.yaml
+Merging i2c-rust/rust-i2c-next (c0260c740d207 i2c: rust: mark I2cAdapter methods as inline)
+$ git merge -m Merge branch 'rust-i2c-next' of https://github.com/ikrtn/rust-for-linux i2c-rust/rust-i2c-next
+Auto-merging rust/kernel/i2c.rs
+Merge made by the 'ort' strategy.
+ rust/kernel/i2c.rs | 3 +++
+ 1 file changed, 3 insertions(+)
+Merging i3c/i3c/next (eeedacd0866ee i3c: dw: avoid shift-out-of-bounds when DAA assigns no devices)
+$ git merge -m Merge branch 'i3c/next' of https://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux.git i3c/i3c/next
+Merge made by the 'ort' strategy.
+ drivers/i3c/master/adi-i3c-master.c | 15 +++++++--------
+ drivers/i3c/master/dw-i3c-master.c | 10 +++++++++-
+ drivers/i3c/master/svc-i3c-master.c | 18 +++++++++++++++---
+ 3 files changed, 31 insertions(+), 12 deletions(-)
+Merging dmi/dmi-for-next (1afafbaf749d8 firmware/dmi: Include product_family info to modalias)
+$ git merge -m Merge branch 'dmi-for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging.git dmi/dmi-for-next
+Already up to date.
+Merging hwmon-staging/hwmon-next (a810e1aa11bf6 hwmon: (cros_ec) Implement custom kelvin to celsius conversions)
+$ git merge -m Merge branch 'hwmon-next' of https://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git hwmon-staging/hwmon-next
+Auto-merging MAINTAINERS
+Auto-merging drivers/hwmon/cros_ec_hwmon.c
+Merge made by the 'ort' strategy.
+ .../devicetree/bindings/hwmon/adi,adm1275.yaml | 43 ++-
+ .../bindings/hwmon/amphenol,chipcap2.yaml | 6 +
+ .../bindings/hwmon/pmbus/silergy,sq24860.yaml | 74 ++++
+ .../bindings/hwmon/pmbus/ti,lm25066.yaml | 20 +
+ .../devicetree/bindings/hwmon/ti,ina2xx.yaml | 3 +
+ Documentation/hwmon/adm1275.rst | 24 ++
+ Documentation/hwmon/chipcap2.rst | 2 +
+ Documentation/hwmon/coretemp.rst | 4 +-
+ Documentation/hwmon/index.rst | 2 +
+ Documentation/hwmon/sq24860.rst | 96 +++++
+ Documentation/hwmon/tvs-mpfs.rst | 53 +++
+ MAINTAINERS | 1 +
+ drivers/hwmon/Kconfig | 13 +
+ drivers/hwmon/Makefile | 1 +
+ drivers/hwmon/chipcap2.c | 25 +-
+ drivers/hwmon/coretemp.c | 2 +-
+ drivers/hwmon/cros_ec_hwmon.c | 12 +-
+ drivers/hwmon/ina2xx.c | 20 +
+ drivers/hwmon/pmbus/Kconfig | 33 +-
+ drivers/hwmon/pmbus/Makefile | 1 +
+ drivers/hwmon/pmbus/adm1275.c | 142 ++++++-
+ drivers/hwmon/pmbus/lm25066.c | 37 ++
+ drivers/hwmon/pmbus/sq24860.c | 430 +++++++++++++++++++++
+ drivers/hwmon/pmbus/xdpe1a2g7b.c | 11 +
+ drivers/hwmon/tvs-mpfs.c | 390 +++++++++++++++++++
+ drivers/hwmon/xgene-hwmon.c | 4 -
+ 26 files changed, 1418 insertions(+), 31 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/hwmon/pmbus/silergy,sq24860.yaml
+ create mode 100644 Documentation/hwmon/sq24860.rst
+ create mode 100644 Documentation/hwmon/tvs-mpfs.rst
+ create mode 100644 drivers/hwmon/pmbus/sq24860.c
+ create mode 100644 drivers/hwmon/tvs-mpfs.c
+Merging jc_docs/docs-next (f4b990a286fdc Revert "docs: allow inline literals in paragraphs to wrap to prevent overflow")
+$ git merge -m Merge branch 'docs-next' of git://git.lwn.net/linux.git jc_docs/docs-next
+Auto-merging Documentation/admin-guide/kernel-parameters.txt
+Auto-merging Documentation/admin-guide/mm/pagemap.rst
+Merge made by the 'ort' strategy.
+ Documentation/admin-guide/kernel-parameters.txt | 6 +-
+ Documentation/admin-guide/media/bttv.rst | 2 +-
+ Documentation/admin-guide/mm/pagemap.rst | 8 +-
+ Documentation/conf.py | 4 +-
+ Documentation/core-api/SMP.rst | 11 +
+ Documentation/core-api/index.rst | 1 +
+ Documentation/dev-tools/container.rst | 6 +-
+ Documentation/kernel-hacking/locking.rst | 8 +-
+ Documentation/mm/hmm.rst | 4 +-
+ Documentation/mm/process_addrs.rst | 2 +-
+ Documentation/sphinx-static/custom.css | 9 -
+ .../translations/pt_BR/process/4.Coding.rst | 440 +++++++++++++++++++++
+ .../translations/pt_BR/process/5.Posting.rst | 376 ++++++++++++++++++
+ .../pt_BR/process/development-process.rst | 2 +
+ .../pt_BR/process/maintainer-netdev.rst | 23 +-
+ tools/lib/python/kdoc/kdoc_output.py | 2 +-
+ 16 files changed, 867 insertions(+), 37 deletions(-)
+ create mode 100644 Documentation/core-api/SMP.rst
+ create mode 100644 Documentation/translations/pt_BR/process/4.Coding.rst
+ create mode 100644 Documentation/translations/pt_BR/process/5.Posting.rst
+Merging v4l-dvb/next (38d9078f8bb3e media: replace linux/gpio.h inclusions)
+$ git merge -m Merge branch 'next' of git://linuxtv.org/media-ci/media-pending.git v4l-dvb/next
+Auto-merging MAINTAINERS
+Auto-merging drivers/media/i2c/cvs/core.c
+Auto-merging drivers/media/usb/em28xx/em28xx.h
+Merge made by the 'ort' strategy.
+ .../admin-guide/media/em28xx-cardlist.rst | 4 +
+ Documentation/devicetree/bindings/media/rc.yaml | 4 +-
+ .../driver-api/media/maintainer-entry-profile.rst | 4 +
+ MAINTAINERS | 13 +
+ drivers/acpi/scan.c | 1 +
+ drivers/media/cec/core/cec-adap.c | 10 +-
+ drivers/media/cec/core/cec-core.c | 94 +-
+ drivers/media/cec/core/cec-pin.c | 8 +-
+ drivers/media/cec/platform/meson/ao-cec-g12a.c | 1 +
+ drivers/media/cec/platform/seco/seco-cec.c | 5 +-
+ drivers/media/cec/platform/stm32/stm32-cec.c | 19 +-
+ drivers/media/cec/platform/tegra/tegra_cec.c | 1 +
+ .../extron-da-hd-4k-plus/extron-da-hd-4k-plus.c | 3 +-
+ drivers/media/common/v4l2-tpg/v4l2-tpg-core.c | 14 +-
+ drivers/media/dvb-frontends/rtl2832_sdr.c | 23 +-
+ drivers/media/i2c/Kconfig | 21 +
+ drivers/media/i2c/Makefile | 2 +
+ drivers/media/i2c/alvium-csi2.c | 2 +-
+ drivers/media/i2c/cvs/core.c | 3 +
+ drivers/media/i2c/imx471.c | 957 +++++++++++++
+ drivers/media/i2c/imx678.c | 1447 ++++++++++++++++++++
+ drivers/media/i2c/ov02a10.c | 12 +-
+ drivers/media/i2c/ov7740.c | 10 +-
+ drivers/media/i2c/ov9282.c | 1 -
+ drivers/media/pci/ddbridge/ddbridge.h | 2 +-
+ drivers/media/pci/hws/hws_v4l2_ioctl.h | 4 -
+ drivers/media/pci/intel/ipu-bridge.c | 42 +
+ .../media/platform/renesas/rzg2l-cru/rzg2l-cru.h | 2 -
+ .../media/platform/samsung/s3c-camif/camif-core.c | 10 +-
+ drivers/media/radio/radio-cadet.c | 4 +-
+ drivers/media/radio/radio-gemtek.c | 4 +-
+ drivers/media/rc/fintek-cir.c | 4 +-
+ drivers/media/rc/ite-cir.c | 29 +-
+ drivers/media/rc/keymaps/Makefile | 2 +-
+ .../{rc-videomate-m1f.c => rc-videomate-k100.c} | 2 +-
+ drivers/media/rc/nuvoton-cir.c | 6 +-
+ drivers/media/rc/sunxi-cir.c | 9 +-
+ drivers/media/rc/winbond-cir.c | 4 +-
+ drivers/media/usb/airspy/airspy.c | 19 +-
+ drivers/media/usb/cx231xx/cx231xx-audio.c | 5 +
+ drivers/media/usb/cx231xx/cx231xx-video.c | 4 +-
+ drivers/media/usb/em28xx/em28xx-cards.c | 29 +
+ drivers/media/usb/em28xx/em28xx-dvb.c | 2 +-
+ drivers/media/usb/em28xx/em28xx-reg.h | 1 +
+ drivers/media/usb/em28xx/em28xx.h | 1 +
+ drivers/platform/x86/intel/int3472/discrete.c | 18 +
+ drivers/staging/media/ipu7/ipu7.c | 4 +-
+ include/media/drv-intf/s3c_camif.h | 2 -
+ include/media/media-entity.h | 1 +
+ include/media/rc-map.h | 2 -
+ include/media/v4l2-ioctl.h | 4 +-
+ 51 files changed, 2733 insertions(+), 142 deletions(-)
+ create mode 100644 drivers/media/i2c/imx471.c
+ create mode 100644 drivers/media/i2c/imx678.c
+ rename drivers/media/rc/keymaps/{rc-videomate-m1f.c => rc-videomate-k100.c} (97%)
+Merging v4l-dvb-next/master (adc218676eef2 Linux 6.12)
+$ git merge -m Merge branch 'master' of git://linuxtv.org/mchehab/media-next.git v4l-dvb-next/master
+Already up to date.
+Merging pm/linux-next (dc8bff6f7d6da Merge branch 'pm-runtime' into linux-next)
+$ git merge -m Merge branch 'linux-next' of https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git pm/linux-next
+Auto-merging drivers/acpi/scan.c
+Merge made by the 'ort' strategy.
+ Documentation/admin-guide/pm/cpufreq.rst | 2 +-
+ Documentation/driver-api/acpi/acpi-drivers.rst | 80 ------------
+ Documentation/driver-api/acpi/index.rst | 1 -
+ arch/riscv/include/asm/acpi.h | 1 +
+ drivers/acpi/apei/ghes.c | 4 +-
+ drivers/acpi/arm64/iort.c | 22 +++-
+ drivers/acpi/bus.c | 138 +-------------------
+ drivers/acpi/irq.c | 172 ++++++++++++++++++++++++-
+ drivers/acpi/numa/srat.c | 2 -
+ drivers/acpi/power.c | 1 -
+ drivers/acpi/riscv/irq.c | 141 +-------------------
+ drivers/acpi/scan.c | 18 +--
+ drivers/base/power/runtime.c | 6 +-
+ drivers/cpufreq/amd-pstate.c | 1 +
+ drivers/cpufreq/cpufreq.c | 17 ++-
+ drivers/cpufreq/intel_pstate.c | 137 ++++++++++----------
+ drivers/irqchip/irq-gic-v3.c | 2 +-
+ drivers/irqchip/irq-gic-v5-iwb.c | 2 +
+ drivers/irqchip/irq-gic-v5.c | 13 +-
+ drivers/irqchip/irq-gic.c | 2 +-
+ drivers/irqchip/irq-loongarch-cpu.c | 2 +-
+ drivers/irqchip/irq-riscv-intc.c | 3 +-
+ drivers/pnp/card.c | 11 +-
+ drivers/pnp/system.c | 6 +-
+ include/acpi/acpi_bus.h | 50 +------
+ include/linux/acpi.h | 13 +-
+ include/linux/acpi_iort.h | 3 +-
+ include/linux/cpufreq.h | 2 +
+ kernel/power/wakelock.c | 2 +-
+ kernel/sched/cpufreq_schedutil.c | 6 +-
+ rust/kernel/cpufreq.rs | 6 +-
+ 31 files changed, 341 insertions(+), 525 deletions(-)
+ delete mode 100644 Documentation/driver-api/acpi/acpi-drivers.rst
+Merging cpufreq-arm/cpufreq/arm/linux-next (f456178290356 rust: rcpufreq_dt: use vertical import style)
+$ git merge -m Merge branch 'cpufreq/arm/linux-next' of https://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm.git cpufreq-arm/cpufreq/arm/linux-next
+Merge made by the 'ort' strategy.
+ drivers/cpufreq/apple-soc-cpufreq.c | 36 ++++++++++++++----------------------
+ drivers/cpufreq/cpufreq-dt-platdev.c | 1 +
+ drivers/cpufreq/qcom-cpufreq-nvmem.c | 8 ++++++++
+ drivers/cpufreq/rcpufreq_dt.rs | 13 ++++++++++---
+ 4 files changed, 33 insertions(+), 25 deletions(-)
+Merging cpupower/cpupower (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'cpupower' of https://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux.git cpupower/cpupower
+Already up to date.
+Merging devfreq/devfreq-next (c096be11c2a9d PM / devfreq: Fix governor_store() failing when device has no current governor)
+$ git merge -m Merge branch 'devfreq-next' of https://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git devfreq/devfreq-next
+Merge made by the 'ort' strategy.
+ drivers/devfreq/devfreq.c | 50 +++++++-----------------------------
+ drivers/devfreq/event/rockchip-dfi.c | 4 ++-
+ 2 files changed, 12 insertions(+), 42 deletions(-)
+Merging pmdomain/next (567cf92d98054 pmdomain: Merge branch fixes into next)
+$ git merge -m Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm.git pmdomain/next
+Merge made by the 'ort' strategy.
+ drivers/pmdomain/qcom/rpmhpd.c | 24 ++++++++++++------------
+ 1 file changed, 12 insertions(+), 12 deletions(-)
+Merging opp/opp/linux-next (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'opp/linux-next' of https://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm.git opp/opp/linux-next
+Already up to date.
+Merging thermal/thermal/linux-next (968098b4ca521 thermal/drivers/qcom/tsens: Disable wakeup interrupt setup on automotive targets)
+$ git merge -m Merge branch 'thermal/linux-next' of https://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux.git thermal/thermal/linux-next
+Already up to date.
+Merging rdma/for-next (b21d9bf627dd4 RDMA/ionic: Remove duplicate IONIC_SPEC_HIGH definition)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma.git rdma/for-next
+Auto-merging drivers/infiniband/hw/irdma/verbs.c
+Merge made by the 'ort' strategy.
+ Documentation/infiniband/user_mad.rst | 2 +-
+ drivers/infiniband/core/iwpm_msg.c | 2 +-
+ drivers/infiniband/core/nldev.c | 29 ++++++-
+ drivers/infiniband/core/uverbs_std_types_mr.c | 6 +-
+ drivers/infiniband/hw/bng_re/bng_fw.c | 10 ++-
+ drivers/infiniband/hw/hfi1/device.c | 32 +------
+ drivers/infiniband/hw/hfi1/device.h | 1 -
+ drivers/infiniband/hw/hfi1/file_ops.c | 2 +-
+ drivers/infiniband/hw/ionic/ionic_ibdev.h | 1 -
+ drivers/infiniband/hw/irdma/i40iw_hw.c | 4 +-
+ drivers/infiniband/hw/irdma/icrdma_hw.c | 2 +
+ drivers/infiniband/hw/irdma/icrdma_hw.h | 2 +
+ drivers/infiniband/hw/irdma/icrdma_if.c | 8 +-
+ drivers/infiniband/hw/irdma/irdma.h | 2 +
+ drivers/infiniband/hw/irdma/utils.c | 6 ++
+ drivers/infiniband/hw/irdma/verbs.c | 116 +++++++++++++++++++-------
+ drivers/infiniband/hw/irdma/verbs.h | 3 +
+ drivers/infiniband/hw/mlx5/umr.c | 2 +-
+ drivers/infiniband/sw/rxe/rxe_mw.c | 20 +++--
+ include/uapi/rdma/rdma_netlink.h | 5 ++
+ 20 files changed, 168 insertions(+), 87 deletions(-)
+Merging net-next/main (832255a6df491 net: qed: Fix spelling typo in qed_dcbx.c comment)
+$ git merge -m Merge branch 'main' of https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git net-next/main
+Auto-merging MAINTAINERS
+CONFLICT (content): Merge conflict in MAINTAINERS
+Auto-merging include/linux/net.h
+Auto-merging net/core/dev.c
+Resolved 'MAINTAINERS' using previous resolution.
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit --no-edit -v -a
+[master 0263f037aec0c] Merge branch 'main' of https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git
+$ git diff -M --stat --summary HEAD^..
+ Documentation/driver-api/dpll.rst | 7 +
+ Documentation/netlink/specs/devlink.yaml | 30 +-
+ Documentation/netlink/specs/dpll.yaml | 19 +
+ Documentation/netlink/specs/rt-addr.yaml | 4 +
+ Documentation/networking/devlink/devlink-port.rst | 11 +
+ Documentation/networking/devlink/index.rst | 8 +-
+ Documentation/networking/devlink/mlx5.rst | 33 +
+ .../net_cachelines/netns_ipv4_sysctl.rst | 1 +
+ Documentation/networking/netdevices.rst | 7 +
+ MAINTAINERS | 5 -
+ arch/powerpc/configs/ppc64_defconfig | 1 -
+ arch/powerpc/mm/mem.c | 6 -
+ drivers/cxl/core/core.h | 2 +
+ drivers/cxl/core/mbox.c | 51 +-
+ drivers/cxl/core/memdev.c | 67 +
+ drivers/cxl/core/pci.c | 1 +
+ drivers/cxl/core/port.c | 1 +
+ drivers/cxl/core/regs.c | 1 +
+ drivers/cxl/cxlpci.h | 12 -
+ drivers/cxl/pci.c | 1 +
+ drivers/dpll/dpll_core.c | 6 +-
+ drivers/dpll/dpll_nl.c | 2 +-
+ drivers/dpll/zl3073x/chan.c | 128 +-
+ drivers/dpll/zl3073x/chan.h | 48 +
+ drivers/dpll/zl3073x/core.c | 48 +-
+ drivers/dpll/zl3073x/core.h | 12 +-
+ drivers/dpll/zl3073x/dpll.c | 491 ++-
+ drivers/dpll/zl3073x/dpll.h | 4 +
+ drivers/dpll/zl3073x/regs.h | 11 +
+ drivers/net/amt.c | 43 +-
+ drivers/net/bonding/bond_3ad.c | 24 +-
+ drivers/net/bonding/bond_main.c | 6 -
+ drivers/net/bonding/bond_netlink.c | 109 +-
+ drivers/net/bonding/bond_options.c | 8 +-
+ drivers/net/dsa/b53/b53_priv.h | 3 +-
+ drivers/net/dsa/microchip/ksz8.c | 431 ++-
+ drivers/net/dsa/microchip/ksz9477.c | 164 +-
+ drivers/net/dsa/microchip/ksz9477.h | 4 +-
+ drivers/net/dsa/microchip/ksz_common.c | 594 +---
+ drivers/net/dsa/microchip/ksz_common.h | 85 +-
+ drivers/net/dsa/microchip/lan937x_main.c | 6 +-
+ drivers/net/dsa/qca/qca8k-leds.c | 3 +
+ drivers/net/dsa/realtek/rtl8366rb.c | 268 +-
+ drivers/net/dsa/realtek/rtl83xx.c | 26 +-
+ drivers/net/ethernet/allwinner/sun4i-emac.c | 2 +-
+ drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 2 +-
+ drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c | 6 +-
+ .../net/ethernet/freescale/dpaa2/dpaa2-switch.c | 931 ++++-
+ .../net/ethernet/freescale/dpaa2/dpaa2-switch.h | 42 +-
+ drivers/net/ethernet/freescale/dpaa2/dpsw-cmd.h | 18 +-
+ drivers/net/ethernet/freescale/dpaa2/dpsw.c | 60 +
+ drivers/net/ethernet/freescale/dpaa2/dpsw.h | 30 +
+ drivers/net/ethernet/hisilicon/hns3/hnae3.h | 14 +
+ .../hisilicon/hns3/hns3_common/hclge_comm_cmd.h | 3 +
+ drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c | 12 +
+ .../net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h | 9 +
+ .../ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 172 +
+ .../ethernet/hisilicon/hns3/hns3pf/hclge_main.h | 7 +
+ drivers/net/ethernet/ibm/Kconfig | 9 -
+ drivers/net/ethernet/ibm/Makefile | 1 -
+ drivers/net/ethernet/ibm/ehea/Makefile | 7 -
+ drivers/net/ethernet/ibm/ehea/ehea.h | 477 ---
+ drivers/net/ethernet/ibm/ehea/ehea_ethtool.c | 277 --
+ drivers/net/ethernet/ibm/ehea/ehea_hw.h | 253 --
+ drivers/net/ethernet/ibm/ehea/ehea_main.c | 3581 --------------------
+ drivers/net/ethernet/ibm/ehea/ehea_phyp.c | 612 ----
+ drivers/net/ethernet/ibm/ehea/ehea_phyp.h | 433 ---
+ drivers/net/ethernet/ibm/ehea/ehea_qmr.c | 999 ------
+ drivers/net/ethernet/ibm/ehea/ehea_qmr.h | 390 ---
+ drivers/net/ethernet/intel/ice/ice_gnss.c | 5 +-
+ drivers/net/ethernet/intel/igb/e1000_82575.h | 21 +
+ drivers/net/ethernet/intel/igb/igb.h | 3 +
+ drivers/net/ethernet/intel/igb/igb_ethtool.c | 89 +-
+ drivers/net/ethernet/intel/igb/igb_main.c | 25 +-
+ drivers/net/ethernet/intel/igc/igc.h | 3 +
+ drivers/net/ethernet/intel/igc/igc_base.c | 33 +-
+ drivers/net/ethernet/intel/igc/igc_defines.h | 9 +-
+ drivers/net/ethernet/intel/igc/igc_ethtool.c | 279 +-
+ drivers/net/ethernet/intel/igc/igc_hw.h | 10 +-
+ drivers/net/ethernet/intel/igc/igc_mac.c | 35 +-
+ drivers/net/ethernet/intel/igc/igc_main.c | 10 +-
+ drivers/net/ethernet/intel/igc/igc_phy.c | 65 +-
+ drivers/net/ethernet/intel/igc/igc_phy.h | 1 +
+ drivers/net/ethernet/marvell/mvneta.c | 18 +
+ drivers/net/ethernet/marvell/mvneta_bm.c | 72 +
+ drivers/net/ethernet/marvell/octeontx2/af/mbox.h | 2 +
+ drivers/net/ethernet/marvell/octeontx2/af/npc.h | 4 +-
+ drivers/net/ethernet/marvell/octeontx2/af/rvu.h | 2 +-
+ .../net/ethernet/marvell/octeontx2/af/rvu_nix.c | 9 +-
+ .../net/ethernet/marvell/octeontx2/af/rvu_npc.c | 43 +-
+ drivers/net/ethernet/marvell/octeontx2/nic/cn20k.c | 1 +
+ .../ethernet/marvell/octeontx2/nic/otx2_common.c | 2 +-
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 5 +
+ drivers/net/ethernet/mellanox/mlx5/core/devlink.c | 1 +
+ .../ethernet/mellanox/mlx5/core/esw/devlink_port.c | 8 +-
+ drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c | 605 ++--
+ drivers/net/ethernet/mellanox/mlx5/core/esw/qos.h | 3 -
+ drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 27 +-
+ drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 18 +-
+ .../net/ethernet/mellanox/mlxsw/spectrum_acl_erp.c | 2 +-
+ .../ethernet/mellanox/mlxsw/spectrum_acl_tcam.h | 2 +-
+ drivers/net/ethernet/microsoft/Kconfig | 1 +
+ drivers/net/ethernet/microsoft/mana/gdma_main.c | 29 +
+ drivers/net/ethernet/microsoft/mana/mana_en.c | 175 +
+ drivers/net/ethernet/microsoft/mana/mana_ethtool.c | 167 +-
+ .../net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c | 2 +-
+ .../net/ethernet/pensando/ionic/ionic_rx_filter.c | 7 +-
+ drivers/net/ethernet/qlogic/qed/qed_dcbx.c | 2 +-
+ drivers/net/ethernet/qualcomm/ppe/ppe_config.c | 7 +-
+ drivers/net/ethernet/qualcomm/ppe/ppe_config.h | 2 +-
+ drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c | 3 +-
+ drivers/net/ethernet/sfc/Kconfig | 9 +
+ drivers/net/ethernet/sfc/Makefile | 1 +
+ drivers/net/ethernet/sfc/ef10.c | 41 +-
+ drivers/net/ethernet/sfc/efx.c | 18 +-
+ drivers/net/ethernet/sfc/efx_cxl.c | 105 +
+ drivers/net/ethernet/sfc/efx_cxl.h | 32 +
+ drivers/net/ethernet/sfc/mcdi.c | 7 +-
+ drivers/net/ethernet/sfc/net_driver.h | 10 +
+ drivers/net/ethernet/sfc/nic.h | 3 +
+ drivers/net/ethernet/sfc/siena/mcdi.c | 7 +-
+ drivers/net/ethernet/sgi/ioc3-eth.c | 9 +-
+ drivers/net/gtp.c | 12 +-
+ drivers/net/macsec.c | 78 +-
+ drivers/net/macvlan.c | 109 +-
+ drivers/net/netconsole.c | 2 +-
+ drivers/net/phy/mdio_device.c | 2 +-
+ drivers/net/phy/phylink.c | 15 +-
+ drivers/net/ppp/ppp_async.c | 2 -
+ drivers/net/ppp/ppp_synctty.c | 2 -
+ drivers/net/usb/rtl8150.c | 4 +-
+ include/cxl/cxl.h | 2 +
+ include/cxl/pci.h | 22 +
+ include/linux/mdio.h | 1 -
+ include/linux/net.h | 23 +
+ include/linux/netfilter.h | 7 +
+ include/linux/netfilter/nf_conntrack_h323.h | 2 -
+ include/linux/netfilter/nf_conntrack_pptp.h | 2 -
+ include/linux/netfilter/nf_conntrack_sane.h | 2 -
+ include/linux/netfilter/nf_conntrack_tftp.h | 2 -
+ include/net/bond_3ad.h | 4 +-
+ include/net/bonding.h | 8 +-
+ include/net/devlink.h | 15 +-
+ include/net/fib_rules.h | 4 +-
+ include/net/ip_fib.h | 3 +-
+ include/net/ip_vs.h | 2 +-
+ include/net/mana/gdma.h | 24 +-
+ include/net/mana/mana.h | 54 +
+ include/net/netfilter/nf_conntrack_helper.h | 10 +-
+ include/net/netns/ipv4.h | 1 +
+ include/net/udp.h | 2 +-
+ include/uapi/linux/devlink.h | 2 +
+ include/uapi/linux/dpll.h | 8 +
+ include/uapi/linux/if_addr.h | 1 +
+ net/batman-adv/bat_iv_ogm.c | 12 +-
+ net/batman-adv/bat_v_elp.c | 9 +-
+ net/batman-adv/bat_v_ogm.c | 33 +-
+ net/batman-adv/bridge_loop_avoidance.c | 9 +-
+ net/batman-adv/hard-interface.c | 165 +-
+ net/batman-adv/hard-interface.h | 10 +-
+ net/batman-adv/main.c | 9 -
+ net/batman-adv/main.h | 3 -
+ net/batman-adv/mesh-interface.c | 13 +-
+ net/batman-adv/netlink.c | 4 +-
+ net/batman-adv/originator.c | 4 -
+ net/batman-adv/tp_meter.c | 215 +-
+ net/batman-adv/tvlv.c | 86 +-
+ net/batman-adv/types.h | 28 +-
+ net/bridge/netfilter/ebtables.c | 12 +-
+ net/core/dev.c | 5 +
+ net/core/fib_rules.c | 83 +-
+ net/core/lock_debug.c | 4 +-
+ net/core/netpoll.c | 2 +-
+ net/core/rtnetlink.c | 17 +-
+ net/devlink/core.c | 20 +-
+ net/devlink/dev.c | 16 +-
+ net/devlink/devl_internal.h | 20 +
+ net/devlink/dpipe.c | 14 +-
+ net/devlink/health.c | 12 +-
+ net/devlink/linecard.c | 4 +-
+ net/devlink/netlink.c | 82 +-
+ net/devlink/netlink_gen.c | 24 +-
+ net/devlink/netlink_gen.h | 8 +
+ net/devlink/param.c | 4 +-
+ net/devlink/port.c | 24 +-
+ net/devlink/rate.c | 329 +-
+ net/devlink/region.c | 6 +-
+ net/devlink/resource.c | 14 +-
+ net/devlink/sb.c | 22 +-
+ net/devlink/trap.c | 12 +-
+ net/dsa/dsa.c | 20 +-
+ net/dsa/user.c | 19 +-
+ net/ipv4/fib_frontend.c | 69 +-
+ net/ipv4/fib_rules.c | 20 +-
+ net/ipv4/fib_trie.c | 3 +-
+ net/ipv4/igmp.c | 2 +
+ net/ipv4/netfilter/nf_nat_snmp_basic_main.c | 2 +-
+ net/ipv4/raw.c | 41 +-
+ net/ipv4/udp.c | 39 +-
+ net/ipv6/addrconf.c | 1 +
+ net/ipv6/fib6_rules.c | 17 +-
+ net/ipv6/mcast.c | 1 +
+ net/ipv6/udp.c | 19 +-
+ net/netfilter/ipvs/ip_vs_nfct.c | 2 +-
+ net/netfilter/nf_conntrack_amanda.c | 6 +-
+ net/netfilter/nf_conntrack_broadcast.c | 2 -
+ net/netfilter/nf_conntrack_ftp.c | 32 +-
+ net/netfilter/nf_conntrack_h323_main.c | 12 +-
+ net/netfilter/nf_conntrack_helper.c | 77 +-
+ net/netfilter/nf_conntrack_irc.c | 27 +-
+ net/netfilter/nf_conntrack_netbios_ns.c | 2 -
+ net/netfilter/nf_conntrack_ovs.c | 6 +-
+ net/netfilter/nf_conntrack_pptp.c | 2 +-
+ net/netfilter/nf_conntrack_sane.c | 34 +-
+ net/netfilter/nf_conntrack_sip.c | 45 +-
+ net/netfilter/nf_conntrack_snmp.c | 4 +-
+ net/netfilter/nf_conntrack_tftp.c | 33 +-
+ net/netfilter/nf_nat_core.c | 6 -
+ net/netfilter/nf_nat_proto.c | 8 +
+ net/netfilter/nfnetlink_cthelper.c | 21 +-
+ net/netfilter/nfnetlink_cttimeout.c | 2 +-
+ net/netfilter/nfnetlink_hook.c | 37 +-
+ net/netfilter/nft_ct.c | 35 +
+ net/netfilter/nft_set_rbtree.c | 3 +-
+ net/netfilter/x_tables.c | 30 +-
+ net/netfilter/xt_TCPOPTSTRIP.c | 8 +-
+ net/netfilter/xt_dscp.c | 12 +
+ net/netfilter/xt_recent.c | 2 +-
+ net/netfilter/xt_tcpmss.c | 13 +
+ net/sched/act_ct.c | 4 +-
+ net/vmw_vsock/virtio_transport_common.c | 49 +-
+ tools/net/ynl/pyynl/__init__.py | 9 +
+ tools/net/ynl/pyynl/cli.py | 56 +-
+ tools/net/ynl/pyynl/lib/__init__.py | 3 +-
+ tools/net/ynl/pyynl/lib/nlspec.py | 22 +-
+ tools/net/ynl/pyynl/lib/specdir.py | 51 +
+ tools/net/ynl/pyynl/lib/ynl.py | 19 +-
+ tools/net/ynl/tests/ethtool.py | 7 +-
+ tools/testing/selftests/bpf/prog_tests/test_xsk.c | 4 +-
+ tools/testing/selftests/drivers/net/hw/Makefile | 1 +
+ .../drivers/net/hw/devlink_rate_cross_esw.py | 296 ++
+ tools/testing/selftests/drivers/net/hw/rss_ctx.py | 11 +-
+ tools/testing/selftests/drivers/net/hw/toeplitz.py | 22 +
+ tools/testing/selftests/drivers/net/lib/py/env.py | 27 +-
+ tools/testing/selftests/drivers/net/xdp.py | 94 +-
+ tools/testing/selftests/net/getsockopt_iter.c | 97 +
+ .../selftests/net/openvswitch/openvswitch.sh | 87 +
+ tools/testing/selftests/net/rtnetlink.py | 101 +-
+ .../tc-testing/tc-tests/infra/qdiscs.json | 164 +
+ 249 files changed, 6921 insertions(+), 9866 deletions(-)
+ delete mode 100644 drivers/net/ethernet/ibm/ehea/Makefile
+ delete mode 100644 drivers/net/ethernet/ibm/ehea/ehea.h
+ delete mode 100644 drivers/net/ethernet/ibm/ehea/ehea_ethtool.c
+ delete mode 100644 drivers/net/ethernet/ibm/ehea/ehea_hw.h
+ delete mode 100644 drivers/net/ethernet/ibm/ehea/ehea_main.c
+ delete mode 100644 drivers/net/ethernet/ibm/ehea/ehea_phyp.c
+ delete mode 100644 drivers/net/ethernet/ibm/ehea/ehea_phyp.h
+ delete mode 100644 drivers/net/ethernet/ibm/ehea/ehea_qmr.c
+ delete mode 100644 drivers/net/ethernet/ibm/ehea/ehea_qmr.h
+ create mode 100644 drivers/net/ethernet/sfc/efx_cxl.c
+ create mode 100644 drivers/net/ethernet/sfc/efx_cxl.h
+ create mode 100644 include/cxl/pci.h
+ create mode 100644 tools/net/ynl/pyynl/lib/specdir.py
+ create mode 100755 tools/testing/selftests/drivers/net/hw/devlink_rate_cross_esw.py
+Merging bpf-next/for-next (b1d4514ff1f96 selftests/bpf: Add bpf_icmp_send no route test)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git bpf-next/for-next
+Merge made by the 'ort' strategy.
+ Documentation/bpf/bpf_devel_QA.rst | 5 +-
+ Documentation/bpf/index.rst | 1 +
+ Documentation/bpf/kfuncs.rst | 23 +-
+ Documentation/bpf/signing.rst | 497 +++++++++
+ arch/s390/net/bpf_jit_comp.c | 4 +-
+ include/linux/bpf.h | 16 +-
+ include/linux/bpf_verifier.h | 28 +-
+ include/uapi/linux/bpf.h | 28 +-
+ kernel/bpf/bpf_lsm.c | 1 -
+ kernel/bpf/btf.c | 19 +-
+ kernel/bpf/core.c | 9 +-
+ kernel/bpf/fixups.c | 11 +-
+ kernel/bpf/syscall.c | 85 +-
+ kernel/bpf/task_iter.c | 36 +-
+ kernel/bpf/verifier.c | 627 +++++++++---
+ kernel/trace/bpf_trace.c | 55 +
+ net/core/filter.c | 102 +-
+ tools/bpf/bpftool/Makefile | 2 +-
+ tools/bpf/bpftool/btf.c | 13 +-
+ tools/bpf/bpftool/btf_dumper.c | 14 +-
+ tools/bpf/bpftool/gen.c | 2 +
+ tools/bpf/bpftool/link.c | 133 +++
+ tools/bpf/bpftool/map.c | 12 +-
+ tools/bpf/bpftool/sign.c | 24 +-
+ tools/bpf/bpftool/struct_ops.c | 4 +
+ tools/bpf/resolve_btfids/Makefile | 5 +-
+ tools/include/linux/btf_ids.h | 78 +-
+ tools/include/uapi/linux/bpf.h | 28 +-
+ tools/lib/bpf/bpf_gen_internal.h | 1 -
+ tools/lib/bpf/btf.c | 10 +-
+ tools/lib/bpf/btf_dump.c | 4 +-
+ tools/lib/bpf/btf_relocate.c | 8 +-
+ tools/lib/bpf/elf.c | 2 +-
+ tools/lib/bpf/gen_loader.c | 92 +-
+ tools/lib/bpf/libbpf.c | 88 +-
+ tools/lib/bpf/libbpf_internal.h | 1 -
+ tools/lib/bpf/nlattr.c | 2 +-
+ tools/lib/bpf/relo_core.c | 22 +-
+ tools/lib/bpf/skel_internal.h | 31 +-
+ tools/lib/bpf/usdt.c | 33 +-
+ .../bpf/libarena/include/libarena/bitmap.h | 34 +
+ .../bpf/libarena/include/libarena/common.h | 2 +-
+ .../{st_asan_buddy.bpf.c => test_asan_buddy.bpf.c} | 10 +-
+ .../{st_asan_common.h => test_asan_common.h} | 0
+ .../bpf/libarena/selftests/test_bitmap.bpf.c | 394 +++++++
+ .../selftests/{st_buddy.bpf.c => test_buddy.bpf.c} | 8 +-
+ .../libarena/selftests/test_parallel_bitmap.bpf.c | 190 ++++
+ .../libarena/selftests/test_parallel_spmc.bpf.c | 9 +-
+ .../selftests/bpf/libarena/src/bitmap.bpf.c | 245 +++++
+ .../selftests/bpf/libarena/src/common.bpf.c | 9 +-
+ tools/testing/selftests/bpf/network_helpers.c | 4 +-
+ tools/testing/selftests/bpf/network_helpers.h | 5 +
+ .../testing/selftests/bpf/prog_tests/bpf_tcp_ca.c | 12 +
+ .../selftests/bpf/prog_tests/fexit_bpf2bpf.c | 14 -
+ .../selftests/bpf/prog_tests/fill_link_info.c | 242 +++++
+ .../bpf/prog_tests/get_smp_processor_id.c | 45 +
+ .../selftests/bpf/prog_tests/icmp_send_kfunc.c | 292 ++++++
+ .../testing/selftests/bpf/prog_tests/kfunc_call.c | 1 +
+ tools/testing/selftests/bpf/prog_tests/libarena.c | 8 +-
+ .../selftests/bpf/prog_tests/libarena_asan.c | 8 +-
+ .../testing/selftests/bpf/prog_tests/linked_list.c | 1 +
+ tools/testing/selftests/bpf/prog_tests/mptcp.c | 13 +-
+ .../selftests/bpf/prog_tests/res_spin_lock.c | 20 +
+ .../selftests/bpf/prog_tests/resolve_btfids.c | 169 ++-
+ .../selftests/bpf/prog_tests/signed_loader.c | 1083 ++++++++++++++++----
+ .../selftests/bpf/prog_tests/sockmap_basic.c | 52 -
+ .../testing/selftests/bpf/prog_tests/tc_redirect.c | 68 ++
+ .../selftests/bpf/prog_tests/test_map_uninit.c | 68 ++
+ .../testing/selftests/bpf/progs/bpf_tracing_net.h | 3 +
+ tools/testing/selftests/bpf/progs/btf_data.c | 10 +
+ .../selftests/bpf/progs/freplace_cls_redirect.c | 34 -
+ .../selftests/bpf/progs/get_smp_processor_id.c | 20 +
+ tools/testing/selftests/bpf/progs/icmp_send.c | 123 +++
+ .../testing/selftests/bpf/progs/kfunc_call_fail.c | 33 +
+ .../testing/selftests/bpf/progs/linked_list_fail.c | 23 +
+ tools/testing/selftests/bpf/progs/map_kptr.c | 12 +
+ tools/testing/selftests/bpf/progs/mptcpify.c | 2 +-
+ .../selftests/bpf/progs/sockmap_verdict_prog.c | 14 +-
+ .../bpf/progs/tcp_ca_untrusted_btf_write.c | 26 +
+ .../selftests/bpf/progs/test_fill_link_info.c | 6 +
+ .../selftests/bpf/progs/test_signed_loader.c | 9 +-
+ .../selftests/bpf/progs/test_sockmap_update.c | 48 -
+ tools/testing/selftests/bpf/progs/test_tc_peer.c | 22 +
+ tools/testing/selftests/bpf/progs/verifier_gotox.c | 25 +
+ .../testing/selftests/bpf/progs/verifier_map_ptr.c | 23 +-
+ .../selftests/bpf/progs/verifier_scalar_ids.c | 56 +
+ .../selftests/bpf/progs/verifier_sockmap_mutate.c | 12 +-
+ .../selftests/bpf/progs/verifier_spill_fill.c | 68 ++
+ .../testing/selftests/bpf/progs/verifier_var_off.c | 110 ++
+ tools/testing/selftests/bpf/test_sockmap.c | 3 +-
+ 90 files changed, 4898 insertions(+), 946 deletions(-)
+ create mode 100644 Documentation/bpf/signing.rst
+ create mode 100644 tools/testing/selftests/bpf/libarena/include/libarena/bitmap.h
+ rename tools/testing/selftests/bpf/libarena/selftests/{st_asan_buddy.bpf.c => test_asan_buddy.bpf.c} (98%)
+ rename tools/testing/selftests/bpf/libarena/selftests/{st_asan_common.h => test_asan_common.h} (100%)
+ create mode 100644 tools/testing/selftests/bpf/libarena/selftests/test_bitmap.bpf.c
+ rename tools/testing/selftests/bpf/libarena/selftests/{st_buddy.bpf.c => test_buddy.bpf.c} (97%)
+ create mode 100644 tools/testing/selftests/bpf/libarena/selftests/test_parallel_bitmap.bpf.c
+ create mode 100644 tools/testing/selftests/bpf/libarena/src/bitmap.bpf.c
+ create mode 100644 tools/testing/selftests/bpf/prog_tests/get_smp_processor_id.c
+ create mode 100644 tools/testing/selftests/bpf/prog_tests/icmp_send_kfunc.c
+ create mode 100644 tools/testing/selftests/bpf/prog_tests/test_map_uninit.c
+ delete mode 100644 tools/testing/selftests/bpf/progs/freplace_cls_redirect.c
+ create mode 100644 tools/testing/selftests/bpf/progs/get_smp_processor_id.c
+ create mode 100644 tools/testing/selftests/bpf/progs/icmp_send.c
+ create mode 100644 tools/testing/selftests/bpf/progs/tcp_ca_untrusted_btf_write.c
+ delete mode 100644 tools/testing/selftests/bpf/progs/test_sockmap_update.c
+$ git am -3 ../patches/0001-perf-Fixup-for-btf_vlan-API-change.patch
+Applying: perf: Fixup for btf_vlan() API change
+Using index info to reconstruct a base tree...
+M tools/perf/builtin-trace.c
+M tools/perf/util/btf.c
+Falling back to patching base and 3-way merge...
+Auto-merging tools/perf/builtin-trace.c
+No changes -- Patch already applied.
+Merging ipsec-next/master (355f808d8a11f Merge branch 'xfrm: XFRM_MSG_MIGRATE_STATE new netlink message')
+$ git merge -m Merge branch 'master' of https://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec-next.git ipsec-next/master
+Already up to date.
+Merging mlx5-next/mlx5-next (ddbddbf8aee54 net/mlx5: Add sd_group_size bits for SD management)
+$ git merge -m Merge branch 'mlx5-next' of https://git.kernel.org/pub/scm/linux/kernel/git/mellanox/linux.git mlx5-next/mlx5-next
+Already up to date.
+Merging netfilter-next/main (08030ddb87b4c Merge branch '1GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue)
+$ git merge -m Merge branch 'main' of https://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf-next.git netfilter-next/main
+Already up to date.
+Merging ipvs-next/main (b73bc9ca3686b Merge tag 'nf-next-26-07-02' of https://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf-next)
+$ git merge -m Merge branch 'main' of https://git.kernel.org/pub/scm/linux/kernel/git/horms/ipvs-next.git ipvs-next/main
+Already up to date.
+Merging bluetooth/master (ca75417ab1793 Bluetooth: btintel_pcie: split coredump worker into per-trigger works)
+$ git merge -m Merge branch 'master' of https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git bluetooth/master
+Auto-merging drivers/bluetooth/btintel_pcie.c
+CONFLICT (content): Merge conflict in drivers/bluetooth/btintel_pcie.c
+Auto-merging drivers/bluetooth/btnxpuart.c
+Auto-merging net/bluetooth/af_bluetooth.c
+Auto-merging net/bluetooth/hci_sync.c
+Auto-merging net/bluetooth/l2cap_sock.c
+Auto-merging net/bluetooth/mgmt.c
+Resolved 'drivers/bluetooth/btintel_pcie.c' using previous resolution.
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit --no-edit -v -a
+[master 2e8650dd90488] Merge branch 'master' of https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git
+$ git diff -M --stat --summary HEAD^..
+ drivers/bluetooth/Makefile | 2 +
+ drivers/bluetooth/btintel_pcie.c | 180 +++++++++++++++++++++++++--------------
+ drivers/bluetooth/btintel_pcie.h | 12 ++-
+ drivers/bluetooth/btnxpuart.c | 4 +-
+ drivers/bluetooth/btqca.c | 27 +-----
+ drivers/bluetooth/btusb.c | 98 +++++++++++++--------
+ drivers/bluetooth/hci_nokia.c | 20 +++++
+ include/net/bluetooth/hci_sync.h | 4 +-
+ net/bluetooth/Makefile | 2 +
+ net/bluetooth/af_bluetooth.c | 7 +-
+ net/bluetooth/bnep/Makefile | 2 +
+ net/bluetooth/hci_core.c | 3 +
+ net/bluetooth/hci_debugfs.c | 12 +--
+ net/bluetooth/hci_event.c | 5 +-
+ net/bluetooth/hci_sync.c | 44 +++-------
+ net/bluetooth/hidp/Makefile | 2 +
+ net/bluetooth/l2cap_sock.c | 1 +
+ net/bluetooth/mgmt.c | 44 ++++++++--
+ net/bluetooth/rfcomm/Makefile | 2 +
+ net/bluetooth/rfcomm/sock.c | 1 +
+ 20 files changed, 288 insertions(+), 184 deletions(-)
+Merging wireless-next/for-next (ac798f757d647 wifi: mac80211: Route (Re)association req/response to per-STA queue)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git wireless-next/for-next
+Auto-merging drivers/net/wireless/marvell/mwifiex/cfg80211.c
+Auto-merging drivers/net/wireless/virtual/mac80211_hwsim_main.c
+Auto-merging include/net/cfg80211.h
+Auto-merging net/mac80211/cfg.c
+Auto-merging net/mac80211/tx.c
+Auto-merging net/wireless/nl80211.c
+Merge made by the 'ort' strategy.
+ drivers/net/wireless/ath/ath12k/mac.c | 6 -
+ drivers/net/wireless/ath/wil6210/cfg80211.c | 10 +-
+ drivers/net/wireless/broadcom/b43/debugfs.c | 12 +-
+ drivers/net/wireless/broadcom/b43legacy/debugfs.c | 12 +-
+ drivers/net/wireless/intersil/p54/Kconfig | 6 +-
+ drivers/net/wireless/intersil/p54/fwio.c | 4 +-
+ drivers/net/wireless/intersil/p54/p54usb.c | 2 +-
+ drivers/net/wireless/marvell/libertas/debugfs.c | 39 +-
+ drivers/net/wireless/marvell/mwifiex/cfg80211.c | 8 +-
+ drivers/net/wireless/marvell/mwifiex/debugfs.c | 62 ++-
+ drivers/net/wireless/realtek/rtw89/core.c | 3 -
+ drivers/net/wireless/ti/wlcore/main.c | 14 +-
+ drivers/net/wireless/virtual/mac80211_hwsim_main.c | 7 +-
+ include/linux/ieee80211.h | 12 +
+ include/net/cfg80211.h | 41 +-
+ include/net/ieee80211_radiotap.h | 190 ++++++++
+ include/uapi/linux/nl80211.h | 46 +-
+ net/mac80211/cfg.c | 6 +-
+ net/mac80211/ieee80211_i.h | 4 +-
+ net/mac80211/status.c | 2 +-
+ net/mac80211/tx.c | 7 +
+ net/wireless/nl80211.c | 476 ++++++++++++++-------
+ net/wireless/rdev-ops.h | 10 +-
+ net/wireless/trace.h | 2 +-
+ net/wireless/wext-core.c | 6 +-
+ 25 files changed, 693 insertions(+), 294 deletions(-)
+Merging ath-next/for-next (913998f903fb1 wifi: ath12k: correct monitor destination ring size)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/ath/ath.git ath-next/for-next
+Auto-merging drivers/net/wireless/ath/ath12k/mac.c
+Auto-merging drivers/net/wireless/ath/ath12k/pci.c
+Merge made by the 'ort' strategy.
+ drivers/net/wireless/ath/ath12k/ahb.c | 1 -
+ drivers/net/wireless/ath/ath12k/ahb.h | 2 +-
+ drivers/net/wireless/ath/ath12k/core.c | 7 +-
+ drivers/net/wireless/ath/ath12k/debugfs.c | 14 +-
+ drivers/net/wireless/ath/ath12k/dp.c | 14 +-
+ drivers/net/wireless/ath/ath12k/dp.h | 3 +-
+ drivers/net/wireless/ath/ath12k/dp_mon.c | 70 +------
+ drivers/net/wireless/ath/ath12k/dp_mon.h | 4 +-
+ drivers/net/wireless/ath/ath12k/hal.c | 42 ++--
+ drivers/net/wireless/ath/ath12k/hal.h | 13 +-
+ drivers/net/wireless/ath/ath12k/mac.c | 9 +-
+ drivers/net/wireless/ath/ath12k/pci.c | 12 +-
+ drivers/net/wireless/ath/ath12k/qmi.c | 214 +++++++++++----------
+ drivers/net/wireless/ath/ath12k/qmi.h | 26 ---
+ drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c | 66 +++----
+ .../net/wireless/ath/ath12k/wifi7/hal_qcc2072.c | 4 +-
+ .../net/wireless/ath/ath12k/wifi7/hal_qcn9274.c | 13 +-
+ .../net/wireless/ath/ath12k/wifi7/hal_wcn7850.c | 13 +-
+ drivers/net/wireless/ath/ath12k/wifi7/hw.c | 61 ++++--
+ drivers/net/wireless/ath/ath12k/wmi.c | 47 +++--
+ drivers/net/wireless/ath/ath12k/wmi.h | 7 +
+ kernel/irq/manage.c | 1 +
+ 22 files changed, 350 insertions(+), 293 deletions(-)
+Merging iwlwifi-next/next (a6136ca2dd977 wifi: iwlwifi: bump maximum core version for BZ/SC/DR to 106)
+$ git merge -m Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next.git iwlwifi-next/next
+Already up to date.
+Merging wpan-next/master (a6bfdfcc6711d ieee802154: allow legacy LLSEC ADD/DEL ops to pass strict validation)
+$ git merge -m Merge branch 'master' of https://git.kernel.org/pub/scm/linux/kernel/git/wpan/wpan-next.git wpan-next/master
+Already up to date.
+Merging wpan-staging/staging (a6bfdfcc6711d ieee802154: allow legacy LLSEC ADD/DEL ops to pass strict validation)
+$ git merge -m Merge branch 'staging' of https://git.kernel.org/pub/scm/linux/kernel/git/wpan/wpan-next.git wpan-staging/staging
+Already up to date.
+Merging mtd/mtd/next (d276783e490d7 mtd: maps: correct CONFIG_MTD_COMPLEX_MAPPINGS macro name in comment)
+$ git merge -m Merge branch 'mtd/next' of https://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git mtd/mtd/next
+Merge made by the 'ort' strategy.
+ drivers/mtd/chips/cfi_cmdset_0001.c | 6 ++++++
+ drivers/mtd/maps/map_funcs.c | 2 +-
+ 2 files changed, 7 insertions(+), 1 deletion(-)
+Merging nand/nand/next (adfc275b317c0 mtd: parsers: redboot: reject unterminated FIS names)
+$ git merge -m Merge branch 'nand/next' of https://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git nand/nand/next
+Auto-merging drivers/mtd/nand/spi/core.c
+Merge made by the 'ort' strategy.
+ drivers/mtd/nand/raw/atmel/nand-controller.c | 3 +-
+ drivers/mtd/nand/raw/pl35x-nand-controller.c | 20 ++--
+ drivers/mtd/nand/spi/Makefile | 2 +-
+ drivers/mtd/nand/spi/core.c | 1 +
+ drivers/mtd/nand/spi/fmsh.c | 95 +++++++++++++++++++
+ drivers/mtd/nand/spi/heyangtek.c | 132 +++++++++++++++++++++++++++
+ drivers/mtd/parsers/redboot.c | 9 +-
+ include/linux/mtd/spinand.h | 1 +
+ 8 files changed, 252 insertions(+), 11 deletions(-)
+ create mode 100644 drivers/mtd/nand/spi/heyangtek.c
+Merging spi-nor/spi-nor/next (df415c5e1de0f mtd: spi-nor: spansion: add die erase support in s28hx-t)
+$ git merge -m Merge branch 'spi-nor/next' of https://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git spi-nor/spi-nor/next
+Already up to date.
+Merging crypto/master (e264401ce4776 crypto: keembay - Fix AEAD unregister count in error path)
+$ git merge -m Merge branch 'master' of https://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git crypto/master
+Auto-merging MAINTAINERS
+Auto-merging arch/arm/configs/multi_v7_defconfig
+Auto-merging arch/arm64/configs/defconfig
+Auto-merging drivers/char/hw_random/atmel-rng.c
+Auto-merging drivers/char/hw_random/xilinx-trng.c
+Auto-merging drivers/crypto/atmel-tdes.c
+Auto-merging drivers/crypto/ccp/sev-dev.c
+Merge made by the 'ort' strategy.
+ .../ABI/testing/sysfs-firmware-sev-vulnerabilities | 19 ++
+ Documentation/admin-guide/sysctl/crypto.rst | 36 +++
+ Documentation/crypto/userspace-if.rst | 13 +-
+ MAINTAINERS | 2 +-
+ arch/arm/configs/multi_v7_defconfig | 2 +-
+ arch/arm/configs/qcom_defconfig | 2 +-
+ arch/arm64/configs/defconfig | 2 +-
+ crypto/af_alg.c | 72 +++++-
+ crypto/algif_aead.c | 11 +
+ crypto/algif_hash.c | 24 ++
+ crypto/algif_rng.c | 9 +
+ crypto/algif_skcipher.c | 20 ++
+ crypto/api.c | 2 +-
+ crypto/crypto_user.c | 9 +-
+ crypto/ecc.c | 98 +++++----
+ crypto/hctr2.c | 3 +-
+ crypto/lrw.c | 2 +-
+ crypto/lskcipher.c | 3 +-
+ crypto/xts.c | 3 +-
+ drivers/char/hw_random/Kconfig | 11 +
+ drivers/char/hw_random/Makefile | 1 +
+ drivers/char/hw_random/atmel-rng.c | 2 +-
+ drivers/char/hw_random/core.c | 4 +-
+ drivers/char/hw_random/omap-rng.c | 30 ++-
+ drivers/{crypto => char/hw_random}/qcom-rng.c | 156 +++----------
+ drivers/char/hw_random/xilinx-trng.c | 32 ++-
+ drivers/crypto/Kconfig | 12 -
+ drivers/crypto/Makefile | 1 -
+ drivers/crypto/allwinner/Kconfig | 16 --
+ drivers/crypto/allwinner/sun8i-ce/Makefile | 1 -
+ drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c | 63 ------
+ drivers/crypto/allwinner/sun8i-ce/sun8i-ce-prng.c | 159 --------------
+ drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h | 29 ---
+ drivers/crypto/allwinner/sun8i-ss/Makefile | 1 -
+ drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c | 45 ----
+ drivers/crypto/allwinner/sun8i-ss/sun8i-ss-prng.c | 177 ---------------
+ drivers/crypto/allwinner/sun8i-ss/sun8i-ss.h | 23 --
+ drivers/crypto/amcc/crypto4xx_core.c | 11 +-
+ drivers/crypto/atmel-ecc.c | 42 ++--
+ drivers/crypto/atmel-i2c.c | 5 +-
+ drivers/crypto/atmel-sha204a.c | 6 +-
+ drivers/crypto/atmel-tdes.c | 5 +-
+ drivers/crypto/caam/Kconfig | 9 -
+ drivers/crypto/caam/Makefile | 1 -
+ drivers/crypto/caam/caamprng.c | 241 ---------------------
+ drivers/crypto/caam/intern.h | 15 --
+ drivers/crypto/caam/jr.c | 2 -
+ drivers/crypto/cavium/nitrox/nitrox_hal.c | 3 +-
+ drivers/crypto/ccp/ccp-crypto-sha.c | 2 +-
+ drivers/crypto/ccp/sev-dev.c | 177 +++++++++++++++
+ drivers/crypto/ccp/sev-dev.h | 3 +
+ drivers/crypto/hisilicon/qm.c | 5 +-
+ .../crypto/intel/keembay/keembay-ocs-aes-core.c | 4 +-
+ drivers/crypto/intel/qat/qat_common/adf_aer.c | 2 +
+ drivers/crypto/intel/qat/qat_common/adf_cfg.c | 7 +-
+ .../crypto/intel/qat/qat_common/adf_cfg_services.c | 2 +-
+ .../crypto/intel/qat/qat_common/adf_mstate_mgr.c | 3 +-
+ .../intel/qat/qat_common/adf_transport_debug.c | 3 +-
+ drivers/crypto/intel/qat/qat_common/qat_algs.c | 1 +
+ .../crypto/intel/qat/qat_common/qat_compression.c | 3 +-
+ drivers/crypto/marvell/octeontx/otx_cptpf_ucode.c | 4 +-
+ .../crypto/marvell/octeontx2/otx2_cptpf_ucode.c | 4 +-
+ drivers/crypto/mxs-dcp.c | 2 +-
+ drivers/crypto/qce/aead.c | 56 +----
+ drivers/crypto/qce/common.c | 55 +----
+ drivers/crypto/qce/common.h | 16 +-
+ drivers/crypto/qce/regs-v5.h | 4 -
+ drivers/crypto/qce/sha.c | 61 +-----
+ drivers/crypto/qce/sha.h | 1 -
+ drivers/crypto/qce/skcipher.c | 97 +--------
+ drivers/crypto/rockchip/rk3288_crypto_ahash.c | 7 +-
+ drivers/crypto/sa2ul.c | 6 +-
+ drivers/gpu/drm/ci/arm64.config | 2 +-
+ include/crypto/if_alg.h | 8 +
+ include/linux/psp-sev.h | 51 +++++
+ include/linux/rhashtable.h | 1 -
+ lib/rhashtable.c | 2 +
+ 77 files changed, 686 insertions(+), 1338 deletions(-)
+ create mode 100644 Documentation/ABI/testing/sysfs-firmware-sev-vulnerabilities
+ rename drivers/{crypto => char/hw_random}/qcom-rng.c (53%)
+ delete mode 100644 drivers/crypto/allwinner/sun8i-ce/sun8i-ce-prng.c
+ delete mode 100644 drivers/crypto/allwinner/sun8i-ss/sun8i-ss-prng.c
+ delete mode 100644 drivers/crypto/caam/caamprng.c
+Merging libcrypto/libcrypto-next (1002500f54b5f lib/crypto: md5: Remove support for md5_mod_init_arch())
+$ git merge -m Merge branch 'libcrypto-next' of https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git libcrypto/libcrypto-next
+Merge made by the 'ort' strategy.
+ lib/crypto/md5.c | 14 --------------
+ 1 file changed, 14 deletions(-)
+Merging drm/drm-next (e3cdab67efa8b Merge tag 'amd-drm-next-7.3-2026-07-09' of https://gitlab.freedesktop.org/agd5f/linux into drm-next)
+ 1dfd4e84b5bee ("drm/amdgpu: add support for SMU version 15.0.9")
+ 5c6c247992d4d ("drm/amdkfd: Check bounds on CRIU restore event id")
+ 6807352cbabb7 ("drm/gfx10: Program DB_RING_CONTROL")
+ 8396b9de4198a ("drm/amdgpu: trigger GPU recovery when userq destroy fails to unmap a hung queue")
+ 873a8d6b3c0a3 ("drm/amd/amdgpu: disable ASPM on VI if pcie dpm is disabled")
+ 8799ba6fb6a48 ("amdkfd: properly free secondary context id")
+ 9d01579f3f868 ("drm/amdgpu: fix lifetime issue of amdgpu_vm_get_task_info_pasid()")
+ c936b8126b444 ("drm/amd/pm: fix smu14 power limit range calculation")
+ d008141ed4ce9 ("nouveau/vmm: fix another SPT/LPT race")
+ e6f2d0b757c4f ("drm/xe: Fix PTE index in xe_vm_populate_pgtable() for chunked binds")
+ ea3fdd1eda088 ("drm/amdgpu: Disable JDPG on VCN5_3")
+ ef71f00173228 ("drm/amdgpu: add support for PSP version 15.0.9")
+$ git merge -m Merge branch 'drm-next' of https://gitlab.freedesktop.org/drm/kernel.git drm/drm-next
+Auto-merging .mailmap
+Auto-merging Documentation/devicetree/bindings/vendor-prefixes.yaml
+Auto-merging MAINTAINERS
+Auto-merging drivers/accel/amdxdna/amdxdna_gem.c
+Auto-merging drivers/gpu/buddy.c
+Auto-merging drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+Auto-merging drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
+Auto-merging drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
+Auto-merging drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+Auto-merging drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
+Auto-merging drivers/gpu/drm/amd/amdgpu/soc21.c
+Auto-merging drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
+Auto-merging drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h
+CONFLICT (content): Merge conflict in drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h
+Auto-merging drivers/gpu/drm/amd/amdkfd/kfd_events.c
+Auto-merging drivers/gpu/drm/amd/amdkfd/kfd_priv.h
+Auto-merging drivers/gpu/drm/amd/amdkfd/kfd_process.c
+Auto-merging drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
+CONFLICT (content): Merge conflict in drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
+Auto-merging drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
+Auto-merging drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
+Auto-merging drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c
+Auto-merging drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+Auto-merging drivers/gpu/drm/drm_fb_helper.c
+Auto-merging drivers/gpu/drm/i915/display/intel_dp.c
+Auto-merging drivers/gpu/drm/i915/display/intel_lt_phy.c
+Auto-merging drivers/gpu/drm/i915/display/intel_psr.c
+Auto-merging drivers/gpu/drm/v3d/v3d_submit.c
+Auto-merging drivers/gpu/drm/xe/tests/xe_pci.c
+Auto-merging drivers/gpu/drm/xe/xe_pt.c
+Auto-merging drivers/gpu/drm/xe/xe_vm_madvise.c
+Auto-merging kernel/events/core.c
+Recorded preimage for 'drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h'
+Recorded preimage for 'drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c'
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit --no-edit -v -a
+Recorded resolution for 'drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h'.
+Recorded resolution for 'drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c'.
+[master 357323b1b3c9b] Merge branch 'drm-next' of https://gitlab.freedesktop.org/drm/kernel.git
+$ git diff -M --stat --summary HEAD^..
+ .mailmap | 1 +
+ .../ABI/testing/sysfs-driver-intel-xe-hwmon | 7 +
+ Documentation/admin-guide/cgroup-v2.rst | 6 +
+ .../bindings/display/panel/anbernic,td4310.yaml | 66 +
+ .../bindings/display/panel/chipone,icna3512.yaml | 79 +
+ .../bindings/display/panel/himax,hx83121a.yaml | 3 +
+ .../bindings/display/panel/ilitek,ili7807s.yaml | 71 +
+ .../bindings/display/panel/ilitek,ili9488.yaml | 63 +
+ .../bindings/display/panel/renesas,r63419.yaml | 98 +
+ .../bindings/display/panel/samsung,atna33xc20.yaml | 2 +
+ .../display/rockchip/rockchip,analogix-dp.yaml | 47 +-
+ .../devicetree/bindings/gpu/img,powervr-rogue.yaml | 3 +-
+ .../devicetree/bindings/gpu/img,powervr-sgx.yaml | 3 +-
+ .../devicetree/bindings/vendor-prefixes.yaml | 6 +
+ Documentation/gpu/automated_testing.rst | 3 +-
+ Documentation/gpu/drm-kms-helpers.rst | 6 +
+ Documentation/gpu/drm-kms.rst | 12 +
+ .../gpu/intel-display/dp-link-training.rst | 8 +
+ Documentation/gpu/intel-display/index.rst | 1 +
+ Documentation/gpu/todo.rst | 50 +-
+ MAINTAINERS | 20 +-
+ drivers/accel/amdxdna/amdxdna_gem.c | 6 +
+ drivers/accel/ethosu/Makefile | 2 +-
+ drivers/accel/ethosu/ethosu_device.h | 35 +-
+ drivers/accel/ethosu/ethosu_drv.c | 23 +-
+ drivers/accel/ethosu/ethosu_drv.h | 61 +-
+ drivers/accel/ethosu/ethosu_job.c | 61 +-
+ drivers/accel/ethosu/ethosu_job.h | 2 +
+ drivers/accel/ethosu/ethosu_perfmon.c | 301 +
+ drivers/accel/ivpu/ivpu_drv.c | 28 +-
+ drivers/accel/ivpu/ivpu_drv.h | 5 +-
+ drivers/accel/ivpu/ivpu_hw.c | 4 +
+ drivers/accel/ivpu/ivpu_ipc.c | 25 +-
+ drivers/accel/ivpu/ivpu_ipc.h | 3 +-
+ drivers/accel/ivpu/ivpu_job.c | 59 +-
+ drivers/accel/ivpu/ivpu_job.h | 7 +-
+ drivers/accel/rocket/rocket_job.c | 32 +-
+ drivers/dma-buf/dma-fence-unwrap.c | 8 +-
+ drivers/dma-buf/dma-fence.c | 22 +-
+ drivers/dma-buf/dma-heap.c | 3 +-
+ drivers/dma-buf/st-dma-fence-chain.c | 4 +-
+ drivers/dma-buf/st-dma-fence-unwrap.c | 42 +-
+ drivers/dma-buf/st-dma-fence.c | 16 +-
+ drivers/dma-buf/st-dma-resv.c | 10 +-
+ drivers/firmware/Kconfig | 28 +-
+ drivers/gpu/buddy.c | 105 +-
+ drivers/gpu/drm/amd/amdgpu/Makefile | 5 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu.h | 319 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c | 985 ---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_aca.h | 232 -
+ drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c | 68 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.h | 151 +
+ drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 14 +
+ drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h | 28 +-
+ .../gpu/drm/amd/amdgpu/amdgpu_amdkfd_gc_9_4_3.c | 63 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v11.c | 3 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12.c | 3 +-
+ .../gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12_1.c | 3 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c | 20 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c | 2 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c | 2 -
+ drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c | 33 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c | 10 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c | 184 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h | 22 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c | 8 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_cper.c | 116 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_cper.h | 8 -
+ drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 70 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c | 215 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h | 14 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c | 7 +
+ drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c | 1 +
+ drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 298 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c | 312 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.h | 6 +
+ drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 27 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c | 53 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c | 290 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h | 24 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c | 9 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h | 1 -
+ drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c | 14 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_ip.c | 151 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_ip.h | 8 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 13 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c | 9 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.h | 3 +
+ drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 39 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_mca.c | 486 --
+ drivers/gpu/drm/amd/amdgpu/amdgpu_mca.h | 108 -
+ drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c | 93 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h | 61 +
+ drivers/gpu/drm/amd/amdgpu/amdgpu_mmhub.h | 23 -
+ drivers/gpu/drm/amd/amdgpu/amdgpu_object.h | 40 -
+ drivers/gpu/drm/amd/amdgpu/amdgpu_preempt_mgr.c | 14 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.c | 5 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c | 987 +--
+ drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h | 70 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c | 514 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h | 26 -
+ drivers/gpu/drm/amd/amdgpu/amdgpu_reg_access.h | 8 +
+ drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c | 206 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h | 8 +
+ drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c | 39 +
+ drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.h | 10 +
+ drivers/gpu/drm/amd/amdgpu/amdgpu_sa.h | 77 +
+ drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c | 8 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c | 19 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h | 28 -
+ drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h | 150 +
+ drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 2 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h | 1 +
+ drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c | 3 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c | 266 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h | 44 -
+ drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.c | 6 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 165 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h | 16 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c | 10 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c | 76 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h | 3 +
+ .../amdgpu_video_codecs.h} | 42 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c | 1 +
+ drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.c | 8 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_wb.c | 129 +
+ drivers/gpu/drm/amd/amdgpu/amdgpu_wb.h | 102 +
+ drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c | 42 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c | 299 +-
+ drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c | 61 +-
+ drivers/gpu/drm/amd/amdgpu/atom.c | 66 +-
+ drivers/gpu/drm/amd/amdgpu/atom.h | 3 +-
+ drivers/gpu/drm/amd/amdgpu/cik.c | 8 +-
+ drivers/gpu/drm/amd/amdgpu/cik_sdma.c | 11 +-
+ drivers/gpu/drm/amd/amdgpu/dce_v10_0.c | 66 -
+ drivers/gpu/drm/amd/amdgpu/dce_v6_0.c | 57 -
+ drivers/gpu/drm/amd/amdgpu/dce_v8_0.c | 57 -
+ drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c | 6 +-
+ drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 369 +-
+ drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c | 264 +-
+ drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c | 8 +-
+ drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 236 +-
+ drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 12 +-
+ drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c | 1097 +--
+ drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c | 2 +-
+ drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c | 125 -
+ drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c | 19 +-
+ drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c | 2 +-
+ drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.h | 4 +
+ drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c | 21 +-
+ drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c | 88 +-
+ drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c | 2 +-
+ drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.h | 4 +
+ drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c | 92 +-
+ drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_2.c | 3 -
+ drivers/gpu/drm/amd/amdgpu/jpeg_v5_3_0.c | 22 +-
+ drivers/gpu/drm/amd/amdgpu/mes_userqueue.c | 151 +-
+ drivers/gpu/drm/amd/amdgpu/mes_userqueue.h | 9 +
+ drivers/gpu/drm/amd/amdgpu/mes_v11_0.c | 246 +-
+ drivers/gpu/drm/amd/amdgpu/mes_v12_0.c | 273 +-
+ drivers/gpu/drm/amd/amdgpu/mes_v12_1.c | 363 +-
+ drivers/gpu/drm/amd/amdgpu/mmhub_v1_8.c | 231 +-
+ drivers/gpu/drm/amd/amdgpu/nv.c | 7 +-
+ drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c | 10 +-
+ drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c | 73 +-
+ drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c | 8 +-
+ drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c | 204 +-
+ drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c | 10 +-
+ drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c | 10 +-
+ drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c | 28 +-
+ drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c | 28 +-
+ drivers/gpu/drm/amd/amdgpu/sdma_v7_1.c | 28 +-
+ drivers/gpu/drm/amd/amdgpu/si.c | 12 +-
+ drivers/gpu/drm/amd/amdgpu/si_dma.c | 8 +-
+ drivers/gpu/drm/amd/amdgpu/soc15.c | 10 +-
+ drivers/gpu/drm/amd/amdgpu/soc15_common.h | 61 +-
+ drivers/gpu/drm/amd/amdgpu/soc21.c | 13 +-
+ drivers/gpu/drm/amd/amdgpu/soc24.c | 12 +-
+ drivers/gpu/drm/amd/amdgpu/soc_v1_0.c | 15 +-
+ drivers/gpu/drm/amd/amdgpu/tonga_ih.c | 40 -
+ drivers/gpu/drm/amd/amdgpu/umc_v12_0.c | 736 +-
+ drivers/gpu/drm/amd/amdgpu/umc_v12_0.h | 31 -
+ drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c | 45 -
+ drivers/gpu/drm/amd/amdgpu/vce_v3_0.c | 69 -
+ drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c | 12 +-
+ drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c | 45 +-
+ drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c | 87 +-
+ drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c | 6 +-
+ drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c | 90 +-
+ drivers/gpu/drm/amd/amdgpu/vcn_v5_0_2.c | 3 -
+ drivers/gpu/drm/amd/amdgpu/vi.c | 23 +-
+ drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 17 +-
+ drivers/gpu/drm/amd/amdkfd/kfd_debugfs.c | 119 +-
+ drivers/gpu/drm/amd/amdkfd/kfd_device.c | 24 +
+ .../gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 223 +-
+ .../gpu/drm/amd/amdkfd/kfd_device_queue_manager.h | 2 +
+ drivers/gpu/drm/amd/amdkfd/kfd_events.c | 224 +-
+ drivers/gpu/drm/amd/amdkfd/kfd_events.h | 4 -
+ drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c | 16 +
+ drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h | 2 +
+ drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c | 14 -
+ drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 32 +-
+ drivers/gpu/drm/amd/amdkfd/kfd_process.c | 147 +-
+ .../gpu/drm/amd/amdkfd/kfd_process_queue_manager.c | 2 +-
+ drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c | 4 +-
+ drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 8 +-
+ drivers/gpu/drm/amd/amdkfd/kfd_topology.c | 11 +-
+ drivers/gpu/drm/amd/amdxcp/amdgpu_xcp_drv.c | 18 +-
+ drivers/gpu/drm/amd/display/amdgpu_dm/Makefile | 6 +-
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 7165 +-------------------
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 79 +-
+ .../drm/amd/display/amdgpu_dm/amdgpu_dm_audio.c | 323 +
+ .../drm/amd/display/amdgpu_dm/amdgpu_dm_audio.h | 56 +
+ .../amd/display/amdgpu_dm/amdgpu_dm_backlight.c | 726 ++
+ .../amd/display/amdgpu_dm/amdgpu_dm_backlight.h | 75 +
+ .../drm/amd/display/amdgpu_dm/amdgpu_dm_color.c | 183 +-
+ .../drm/amd/display/amdgpu_dm/amdgpu_dm_color.h | 8 +-
+ .../drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c | 1 +
+ .../amd/display/amdgpu_dm/amdgpu_dm_connector.c | 3663 ++++++++++
+ .../amd/display/amdgpu_dm/amdgpu_dm_connector.h | 162 +
+ .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c | 102 +-
+ .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h | 6 +
+ .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c | 22 +-
+ .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.h | 6 +
+ .../drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 78 +-
+ .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c | 943 +++
+ .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.h | 68 +
+ .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c | 115 +-
+ .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h | 12 +
+ .../drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 66 +-
+ .../drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.h | 20 +
+ .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c | 1548 ++++-
+ .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h | 27 +
+ .../display/amdgpu_dm/amdgpu_dm_kunit_helpers.h | 1 +
+ .../amd/display/amdgpu_dm/amdgpu_dm_mst_types.c | 189 +-
+ .../amd/display/amdgpu_dm/amdgpu_dm_mst_types.h | 25 +
+ .../drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c | 133 +-
+ .../drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h | 51 +
+ .../drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c | 327 +-
+ .../drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.h | 61 +
+ .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c | 51 +-
+ .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.h | 5 +
+ .../drm/amd/display/amdgpu_dm/amdgpu_dm_quirks.c | 2 +
+ .../drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c | 10 +-
+ .../drm/amd/display/amdgpu_dm/amdgpu_dm_services.c | 7 +
+ .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.c | 16 +-
+ .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.h | 13 +
+ .../drm/amd/display/amdgpu_dm/tests/.kunitconfig | 6 +
+ .../gpu/drm/amd/display/amdgpu_dm/tests/Makefile | 18 +
+ .../display/amdgpu_dm/tests/amdgpu_dm_audio_test.c | 490 ++
+ .../amdgpu_dm/tests/amdgpu_dm_backlight_test.c | 1242 ++++
+ .../display/amdgpu_dm/tests/amdgpu_dm_color_test.c | 64 +-
+ .../amdgpu_dm/tests/amdgpu_dm_colorop_test.c | 140 +-
+ .../amdgpu_dm/tests/amdgpu_dm_connector_test.c | 2158 ++++++
+ .../display/amdgpu_dm/tests/amdgpu_dm_crc_test.c | 122 +
+ .../display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c | 523 ++
+ .../display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c | 582 ++
+ .../display/amdgpu_dm/tests/amdgpu_dm_hdcp_test.c | 297 +-
+ .../amdgpu_dm/tests/amdgpu_dm_helpers_test.c | 634 ++
+ .../display/amdgpu_dm/tests/amdgpu_dm_irq_test.c | 909 +++
+ .../display/amdgpu_dm/tests/amdgpu_dm_ism_test.c | 39 +-
+ .../amdgpu_dm/tests/amdgpu_dm_kunit_helpers.c | 142 +
+ .../amdgpu_dm/tests/amdgpu_dm_kunit_test_helpers.h | 32 +
+ .../amdgpu_dm/tests/amdgpu_dm_mst_types_test.c | 1092 +++
+ .../display/amdgpu_dm/tests/amdgpu_dm_plane_test.c | 1228 ++++
+ .../amdgpu_dm/tests/amdgpu_dm_pp_smu_test.c | 2454 +++++++
+ .../display/amdgpu_dm/tests/amdgpu_dm_psr_test.c | 518 +-
+ .../amdgpu_dm/tests/amdgpu_dm_quirks_test.c | 103 +
+ .../amdgpu_dm/tests/amdgpu_dm_replay_test.c | 432 +-
+ .../amdgpu_dm/tests/amdgpu_dm_services_test.c | 313 +
+ .../amd/display/amdgpu_dm/tests/amdgpu_dm_test.c | 949 +++
+ .../display/amdgpu_dm/tests/amdgpu_dm_wb_test.c | 392 ++
+ .../amd/display/dc/clk_mgr/dcn401/dcn401_clk_mgr.c | 57 +-
+ .../amd/display/dc/clk_mgr/dcn401/dcn401_clk_mgr.h | 9 +
+ drivers/gpu/drm/amd/display/dc/core/dc.c | 293 +-
+ .../gpu/drm/amd/display/dc/core/dc_hw_sequencer.c | 174 +-
+ drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 11 +-
+ drivers/gpu/drm/amd/display/dc/core/dc_surface.c | 44 +-
+ drivers/gpu/drm/amd/display/dc/dc.h | 238 +-
+ drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c | 41 +-
+ drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h | 43 +-
+ drivers/gpu/drm/amd/display/dc/dc_dp_types.h | 1 +
+ drivers/gpu/drm/amd/display/dc/dc_helper.c | 226 -
+ drivers/gpu/drm/amd/display/dc/dc_stream.h | 29 +
+ drivers/gpu/drm/amd/display/dc/dc_types.h | 67 +-
+ .../gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.c | 59 +-
+ .../gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.h | 1 +
+ drivers/gpu/drm/amd/display/dc/dce/dce_aux.c | 9 +-
+ .../drm/amd/display/dc/dce110/dce110_compressor.c | 2 -
+ .../drm/amd/display/dc/dce110/dce110_mem_input_v.c | 2 -
+ .../drm/amd/display/dc/dce112/dce112_compressor.c | 8 +-
+ .../gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c | 184 +
+ .../display/dc/dio/dcn31/dcn31_dio_link_encoder.c | 4 +
+ .../display/dc/dio/dcn31/dcn31_dio_link_encoder.h | 2 +
+ drivers/gpu/drm/amd/display/dc/dm_services.h | 4 -
+ .../gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c | 2 +-
+ .../amd/display/dc/dml/dcn31/display_mode_vba_31.c | 2 +-
+ .../display/dc/dml/dcn314/display_mode_vba_314.c | 2 +-
+ .../display/dc/dml2_0/dml21/dml21_wrapper_fpu.c | 8 +-
+ .../dml21/inc/bounding_boxes/dcn42b_soc_bb.h | 40 +-
+ .../dml2_0/dml21/inc/dml_top_soc_parameter_types.h | 13 +
+ .../dml21/src/dml2_core/dml2_core_dcn4_calcs.c | 41 +-
+ .../dml2_0/dml21/src/dml2_core/dml2_core_factory.c | 2 -
+ .../dml21/src/dml2_core/dml2_core_shared_types.h | 2 -
+ .../dml21/src/inc/dml2_internal_shared_types.h | 1 -
+ .../drm/amd/display/dc/dpp/dcn10/dcn10_dpp_cm.c | 5 -
+ .../drm/amd/display/dc/dwb/dcn30/dcn30_cm_common.h | 4 +
+ .../amd/display/dc/gpio/dce80/hw_translate_dce80.c | 5 +-
+ .../amd/display/dc/gpio/dcn10/hw_translate_dcn10.c | 484 +-
+ .../amd/display/dc/gpio/dcn20/hw_translate_dcn20.c | 434 +-
+ .../amd/display/dc/gpio/dcn21/hw_translate_dcn21.c | 419 +-
+ .../amd/display/dc/gpio/dcn30/hw_translate_dcn30.c | 434 +-
+ .../display/dc/gpio/dcn315/hw_translate_dcn315.c | 420 +-
+ .../amd/display/dc/gpio/dcn32/hw_translate_dcn32.c | 386 +-
+ .../display/dc/gpio/dcn401/hw_translate_dcn401.c | 394 +-
+ .../amd/display/dc/gpio/dcn42/hw_translate_dcn42.c | 191 +-
+ drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c | 86 +
+ drivers/gpu/drm/amd/display/dc/gpio/hw_translate.h | 21 +
+ .../drm/amd/display/dc/hubbub/dcn31/dcn31_hubbub.c | 8 +-
+ .../drm/amd/display/dc/hubbub/dcn35/dcn35_hubbub.c | 2 +-
+ .../drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c | 2 +-
+ .../gpu/drm/amd/display/dc/hubp/dcn42/dcn42_hubp.c | 6 +
+ .../drm/amd/display/dc/hwss/dce110/dce110_hwseq.c | 8 +-
+ .../drm/amd/display/dc/hwss/dce60/dce60_hwseq.c | 8 +-
+ .../drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c | 62 +-
+ .../drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c | 76 +-
+ .../drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.c | 2 +-
+ .../drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c | 10 +-
+ .../drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c | 36 +-
+ .../drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c | 3 -
+ .../drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 341 +-
+ .../drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h | 12 +-
+ .../drm/amd/display/dc/hwss/dcn401/dcn401_init.c | 2 +
+ .../drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c | 327 +-
+ .../drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.h | 5 +-
+ drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h | 82 +
+ .../drm/amd/display/dc/hwss/hw_sequencer_private.h | 3 +-
+ drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h | 12 +
+ drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h | 1 +
+ drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h | 2 +-
+ drivers/gpu/drm/amd/display/dc/inc/link_service.h | 1 +
+ drivers/gpu/drm/amd/display/dc/inc/reg_helper.h | 19 -
+ .../drm/amd/display/dc/inc/soc_and_ip_translator.h | 14 -
+ .../gpu/drm/amd/display/dc/link/link_detection.c | 2 +-
+ drivers/gpu/drm/amd/display/dc/link/link_factory.c | 7 +-
+ .../drm/amd/display/dc/link/protocols/link_ddc.c | 20 +-
+ .../drm/amd/display/dc/link/protocols/link_ddc.h | 2 +
+ .../display/dc/link/protocols/link_dp_capability.c | 14 +-
+ .../dc/link/protocols/link_dp_panel_replay.c | 3 +-
+ .../dc/link/protocols/link_edp_panel_control.c | 8 +-
+ .../gpu/drm/amd/display/dc/mpc/dcn20/dcn20_mpc.c | 4 -
+ .../gpu/drm/amd/display/dc/opp/dcn20/dcn20_opp.c | 51 +-
+ .../gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.c | 5 -
+ .../gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.c | 5 -
+ .../gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c | 5 -
+ .../drm/amd/display/dc/optc/dcn314/dcn314_optc.c | 5 -
+ .../gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c | 5 -
+ .../gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c | 5 -
+ .../drm/amd/display/dc/optc/dcn401/dcn401_optc.c | 5 -
+ .../drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.c | 258 +-
+ .../drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.h | 22 +-
+ .../amd/display/dc/resource/dcn30/dcn30_resource.c | 1 -
+ .../display/dc/resource/dcn302/dcn302_resource.c | 1 -
+ .../display/dc/resource/dcn303/dcn303_resource.c | 1 -
+ .../amd/display/dc/resource/dcn31/dcn31_resource.c | 5 +-
+ .../display/dc/resource/dcn314/dcn314_resource.c | 4 +-
+ .../display/dc/resource/dcn315/dcn315_resource.c | 5 +-
+ .../display/dc/resource/dcn316/dcn316_resource.c | 5 +-
+ .../amd/display/dc/resource/dcn32/dcn32_resource.c | 1 -
+ .../display/dc/resource/dcn321/dcn321_resource.c | 1 -
+ .../amd/display/dc/resource/dcn35/dcn35_resource.c | 6 +-
+ .../display/dc/resource/dcn351/dcn351_resource.c | 6 +-
+ .../amd/display/dc/resource/dcn36/dcn36_resource.c | 6 +-
+ .../amd/display/dc/resource/dcn42/dcn42_resource.c | 5 +-
+ .../display/dc/resource/dcn42b/dcn42b_resource.c | 6 +-
+ .../amd/display/dc/soc_and_ip_translator/Makefile | 3 +
+ .../dcn42/dcn42_soc_and_ip_translator.c | 18 +-
+ .../dcn42/dcn42_soc_and_ip_translator.h | 1 +
+ .../dcn42b/dcn42b_soc_and_ip_translator.c | 42 +
+ .../dcn42b/dcn42b_soc_and_ip_translator.h | 17 +
+ .../soc_and_ip_translator/soc_and_ip_translator.c | 5 +-
+ drivers/gpu/drm/amd/display/dc/sspl/spl_debug.h | 4 +-
+ drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 289 +-
+ .../drm/amd/display/include/ddc_service_types.h | 1 +
+ drivers/gpu/drm/amd/display/include/gpio_types.h | 48 +
+ drivers/gpu/drm/amd/display/modules/power/Makefile | 2 +-
+ drivers/gpu/drm/amd/display/modules/power/power.c | 12 +-
+ .../gpu/drm/amd/display/modules/power/power_abm.c | 14 +-
+ .../drm/amd/display/modules/power/power_replay.c | 9 +-
+ drivers/gpu/drm/amd/include/amd_shared.h | 3 -
+ .../amd/include/asic_reg/sdma/sdma_4_4_2_offset.h | 4 +
+ drivers/gpu/drm/amd/include/kgd_kfd_interface.h | 3 +
+ drivers/gpu/drm/amd/include/mes_v11_api_def.h | 5 +-
+ drivers/gpu/drm/amd/include/mes_v12_api_def.h | 5 +-
+ drivers/gpu/drm/amd/include/soc15_hw_ip.h | 1 +
+ drivers/gpu/drm/amd/include/v9_structs.h | 4 +-
+ drivers/gpu/drm/amd/pm/amdgpu_dpm.c | 7 -
+ drivers/gpu/drm/amd/pm/amdgpu_pm.c | 116 +-
+ drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h | 1 -
+ drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c | 21 +-
+ .../gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c | 38 +-
+ .../gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c | 11 +-
+ .../amd/pm/powerplay/hwmgr/process_pptables_v1_0.c | 753 +-
+ .../drm/amd/pm/powerplay/hwmgr/processpptables.c | 450 +-
+ .../gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c | 60 +-
+ .../gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c | 83 +-
+ .../pm/powerplay/hwmgr/vega10_processpptables.c | 761 ++-
+ .../pm/powerplay/hwmgr/vega12_processpptables.c | 7 +
+ .../pm/powerplay/hwmgr/vega20_processpptables.c | 7 +
+ drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h | 17 +
+ drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 45 +-
+ drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 45 +-
+ drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h | 2 -
+ drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h | 6 -
+ drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h | 4 -
+ drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h | 4 -
+ drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 8 +-
+ drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 8 +-
+ .../drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 8 +-
+ drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c | 82 +-
+ drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c | 1 -
+ drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 1 -
+ drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c | 94 +-
+ .../gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 7 +-
+ .../gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c | 136 -
+ .../gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c | 674 --
+ .../gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h | 1 -
+ .../gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 7 +-
+ drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c | 85 +-
+ .../gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 9 +-
+ drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c | 85 +-
+ drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 140 +
+ drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h | 13 +
+ drivers/gpu/drm/amd/pm/swsmu/smu_internal.h | 1 -
+ drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_cmd.c | 3 -
+ .../drm/amd/ras/ras_mgr/amdgpu_ras_eeprom_i2c.c | 2 +-
+ drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c | 76 +-
+ drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.h | 2 +
+ .../gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mp1_v13_0.c | 14 +
+ drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_sys.c | 19 +
+ drivers/gpu/drm/amd/ras/ras_mgr/ras_sys.h | 3 +
+ drivers/gpu/drm/amd/ras/rascore/ras.h | 5 +
+ drivers/gpu/drm/amd/ras/rascore/ras_aca_v1_0.c | 13 +-
+ drivers/gpu/drm/amd/ras/rascore/ras_core.c | 15 +
+ drivers/gpu/drm/amd/ras/rascore/ras_eeprom.c | 3 +
+ drivers/gpu/drm/amd/ras/rascore/ras_eeprom_fw.c | 2 +-
+ drivers/gpu/drm/amd/ras/rascore/ras_mp1.c | 19 +-
+ drivers/gpu/drm/amd/ras/rascore/ras_mp1.h | 3 +
+ drivers/gpu/drm/amd/ras/rascore/ras_mp1_v13_0.c | 13 +
+ drivers/gpu/drm/amd/ras/rascore/ras_process.c | 5 +-
+ drivers/gpu/drm/amd/ras/rascore/ras_umc.c | 32 +-
+ drivers/gpu/drm/amd/ras/rascore/ras_umc.h | 6 +
+ drivers/gpu/drm/amd/ras/rascore/ras_umc_v12_0.h | 2 +
+ drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 2 +-
+ drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 19 +-
+ drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 6 +-
+ drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 32 +-
+ drivers/gpu/drm/bridge/analogix/anx7625.c | 2 +-
+ drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c | 9 +-
+ .../gpu/drm/bridge/cadence/cdns-mhdp8546-core.c | 8 +-
+ drivers/gpu/drm/bridge/chipone-icn6211.c | 2 +-
+ drivers/gpu/drm/bridge/display-connector.c | 38 +-
+ drivers/gpu/drm/bridge/fsl-ldb.c | 2 +-
+ drivers/gpu/drm/bridge/imx/imx8mp-hdmi-pvi.c | 2 +-
+ drivers/gpu/drm/bridge/imx/imx8qm-ldb.c | 2 +-
+ drivers/gpu/drm/bridge/imx/imx8qxp-ldb.c | 2 +-
+ .../gpu/drm/bridge/imx/imx8qxp-pixel-combiner.c | 2 +-
+ drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c | 2 +-
+ drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c | 2 +-
+ drivers/gpu/drm/bridge/inno-hdmi.c | 2 +-
+ drivers/gpu/drm/bridge/ite-it6263.c | 2 +-
+ drivers/gpu/drm/bridge/ite-it6505.c | 2 +-
+ drivers/gpu/drm/bridge/ite-it66121.c | 2 +-
+ drivers/gpu/drm/bridge/lontium-lt9211.c | 2 +-
+ drivers/gpu/drm/bridge/lontium-lt9611.c | 2 +-
+ drivers/gpu/drm/bridge/lvds-codec.c | 2 +-
+ drivers/gpu/drm/bridge/nwl-dsi.c | 2 +-
+ drivers/gpu/drm/bridge/of-display-mode-bridge.c | 2 +-
+ drivers/gpu/drm/bridge/panel.c | 2 +-
+ drivers/gpu/drm/bridge/parade-ps8640.c | 2 +-
+ drivers/gpu/drm/bridge/samsung-dsim.c | 2 +-
+ drivers/gpu/drm/bridge/sii902x.c | 6 +-
+ drivers/gpu/drm/bridge/ssd2825.c | 2 +-
+ drivers/gpu/drm/bridge/synopsys/dw-dp.c | 8 +-
+ drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 3 +-
+ drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 2 +-
+ drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 2 +-
+ drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi2.c | 2 +-
+ drivers/gpu/drm/bridge/tc358762.c | 2 +-
+ drivers/gpu/drm/bridge/tc358767.c | 4 +-
+ drivers/gpu/drm/bridge/tc358768.c | 2 +-
+ drivers/gpu/drm/bridge/tc358775.c | 2 +-
+ drivers/gpu/drm/bridge/ti-dlpc3433.c | 2 +-
+ drivers/gpu/drm/bridge/ti-sn65dsi83.c | 3 +-
+ drivers/gpu/drm/bridge/ti-sn65dsi86.c | 2 +-
+ drivers/gpu/drm/bridge/ti-tdp158.c | 2 +-
+ drivers/gpu/drm/bridge/ti-tfp410.c | 2 +-
+ drivers/gpu/drm/clients/drm_log.c | 10 +-
+ drivers/gpu/drm/display/drm_bridge_connector.c | 41 +-
+ drivers/gpu/drm/display/drm_hdmi_state_helper.c | 68 +-
+ drivers/gpu/drm/drm_atomic.c | 80 +
+ drivers/gpu/drm/drm_atomic_helper.c | 86 +
+ drivers/gpu/drm/drm_atomic_state_helper.c | 154 +-
+ drivers/gpu/drm/drm_atomic_uapi.c | 4 +
+ drivers/gpu/drm/drm_bridge.c | 124 +-
+ drivers/gpu/drm/drm_buddy.c | 30 +-
+ drivers/gpu/drm/drm_colorop.c | 41 +-
+ drivers/gpu/drm/drm_connector.c | 192 +-
+ drivers/gpu/drm/drm_displayid_internal.h | 24 +
+ drivers/gpu/drm/drm_draw_internal.h | 7 -
+ drivers/gpu/drm/drm_drv.c | 4 +-
+ drivers/gpu/drm/drm_dumb_buffers.c | 1 -
+ drivers/gpu/drm/drm_edid.c | 80 +-
+ drivers/gpu/drm/drm_exec.c | 2 +-
+ drivers/gpu/drm/drm_fb_helper.c | 11 +-
+ drivers/gpu/drm/drm_gem.c | 3 +-
+ drivers/gpu/drm/drm_gem_shmem_helper.c | 22 +-
+ drivers/gpu/drm/drm_gpuvm.c | 44 -
+ drivers/gpu/drm/drm_mode_config.c | 189 +-
+ drivers/gpu/drm/drm_modes.c | 23 +
+ drivers/gpu/drm/drm_of.c | 44 +
+ drivers/gpu/drm/drm_panel.c | 44 +-
+ drivers/gpu/drm/drm_panic.c | 6 +-
+ drivers/gpu/drm/drm_print.c | 4 +-
+ drivers/gpu/drm/drm_syncobj.c | 2 +-
+ drivers/gpu/drm/drm_writeback.c | 6 +
+ drivers/gpu/drm/gma500/psb_drv.c | 56 +-
+ drivers/gpu/drm/hisilicon/hibmc/Kconfig | 4 +-
+ drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c | 114 +-
+ drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c | 78 +-
+ drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h | 5 +
+ drivers/gpu/drm/hyperv/hyperv_drm.h | 16 +-
+ drivers/gpu/drm/hyperv/hyperv_drm_drv.c | 92 +-
+ drivers/gpu/drm/hyperv/hyperv_drm_modeset.c | 110 +-
+ drivers/gpu/drm/hyperv/hyperv_drm_proto.c | 70 +-
+ drivers/gpu/drm/i915/Makefile | 5 +-
+ drivers/gpu/drm/i915/display/g4x_dp.c | 15 +-
+ drivers/gpu/drm/i915/display/g4x_hdmi.c | 4 +-
+ drivers/gpu/drm/i915/display/icl_dsi.c | 5 +-
+ drivers/gpu/drm/i915/display/intel_alpm.c | 15 +-
+ drivers/gpu/drm/i915/display/intel_bios.c | 62 +-
+ drivers/gpu/drm/i915/display/intel_bw.c | 168 +-
+ drivers/gpu/drm/i915/display/intel_cdclk.c | 54 +-
+ drivers/gpu/drm/i915/display/intel_cmtg.c | 280 +-
+ drivers/gpu/drm/i915/display/intel_cmtg.h | 19 +-
+ drivers/gpu/drm/i915/display/intel_cmtg_regs.h | 24 +-
+ drivers/gpu/drm/i915/display/intel_color.c | 115 +-
+ drivers/gpu/drm/i915/display/intel_crt.c | 9 +-
+ drivers/gpu/drm/i915/display/intel_crtc.c | 2 +-
+ drivers/gpu/drm/i915/display/intel_cursor.c | 2 +-
+ drivers/gpu/drm/i915/display/intel_cx0_phy.c | 11 +
+ drivers/gpu/drm/i915/display/intel_cx0_phy.h | 1 -
+ drivers/gpu/drm/i915/display/intel_ddi.c | 29 +-
+ drivers/gpu/drm/i915/display/intel_de.c | 40 +-
+ drivers/gpu/drm/i915/display/intel_display.c | 170 +-
+ drivers/gpu/drm/i915/display/intel_display.h | 7 +
+ drivers/gpu/drm/i915/display/intel_display_core.h | 14 +-
+ .../gpu/drm/i915/display/intel_display_debugfs.c | 2 +
+ .../gpu/drm/i915/display/intel_display_device.c | 14 +
+ .../gpu/drm/i915/display/intel_display_device.h | 3 +-
+ .../gpu/drm/i915/display/intel_display_driver.c | 131 +-
+ .../gpu/drm/i915/display/intel_display_driver.h | 9 +-
+ drivers/gpu/drm/i915/display/intel_display_irq.c | 19 +
+ drivers/gpu/drm/i915/display/intel_display_irq.h | 2 +
+ .../gpu/drm/i915/display/intel_display_limits.h | 2 +
+ drivers/gpu/drm/i915/display/intel_display_power.c | 185 +-
+ drivers/gpu/drm/i915/display/intel_display_power.h | 40 +
+ .../drm/i915/display/intel_display_power_well.c | 76 +-
+ .../drm/i915/display/intel_display_power_well.h | 1 +
+ drivers/gpu/drm/i915/display/intel_display_regs.h | 46 +-
+ drivers/gpu/drm/i915/display/intel_display_types.h | 57 +-
+ drivers/gpu/drm/i915/display/intel_dmc.c | 15 +-
+ drivers/gpu/drm/i915/display/intel_dmc_regs.h | 2 +
+ drivers/gpu/drm/i915/display/intel_dmc_wl.c | 2 +-
+ drivers/gpu/drm/i915/display/intel_dp.c | 539 +-
+ drivers/gpu/drm/i915/display/intel_dp.h | 16 +-
+ drivers/gpu/drm/i915/display/intel_dp_link_caps.c | 675 ++
+ drivers/gpu/drm/i915/display/intel_dp_link_caps.h | 47 +
+ .../gpu/drm/i915/display/intel_dp_link_training.c | 1093 ++-
+ .../gpu/drm/i915/display/intel_dp_link_training.h | 15 +
+ drivers/gpu/drm/i915/display/intel_dp_mst.c | 8 +-
+ drivers/gpu/drm/i915/display/intel_dp_test.c | 7 +-
+ drivers/gpu/drm/i915/display/intel_dp_tunnel.c | 6 +-
+ drivers/gpu/drm/i915/display/intel_dsb.c | 32 +-
+ drivers/gpu/drm/i915/display/intel_dvo.c | 5 +-
+ drivers/gpu/drm/i915/display/intel_gmbus.c | 148 +-
+ drivers/gpu/drm/i915/display/intel_gmbus.h | 22 +-
+ drivers/gpu/drm/i915/display/intel_hdmi.c | 71 +-
+ drivers/gpu/drm/i915/display/intel_hdmi.h | 2 +
+ drivers/gpu/drm/i915/display/intel_initial_plane.c | 2 +-
+ drivers/gpu/drm/i915/display/intel_lpe_audio.c | 4 +-
+ drivers/gpu/drm/i915/display/intel_lt_phy.c | 14 +-
+ drivers/gpu/drm/i915/display/intel_lvds.c | 5 +-
+ drivers/gpu/drm/i915/display/intel_panel.c | 170 +-
+ drivers/gpu/drm/i915/display/intel_panel.h | 6 +-
+ drivers/gpu/drm/i915/display/intel_parent.c | 6 +-
+ drivers/gpu/drm/i915/display/intel_parent.h | 4 +-
+ drivers/gpu/drm/i915/display/intel_plane.c | 54 +-
+ drivers/gpu/drm/i915/display/intel_plane.h | 5 +-
+ drivers/gpu/drm/i915/display/intel_psr.c | 264 +-
+ drivers/gpu/drm/i915/display/intel_psr.h | 1 +
+ drivers/gpu/drm/i915/display/intel_psr_regs.h | 1 +
+ drivers/gpu/drm/i915/display/intel_sdvo.c | 7 +-
+ drivers/gpu/drm/i915/display/intel_tv.c | 5 +-
+ drivers/gpu/drm/i915/display/intel_vrr.c | 29 +-
+ drivers/gpu/drm/i915/display/intel_vrr.h | 4 +-
+ drivers/gpu/drm/i915/display/vlv_dsi.c | 5 +-
+ drivers/gpu/drm/i915/gem/i915_gem_object.h | 7 -
+ drivers/gpu/drm/i915/gem/i915_gem_pages.c | 128 -
+ drivers/gpu/drm/i915/gem/i915_gem_panic.c | 147 +
+ drivers/gpu/drm/i915/gem/i915_gem_panic.h | 11 +
+ drivers/gpu/drm/i915/gt/intel_gsc.c | 2 +-
+ drivers/gpu/drm/i915/gvt/edid.c | 14 +-
+ drivers/gpu/drm/i915/i915_active.c | 2 +-
+ drivers/gpu/drm/i915/i915_driver.c | 123 +-
+ drivers/gpu/drm/i915/i915_panic.c | 35 -
+ drivers/gpu/drm/i915/i915_panic.h | 9 -
+ drivers/gpu/drm/imagination/pvr_drv.c | 2 +-
+ drivers/gpu/drm/imx/ipuv3/parallel-display.c | 2 +-
+ drivers/gpu/drm/ingenic/ingenic-drm-drv.c | 2 +-
+ drivers/gpu/drm/lima/lima_device.c | 12 +-
+ drivers/gpu/drm/loongson/lsdc_drv.c | 4 +-
+ drivers/gpu/drm/mediatek/mtk_dp.c | 2 +-
+ drivers/gpu/drm/mediatek/mtk_dpi.c | 2 +-
+ drivers/gpu/drm/mediatek/mtk_dsi.c | 2 +-
+ drivers/gpu/drm/mediatek/mtk_hdmi.c | 2 +-
+ drivers/gpu/drm/mediatek/mtk_hdmi_v2.c | 2 +-
+ drivers/gpu/drm/meson/meson_encoder_cvbs.c | 2 +-
+ drivers/gpu/drm/meson/meson_encoder_dsi.c | 2 +-
+ drivers/gpu/drm/meson/meson_encoder_hdmi.c | 2 +-
+ drivers/gpu/drm/mgag200/mgag200_drv.c | 24 +-
+ drivers/gpu/drm/msm/dp/dp_drm.c | 4 +-
+ drivers/gpu/drm/msm/dsi/dsi_host.c | 25 +-
+ drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 2 +-
+ drivers/gpu/drm/msm/msm_drv.c | 2 -
+ drivers/gpu/drm/mxsfb/lcdif_drv.c | 2 +-
+ drivers/gpu/drm/mxsfb/lcdif_kms.c | 18 +-
+ drivers/gpu/drm/mxsfb/lcdif_regs.h | 1 +
+ drivers/gpu/drm/nouveau/nouveau_drm.c | 35 +-
+ drivers/gpu/drm/nouveau/nouveau_gem.c | 11 +-
+ drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c | 4 +-
+ drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h | 2 +
+ .../gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/disp.c | 8 +-
+ drivers/gpu/drm/omapdrm/dss/hdmi4.c | 2 +-
+ drivers/gpu/drm/omapdrm/dss/hdmi5.c | 2 +-
+ drivers/gpu/drm/panel/Kconfig | 56 +
+ drivers/gpu/drm/panel/Makefile | 5 +
+ drivers/gpu/drm/panel/panel-anbernic-td4310.c | 258 +
+ .../gpu/drm/panel/panel-boe-th101mb31ig002-28a.c | 3 +-
+ drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c | 3 +-
+ drivers/gpu/drm/panel/panel-chipone-icna35xx.c | 423 ++
+ drivers/gpu/drm/panel/panel-chipwealth-ch13726a.c | 3 +-
+ drivers/gpu/drm/panel/panel-edp.c | 24 +-
+ drivers/gpu/drm/panel/panel-elida-kd35t133.c | 3 +-
+ drivers/gpu/drm/panel/panel-focaltech-ota7290b.c | 3 +-
+ drivers/gpu/drm/panel/panel-himax-hx83102.c | 3 +-
+ drivers/gpu/drm/panel/panel-himax-hx83121a.c | 39 +-
+ drivers/gpu/drm/panel/panel-himax-hx8394.c | 3 +-
+ drivers/gpu/drm/panel/panel-ilitek-ili7807s.c | 285 +
+ drivers/gpu/drm/panel/panel-ilitek-ili9488.c | 290 +
+ drivers/gpu/drm/panel/panel-ilitek-ili9806e-dsi.c | 3 +-
+ drivers/gpu/drm/panel/panel-ilitek-ili9881c.c | 3 +-
+ drivers/gpu/drm/panel/panel-ilitek-ili9882t.c | 3 +-
+ drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c | 2 +-
+ drivers/gpu/drm/panel/panel-lvds.c | 2 +-
+ drivers/gpu/drm/panel/panel-novatek-nt36523.c | 3 +-
+ drivers/gpu/drm/panel/panel-novatek-nt36672a.c | 522 +-
+ drivers/gpu/drm/panel/panel-renesas-r63419.c | 351 +
+ drivers/gpu/drm/panel/panel-simple.c | 2 +-
+ drivers/gpu/drm/panel/panel-sitronix-st7701.c | 3 +-
+ drivers/gpu/drm/panel/panel-sitronix-st7703.c | 3 +-
+ drivers/gpu/drm/panel/panel-sitronix-st7789v.c | 3 +-
+ drivers/gpu/drm/panel/panel-visionox-vtdr6130.c | 42 +-
+ drivers/gpu/drm/panthor/panthor_device.h | 3 +
+ drivers/gpu/drm/panthor/panthor_drv.c | 14 +-
+ drivers/gpu/drm/panthor/panthor_gem.c | 18 +
+ drivers/gpu/drm/panthor/panthor_gem.h | 2 +
+ drivers/gpu/drm/panthor/panthor_mmu.c | 259 +-
+ drivers/gpu/drm/qxl/qxl_drv.c | 15 +-
+ drivers/gpu/drm/radeon/r600_dpm.c | 21 +-
+ drivers/gpu/drm/renesas/rcar-du/rcar_du_drv.c | 20 +-
+ drivers/gpu/drm/renesas/rcar-du/rcar_lvds.c | 2 +-
+ drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c | 2 +-
+ drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c | 2 +-
+ drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 40 +-
+ drivers/gpu/drm/rockchip/cdn-dp-core.c | 11 +-
+ drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c | 9 +-
+ drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c | 8 +-
+ drivers/gpu/drm/rockchip/dw_dp-rockchip.c | 16 +-
+ drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 228 +-
+ drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 112 +-
+ drivers/gpu/drm/rockchip/rk3066_hdmi.c | 10 +-
+ drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 4 +
+ drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 176 +-
+ drivers/gpu/drm/rockchip/rockchip_drm_vop2.h | 2 +-
+ drivers/gpu/drm/rockchip/rockchip_lvds.c | 11 +-
+ drivers/gpu/drm/rockchip/rockchip_rgb.c | 8 +-
+ drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 46 +-
+ drivers/gpu/drm/scheduler/sched_entity.c | 11 +-
+ drivers/gpu/drm/scheduler/sched_main.c | 9 -
+ drivers/gpu/drm/scheduler/tests/tests_basic.c | 359 +
+ drivers/gpu/drm/scheduler/tests/tests_scheduler.c | 2 +-
+ drivers/gpu/drm/solomon/ssd130x.c | 360 +-
+ drivers/gpu/drm/stm/lvds.c | 2 +-
+ drivers/gpu/drm/sun4i/sun4i_backend.c | 2 +-
+ drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c | 11 +-
+ drivers/gpu/drm/sun4i/sun4i_lvds.c | 10 +-
+ drivers/gpu/drm/sun4i/sun4i_rgb.c | 10 +-
+ drivers/gpu/drm/sun4i/sun4i_tv.c | 10 +-
+ drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 10 +-
+ drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c | 8 +-
+ drivers/gpu/drm/sysfb/Kconfig | 7 +-
+ drivers/gpu/drm/sysfb/simpledrm.c | 120 +-
+ drivers/gpu/drm/tegra/drm.c | 2 +
+ drivers/gpu/drm/tegra/dsi.c | 126 +-
+ drivers/gpu/drm/tegra/dsi.h | 10 +
+ drivers/gpu/drm/tests/Makefile | 3 +-
+ drivers/gpu/drm/tests/drm_bridge_test.c | 973 ++-
+ drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 347 +-
+ drivers/gpu/drm/tests/drm_kunit_edid.c | 995 +++
+ drivers/gpu/drm/tests/drm_kunit_edid.h | 985 +--
+ drivers/gpu/drm/tidss/tidss_crtc.c | 17 +-
+ drivers/gpu/drm/tidss/tidss_encoder.c | 2 +-
+ drivers/gpu/drm/tidss/tidss_oldi.c | 2 +-
+ drivers/gpu/drm/tidss/tidss_plane.c | 2 +-
+ drivers/gpu/drm/tiny/gm12u320.c | 5 +-
+ drivers/gpu/drm/ttm/tests/ttm_bo_validate_test.c | 2 +-
+ drivers/gpu/drm/ttm/ttm_bo.c | 2 +-
+ drivers/gpu/drm/ttm/ttm_pool.c | 37 +-
+ drivers/gpu/drm/v3d/Kconfig | 1 +
+ drivers/gpu/drm/v3d/v3d_drv.c | 20 +-
+ drivers/gpu/drm/v3d/v3d_drv.h | 83 +-
+ drivers/gpu/drm/v3d/v3d_gem.c | 7 +-
+ drivers/gpu/drm/v3d/v3d_irq.c | 7 +-
+ drivers/gpu/drm/v3d/v3d_perfmon.c | 189 +-
+ drivers/gpu/drm/v3d/v3d_power.c | 4 +
+ drivers/gpu/drm/v3d/v3d_sched.c | 103 +-
+ drivers/gpu/drm/v3d/v3d_submit.c | 966 +--
+ drivers/gpu/drm/vc4/vc4_dsi.c | 2 +-
+ drivers/gpu/drm/vc4/vc4_hdmi.c | 2 +-
+ drivers/gpu/drm/verisilicon/vs_bridge.c | 4 +-
+ drivers/gpu/drm/virtio/virtgpu_drv.c | 101 +-
+ drivers/gpu/drm/virtio/virtgpu_drv.h | 26 +-
+ drivers/gpu/drm/virtio/virtgpu_kms.c | 71 +-
+ drivers/gpu/drm/virtio/virtgpu_object.c | 90 +-
+ drivers/gpu/drm/virtio/virtgpu_prime.c | 45 +-
+ drivers/gpu/drm/virtio/virtgpu_vq.c | 50 +-
+ drivers/gpu/drm/virtio/virtgpu_vram.c | 5 +-
+ drivers/gpu/drm/xe/Kconfig.profile | 71 +-
+ drivers/gpu/drm/xe/Makefile | 2 +
+ drivers/gpu/drm/xe/display/xe_display.c | 244 +-
+ drivers/gpu/drm/xe/display/xe_display.h | 10 +-
+ drivers/gpu/drm/xe/display/xe_panic.c | 26 +-
+ drivers/gpu/drm/xe/tests/Makefile | 1 +
+ drivers/gpu/drm/xe/tests/xe_pci.c | 53 +-
+ drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c | 112 +
+ drivers/gpu/drm/xe/tests/xe_rtp_test.c | 52 +
+ drivers/gpu/drm/xe/tests/xe_wa_test.c | 3 -
+ drivers/gpu/drm/xe/xe_bo.c | 2 +-
+ drivers/gpu/drm/xe/xe_debugfs.c | 1 -
+ drivers/gpu/drm/xe/xe_device.c | 38 +-
+ drivers/gpu/drm/xe/xe_device.h | 17 +-
+ drivers/gpu/drm/xe/xe_device_types.h | 10 +-
+ drivers/gpu/drm/xe/xe_drm_client.c | 5 +-
+ drivers/gpu/drm/xe/xe_drm_ras.c | 41 +-
+ drivers/gpu/drm/xe/xe_eu_stall.c | 5 +-
+ drivers/gpu/drm/xe/xe_exec_queue_types.h | 2 -
+ drivers/gpu/drm/xe/xe_execlist.c | 7 -
+ drivers/gpu/drm/xe/xe_ggtt.c | 8 +-
+ drivers/gpu/drm/xe/xe_gt.c | 14 +-
+ drivers/gpu/drm/xe/xe_gt_mcr.c | 19 +-
+ drivers/gpu/drm/xe/xe_guc_submit.c | 18 +-
+ drivers/gpu/drm/xe/xe_guc_tlb_inval.c | 6 -
+ drivers/gpu/drm/xe/xe_hw_engine.c | 218 +-
+ drivers/gpu/drm/xe/xe_hw_error.c | 23 +-
+ drivers/gpu/drm/xe/xe_i2c.c | 3 -
+ drivers/gpu/drm/xe/xe_lrc.c | 8 +-
+ drivers/gpu/drm/xe/xe_mmio.c | 100 +-
+ drivers/gpu/drm/xe/xe_module.c | 3 -
+ drivers/gpu/drm/xe/xe_module.h | 1 -
+ drivers/gpu/drm/xe/xe_oa.c | 25 +-
+ drivers/gpu/drm/xe/xe_observation.c | 32 +-
+ drivers/gpu/drm/xe/xe_observation.h | 3 +-
+ drivers/gpu/drm/xe/xe_pci.c | 176 +-
+ drivers/gpu/drm/xe/xe_pci_error.c | 122 +
+ drivers/gpu/drm/xe/xe_pci_error.h | 13 +
+ drivers/gpu/drm/xe/xe_pci_types.h | 1 +
+ drivers/gpu/drm/xe/xe_pcode.c | 8 +-
+ drivers/gpu/drm/xe/xe_pcode.h | 2 +-
+ drivers/gpu/drm/xe/xe_pt.c | 6 +
+ drivers/gpu/drm/xe/xe_pxp.c | 35 +-
+ drivers/gpu/drm/xe/xe_query.c | 7 +-
+ drivers/gpu/drm/xe/xe_ras.c | 260 +
+ drivers/gpu/drm/xe/xe_ras.h | 5 +
+ drivers/gpu/drm/xe/xe_ras_types.h | 51 +
+ drivers/gpu/drm/xe/xe_reg_whitelist.c | 5 +-
+ drivers/gpu/drm/xe/xe_reg_whitelist.h | 4 +
+ drivers/gpu/drm/xe/xe_rtp.c | 10 +-
+ drivers/gpu/drm/xe/xe_rtp.h | 19 +
+ drivers/gpu/drm/xe/xe_rtp_types.h | 33 +-
+ drivers/gpu/drm/xe/xe_sched_job.c | 2 +-
+ drivers/gpu/drm/xe/xe_step.c | 38 +-
+ drivers/gpu/drm/xe/xe_step.h | 8 +-
+ drivers/gpu/drm/xe/xe_svm.c | 2 +-
+ drivers/gpu/drm/xe/xe_sysctrl_mailbox.c | 28 +
+ drivers/gpu/drm/xe/xe_sysctrl_mailbox.h | 3 +
+ drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h | 4 +
+ drivers/gpu/drm/xe/xe_tile.c | 4 +-
+ drivers/gpu/drm/xe/xe_tuning.c | 3 +-
+ drivers/gpu/drm/xe/xe_tuning.h | 6 +
+ drivers/gpu/drm/xe/xe_userptr.c | 2 +-
+ drivers/gpu/drm/xe/xe_vm.c | 4 +-
+ drivers/gpu/drm/xe/xe_vm_madvise.c | 19 +-
+ drivers/gpu/drm/xe/xe_wa.c | 15 +-
+ drivers/gpu/drm/xe/xe_wa.h | 7 +
+ drivers/gpu/drm/xe/xe_wa_oob.rules | 1 +
+ drivers/gpu/drm/xlnx/zynqmp_dp.c | 2 +-
+ include/drm/bridge/analogix_dp.h | 13 +-
+ include/drm/bridge/dw_dp.h | 1 +
+ include/drm/display/drm_dp.h | 13 +-
+ include/drm/display/drm_hdmi_state_helper.h | 4 +-
+ include/drm/drm_atomic.h | 5 +-
+ include/drm/drm_atomic_helper.h | 7 +
+ include/drm/drm_atomic_state_helper.h | 18 +-
+ include/drm/drm_bridge.h | 37 +-
+ include/drm/drm_colorop.h | 2 +
+ include/drm/drm_connector.h | 118 +
+ include/drm/drm_crtc.h | 16 +
+ include/drm/drm_debugfs.h | 2 +-
+ include/drm/drm_drv.h | 6 -
+ include/drm/drm_gem.h | 3 -
+ include/drm/drm_gem_shmem_helper.h | 4 +
+ include/drm/drm_gpuvm.h | 4 +-
+ include/drm/drm_managed.h | 2 +-
+ include/drm/drm_mipi_dsi.h | 2 +
+ include/drm/drm_mode_config.h | 1 +
+ include/drm/drm_modes.h | 1 +
+ include/drm/drm_of.h | 11 +
+ include/drm/drm_panel.h | 8 -
+ include/drm/drm_plane.h | 16 +
+ include/drm/drm_print.h | 2 +-
+ include/drm/gpu_scheduler.h | 3 +-
+ include/drm/intel/display_parent_interface.h | 4 +-
+ include/drm/intel/mchbar_regs.h | 2 -
+ include/drm/intel/pciids.h | 5 +-
+ include/linux/dma-fence-unwrap.h | 6 +-
+ include/linux/dma-fence.h | 4 +-
+ include/linux/font.h | 3 +
+ include/linux/gpu_buddy.h | 15 +
+ include/linux/perf_event.h | 31 +-
+ include/linux/sysfb.h | 4 +-
+ include/uapi/drm/amdgpu_drm.h | 21 +
+ include/uapi/drm/drm_mode.h | 1 +
+ include/uapi/drm/ethosu_accel.h | 60 +-
+ include/uapi/drm/panthor_drm.h | 26 +-
+ include/uapi/drm/xe_drm.h | 11 +-
+ kernel/cgroup/dmem.c | 15 +
+ kernel/events/core.c | 18 +
+ lib/fonts/fonts.c | 31 +
+ 859 files changed, 49461 insertions(+), 28698 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/display/panel/anbernic,td4310.yaml
+ create mode 100644 Documentation/devicetree/bindings/display/panel/chipone,icna3512.yaml
+ create mode 100644 Documentation/devicetree/bindings/display/panel/ilitek,ili7807s.yaml
+ create mode 100644 Documentation/devicetree/bindings/display/panel/ilitek,ili9488.yaml
+ create mode 100644 Documentation/devicetree/bindings/display/panel/renesas,r63419.yaml
+ create mode 100644 Documentation/gpu/intel-display/dp-link-training.rst
+ create mode 100644 drivers/accel/ethosu/ethosu_perfmon.c
+ delete mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c
+ delete mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_aca.h
+ create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.h
+ create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_sa.h
+ rename drivers/gpu/drm/amd/{display/modules/power/power_helpers.c => amdgpu/amdgpu_video_codecs.h} (63%)
+ create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_wb.c
+ create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_wb.h
+ create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_audio.c
+ create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_audio.h
+ create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_backlight.c
+ create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_backlight.h
+ create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+ create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h
+ create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c
+ create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.h
+ create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.h
+ create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.h
+ create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_audio_test.c
+ create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_backlight_test.c
+ create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
+ create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c
+ create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c
+ create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c
+ create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c
+ create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_kunit_helpers.c
+ create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_kunit_test_helpers.h
+ create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
+ create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c
+ create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_pp_smu_test.c
+ create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_quirks_test.c
+ create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_services_test.c
+ create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c
+ create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_wb_test.c
+ create mode 100644 drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn42b/dcn42b_soc_and_ip_translator.c
+ create mode 100644 drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn42b/dcn42b_soc_and_ip_translator.h
+ create mode 100644 drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+ create mode 100644 drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+ create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_panic.c
+ create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_panic.h
+ delete mode 100644 drivers/gpu/drm/i915/i915_panic.c
+ delete mode 100644 drivers/gpu/drm/i915/i915_panic.h
+ create mode 100644 drivers/gpu/drm/panel/panel-anbernic-td4310.c
+ create mode 100644 drivers/gpu/drm/panel/panel-chipone-icna35xx.c
+ create mode 100644 drivers/gpu/drm/panel/panel-ilitek-ili7807s.c
+ create mode 100644 drivers/gpu/drm/panel/panel-ilitek-ili9488.c
+ create mode 100644 drivers/gpu/drm/panel/panel-renesas-r63419.c
+ create mode 100644 drivers/gpu/drm/tests/drm_kunit_edid.c
+ create mode 100644 drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c
+ create mode 100644 drivers/gpu/drm/xe/xe_pci_error.c
+ create mode 100644 drivers/gpu/drm/xe/xe_pci_error.h
+$ git am -3 ../patches/0001-drm-Fix-up-lut3d-mismerge.patch
+Applying: drm: Fix up lut3d mismerge
+Using index info to reconstruct a base tree...
+M drivers/gpu/drm/drm_atomic.c
+M include/drm/drm_colorop.h
+Falling back to patching base and 3-way merge...
+Auto-merging include/drm/drm_colorop.h
+Auto-merging drivers/gpu/drm/drm_atomic.c
+No changes -- Patch already applied.
+Merging drm-exynos/for-linux-next (3a8660878839f Linux 6.18-rc1)
+$ git merge -m Merge branch 'for-linux-next' of https://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos.git drm-exynos/for-linux-next
+Already up to date.
+Merging drm-misc/for-linux-next (104c00917264c drm/panthor: Remove redundant drm_sched_job_cleanup() from the .free_job callback)
+$ git merge -m Merge branch 'for-linux-next' of https://gitlab.freedesktop.org/drm/misc/kernel.git drm-misc/for-linux-next
+Auto-merging drivers/gpu/drm/xe/xe_pt.c
+Merge made by the 'ort' strategy.
+ drivers/gpu/drm/drm_gpusvm.c | 243 +++++++++++++++++++-------------
+ drivers/gpu/drm/panthor/panthor_sched.c | 1 -
+ drivers/gpu/drm/xe/xe_pt.c | 2 +-
+ drivers/gpu/drm/xe/xe_svm.c | 66 +++++++--
+ drivers/gpu/drm/xe/xe_svm.h | 14 +-
+ drivers/gpu/drm/xe/xe_userptr.c | 5 +-
+ include/drm/drm_gpusvm.h | 67 ++++++---
+ 7 files changed, 255 insertions(+), 143 deletions(-)
+$ git am -3 ../patches/0001-drm-bridge-microchip-lvds-Rename-drm_atomic_state-to.patch
+Applying: drm/bridge: microchip-lvds: Rename drm_atomic_state to drm_atomic_commit
+Using index info to reconstruct a base tree...
+M drivers/gpu/drm/bridge/microchip-lvds.c
+Falling back to patching base and 3-way merge...
+No changes -- Patch already applied.
+Merging amdgpu/drm-next (5c6c247992d4d drm/amdkfd: Check bounds on CRIU restore event id)
+$ git merge -m Merge branch 'drm-next' of https://gitlab.freedesktop.org/agd5f/linux.git amdgpu/drm-next
+Already up to date.
+$ git am -3 ../patches/0001-amdgpu-Fix-up-drm_atomic_commit-rename.patch
+Applying: amdgpu: Fix up drm_atomic_commit rename
+Using index info to reconstruct a base tree...
+M drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+Falling back to patching base and 3-way merge...
+Auto-merging drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+No changes -- Patch already applied.
+Merging drm-intel/for-linux-next (4fee95d4f8875 drm/i915/kunit: DP link: add fallback tests)
+$ git merge -m Merge branch 'for-linux-next' of https://gitlab.freedesktop.org/drm/i915/kernel.git drm-intel/for-linux-next
+Auto-merging drivers/gpu/drm/i915/display/intel_dp.c
+Auto-merging drivers/gpu/drm/xe/Makefile
+Merge made by the 'ort' strategy.
+ .../gpu/intel-display/dp-link-capabilities.rst | 11 +
+ Documentation/gpu/intel-display/index.rst | 1 +
+ drivers/gpu/drm/i915/.kunitconfig | 9 +
+ drivers/gpu/drm/i915/Kconfig.debug | 12 +
+ drivers/gpu/drm/i915/Makefile | 2 +
+ drivers/gpu/drm/i915/display/intel_audio.c | 55 +-
+ drivers/gpu/drm/i915/display/intel_display.c | 9 +
+ drivers/gpu/drm/i915/display/intel_display_core.h | 2 +
+ .../gpu/drm/i915/display/intel_display_driver.c | 71 +
+ .../gpu/drm/i915/display/intel_display_driver.h | 8 +
+ drivers/gpu/drm/i915/display/intel_display_regs.h | 3 +
+ drivers/gpu/drm/i915/display/intel_display_wa.c | 2 +
+ drivers/gpu/drm/i915/display/intel_display_wa.h | 1 +
+ drivers/gpu/drm/i915/display/intel_dp.c | 291 ++--
+ drivers/gpu/drm/i915/display/intel_dp.h | 11 +-
+ drivers/gpu/drm/i915/display/intel_dp_link_caps.c | 759 ++++++++++-
+ drivers/gpu/drm/i915/display/intel_dp_link_caps.h | 172 ++-
+ .../gpu/drm/i915/display/intel_dp_link_training.c | 237 ++--
+ .../gpu/drm/i915/display/intel_dp_link_training.h | 31 +
+ drivers/gpu/drm/i915/display/intel_dp_mst.c | 72 +-
+ drivers/gpu/drm/i915/display/intel_dp_test.c | 107 +-
+ drivers/gpu/drm/i915/display/intel_dp_test.h | 3 +-
+ drivers/gpu/drm/i915/display/intel_dp_tunnel.c | 8 +-
+ drivers/gpu/drm/i915/display/intel_psr.c | 16 +
+ drivers/gpu/drm/i915/display/intel_vrr.c | 6 +
+ drivers/gpu/drm/i915/display/tests/Makefile | 7 +
+ .../drm/i915/display/tests/intel_dp_link_test.c | 1440 ++++++++++++++++++++
+ drivers/gpu/drm/i915/i915_driver.c | 58 +-
+ drivers/gpu/drm/xe/.gitignore | 1 +
+ drivers/gpu/drm/xe/.kunitconfig-display | 11 +
+ drivers/gpu/drm/xe/Makefile | 3 +
+ drivers/gpu/drm/xe/display/tests/Makefile | 13 +
+ drivers/gpu/drm/xe/display/xe_display.c | 44 +-
+ drivers/gpu/drm/xe/display/xe_display.h | 2 +
+ drivers/gpu/drm/xe/xe_pm.c | 2 +
+ 35 files changed, 3018 insertions(+), 462 deletions(-)
+ create mode 100644 Documentation/gpu/intel-display/dp-link-capabilities.rst
+ create mode 100644 drivers/gpu/drm/i915/.kunitconfig
+ create mode 100644 drivers/gpu/drm/i915/display/tests/Makefile
+ create mode 100644 drivers/gpu/drm/i915/display/tests/intel_dp_link_test.c
+ create mode 100644 drivers/gpu/drm/xe/.kunitconfig-display
+ create mode 100644 drivers/gpu/drm/xe/display/tests/Makefile
+Merging drm-msm/msm-next (9a967125427e0 drm/msm/adreno: add Adreno 810 GPU support)
+$ git merge -m Merge branch 'msm-next' of https://gitlab.freedesktop.org/drm/msm.git drm-msm/msm-next
+Already up to date.
+Merging drm-msm-lumag/msm-next-lumag (8de061ca149c9 drm/msm: Restore second parameter name in purge() and evict())
+$ git merge -m Merge branch 'msm-next-lumag' of https://gitlab.freedesktop.org/lumag/msm.git drm-msm-lumag/msm-next-lumag
+Already up to date.
+Merging drm-xe/drm-xe-next (9cdcdadab5431 drm/xe/guc: Define GuC firmware for NVL-S)
+ 3359422bf0a11 ("drm/xe/userptr: Stub notifier_lock helpers when DRM_GPUSVM=n")
+ 84ed5b0a92572 ("drm/xe: remove duplicate <kunit/test-bug.h> include")
+ a6b842acf3ddd ("drm/xe: Wait on external BO kernel fences in exec IOCTL")
+ c3a1c3579b125 ("drm/xe: free madvise VMA array on L2 flush failure")
+$ git merge -m Merge branch 'drm-xe-next' of https://gitlab.freedesktop.org/drm/xe/kernel.git drm-xe/drm-xe-next
+Auto-merging drivers/gpu/drm/xe/xe_pt.c
+Merge made by the 'ort' strategy.
+ drivers/gpu/drm/xe/abi/guc_actions_abi.h | 1 +
+ drivers/gpu/drm/xe/abi/guc_klvs_abi.h | 10 +++++++
+ drivers/gpu/drm/xe/regs/xe_pmt.h | 2 ++
+ drivers/gpu/drm/xe/xe_debugfs.c | 33 ++++++++++++++++++++++
+ drivers/gpu/drm/xe/xe_gt_types.h | 5 ++++
+ drivers/gpu/drm/xe/xe_guc.c | 10 +++++++
+ drivers/gpu/drm/xe/xe_guc_ads.c | 9 ++++++
+ drivers/gpu/drm/xe/xe_guc_ct.c | 43 ++++++++++++++++++++++++++++-
+ drivers/gpu/drm/xe/xe_guc_engine_activity.c | 2 +-
+ drivers/gpu/drm/xe/xe_guc_submit.c | 32 +++++++++++++++++++++
+ drivers/gpu/drm/xe/xe_guc_submit.h | 1 +
+ drivers/gpu/drm/xe/xe_pci.c | 15 +++++++++-
+ drivers/gpu/drm/xe/xe_pci_types.h | 2 ++
+ drivers/gpu/drm/xe/xe_pcode.c | 32 +++++++++++++++++++++
+ drivers/gpu/drm/xe/xe_pcode.h | 7 +++++
+ drivers/gpu/drm/xe/xe_trace.h | 5 ++++
+ drivers/gpu/drm/xe/xe_uc_fw.c | 1 +
+ drivers/gpu/drm/xe/xe_wa_oob.rules | 5 ++++
+ include/uapi/drm/xe_drm.h | 6 ++--
+ 19 files changed, 215 insertions(+), 6 deletions(-)
+$ git am -3 ../patches/0001-drm-xe-Fix-up-merge-issue.patch
+Applying: drm: xe: Fix up merge issue
+Using index info to reconstruct a base tree...
+M drivers/gpu/drm/xe/xe_ttm_vram_mgr.c
+Falling back to patching base and 3-way merge...
+Auto-merging drivers/gpu/drm/xe/xe_ttm_vram_mgr.c
+No changes -- Patch already applied.
+Merging drm-rust/for-linux-next (d85845b64c002 gpu: nova-core: build SetRegistry entries dynamically)
+$ git merge -m Merge branch 'for-linux-next' of https://gitlab.freedesktop.org/drm/rust/kernel.git drm-rust/for-linux-next
+Merge made by the 'ort' strategy.
+ Documentation/gpu/nova/core/fsp.rst | 142 ++++++
+ Documentation/gpu/nova/index.rst | 1 +
+ drivers/gpu/Makefile | 58 ++-
+ drivers/gpu/drm/Makefile | 2 +-
+ drivers/gpu/drm/nova/Makefile | 5 +-
+ drivers/gpu/drm/tyr/regs.rs | 14 +-
+ drivers/gpu/nova-core/.gitignore | 1 +
+ drivers/gpu/nova-core/Makefile | 5 +-
+ drivers/gpu/nova-core/bitfield.rs | 329 ------------
+ drivers/gpu/nova-core/falcon.rs | 195 ++++---
+ drivers/gpu/nova-core/falcon/fsp.rs | 44 +-
+ drivers/gpu/nova-core/falcon/gsp.rs | 32 +-
+ drivers/gpu/nova-core/falcon/hal.rs | 14 +-
+ drivers/gpu/nova-core/falcon/hal/ga102.rs | 29 +-
+ drivers/gpu/nova-core/falcon/hal/tu102.rs | 24 +-
+ drivers/gpu/nova-core/fb.rs | 4 +-
+ drivers/gpu/nova-core/fb/hal/gb202.rs | 28 +-
+ drivers/gpu/nova-core/fb/hal/gh100.rs | 31 +-
+ drivers/gpu/nova-core/fb/regs.rs | 25 +
+ drivers/gpu/nova-core/firmware.rs | 25 +-
+ drivers/gpu/nova-core/firmware/booter.rs | 25 +-
+ drivers/gpu/nova-core/firmware/fwsec.rs | 19 +-
+ drivers/gpu/nova-core/firmware/fwsec/bootloader.rs | 16 +-
+ drivers/gpu/nova-core/fsp.rs | 116 +++--
+ drivers/gpu/nova-core/gpu.rs | 136 +++--
+ drivers/gpu/nova-core/gsp.rs | 38 +-
+ drivers/gpu/nova-core/gsp/boot.rs | 56 +--
+ drivers/gpu/nova-core/gsp/cmdq.rs | 3 +-
+ drivers/gpu/nova-core/gsp/commands.rs | 89 ++--
+ drivers/gpu/nova-core/gsp/fw.rs | 19 +-
+ drivers/gpu/nova-core/gsp/fw/commands.rs | 42 +-
+ drivers/gpu/nova-core/gsp/hal.rs | 27 +-
+ drivers/gpu/nova-core/gsp/hal/gh100.rs | 52 +-
+ drivers/gpu/nova-core/gsp/hal/tu102.rs | 118 +++--
+ drivers/gpu/nova-core/gsp/regs.rs | 11 +
+ drivers/gpu/nova-core/gsp/sequencer.rs | 31 +-
+ drivers/gpu/nova-core/mctp.rs | 86 ++--
+ drivers/gpu/nova-core/nova_core.rs | 5 +-
+ drivers/gpu/nova-core/nova_core_exports.c | 15 +
+ drivers/gpu/nova-core/regs.rs | 70 ++-
+ drivers/gpu/nova-core/vbios.rs | 64 +--
+ rust/kernel/drm/device.rs | 2 +-
+ rust/kernel/drm/gem/mod.rs | 2 +-
+ rust/kernel/drm/gem/shmem.rs | 558 ++++++++++++++++++++-
+ rust/kernel/drm/gpuvm/mod.rs | 12 +-
+ rust/kernel/drm/gpuvm/sm_ops.rs | 4 +-
+ rust/kernel/faux.rs | 18 +-
+ 47 files changed, 1571 insertions(+), 1071 deletions(-)
+ create mode 100644 Documentation/gpu/nova/core/fsp.rst
+ create mode 100644 drivers/gpu/nova-core/.gitignore
+ delete mode 100644 drivers/gpu/nova-core/bitfield.rs
+ create mode 100644 drivers/gpu/nova-core/fb/regs.rs
+ create mode 100644 drivers/gpu/nova-core/gsp/regs.rs
+ create mode 100644 drivers/gpu/nova-core/nova_core_exports.c
+$ git am -3 ../patches/0001-drm-nova-Fix-up-merge-issue.patch
+Applying: drm: nova: Fix up merge issue
+Using index info to reconstruct a base tree...
+M drivers/gpu/nova-core/gsp/cmdq.rs
+Falling back to patching base and 3-way merge...
+Auto-merging drivers/gpu/nova-core/gsp/cmdq.rs
+No changes -- Patch already applied.
+Merging drm-nova/nova-next (93296e9d9528f gpu: nova-core: vbios: store reference to Device where relevant)
+$ git merge -m Merge branch 'nova-next' of https://gitlab.freedesktop.org/drm/nova.git drm-nova/nova-next
+Already up to date.
+Merging etnaviv/etnaviv/next (6bde14ba5f7ef drm/etnaviv: add optional reset support)
+$ git merge -m Merge branch 'etnaviv/next' of https://git.pengutronix.de/git/lst/linux etnaviv/etnaviv/next
+Already up to date.
+Merging fbdev/for-next (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/deller/linux-fbdev.git fbdev/for-next
+Already up to date.
+$ git am -3 ../patches/0001-fix-up-for-drm-hyperv-Remove-reference-to-hyperv_fb-.patch
+Applying: fix up for "drm/hyperv: Remove reference to hyperv_fb driver"
+$ git reset HEAD^
+Unstaged changes after reset:
+M drivers/gpu/drm/hyperv/Kconfig
+$ git add -A .
+$ git commit -v -a --amend
+warning: notes ref refs/notes/commits is invalid
+[master 35a59760fb4a5] Merge branch 'for-linux-next' of https://gitlab.freedesktop.org/drm/rust/kernel.git
+ Date: Fri Jul 10 13:11:40 2026 +0100
+Merging regmap/for-next (1c790e0326461 Merge remote-tracking branch 'regmap/for-7.3' into regmap-next)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git regmap/for-next
+Merge made by the 'ort' strategy.
+ drivers/base/regmap/internal.h | 2 +-
+ drivers/base/regmap/regcache-flat.c | 4 +---
+ drivers/base/regmap/regcache-maple.c | 8 +++-----
+ drivers/base/regmap/regcache-rbtree.c | 8 +++-----
+ drivers/base/regmap/regmap-irq.c | 22 ++++++++++++++++++++++
+ include/linux/regmap.h | 2 ++
+ 6 files changed, 32 insertions(+), 14 deletions(-)
+Merging sound/for-next (75c4027e741db ALSA: hda/cm9825: Add IBP support for DFI)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git sound/for-next
+Auto-merging include/sound/hda_codec.h
+Auto-merging sound/hda/codecs/realtek/alc269.c
+Merge made by the 'ort' strategy.
+ include/sound/hda_codec.h | 1 +
+ sound/core/control.c | 10 +-
+ sound/core/hwdep.c | 2 +-
+ sound/core/info.c | 2 +-
+ sound/core/oss/mixer_oss.c | 6 +-
+ sound/core/oss/pcm_oss.c | 6 +-
+ sound/core/pcm_native.c | 18 +-
+ sound/core/rawmidi.c | 4 +-
+ sound/core/seq/seq_clientmgr.c | 5 +-
+ sound/core/sound.c | 16 +-
+ sound/core/timer.c | 5 +-
+ sound/drivers/aloop.c | 118 +++-
+ sound/hda/codecs/cm9825.c | 148 ++++-
+ sound/hda/codecs/hdmi/hdmi.c | 4 +-
+ sound/hda/codecs/helpers/razer_blade16_2025.c | 820 ++++++++++++++++++++++++++
+ sound/hda/codecs/realtek/alc269.c | 21 +
+ sound/hda/common/codec.c | 5 +-
+ sound/hda/controllers/intel.c | 11 +
+ sound/hda/core/controller.c | 28 +-
+ sound/hda/core/stream.c | 40 +-
+ sound/pci/via82xx_modem.c | 26 +-
+ sound/usb/card.c | 70 ++-
+ sound/usb/mixer_quirks.c | 20 +
+ sound/usb/quirks-table.h | 67 +++
+ 24 files changed, 1340 insertions(+), 113 deletions(-)
+ create mode 100644 sound/hda/codecs/helpers/razer_blade16_2025.c
+Merging ieee1394/for-next (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394.git ieee1394/for-next
+Already up to date.
+Merging sound-asoc/for-next (8dfce4002fc1e Merge remote-tracking branch 'asoc/for-7.3' into asoc-next)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git sound-asoc/for-next
+Merge made by the 'ort' strategy.
+ .../devicetree/bindings/sound/cirrus,cs35l36.yaml | 240 ++++++
+ .../devicetree/bindings/sound/cs35l36.txt | 168 -----
+ .../devicetree/bindings/sound/dmic-codec.yaml | 4 +
+ .../devicetree/bindings/sound/fsl,micfil.yaml | 4 +
+ .../bindings/sound/loongson,ls-audio-card.yaml | 53 +-
+ .../bindings/sound/loongson,ls2k1000-i2s.yaml | 22 +-
+ .../bindings/sound/mediatek,mtk-btcvsd-snd.yaml | 59 ++
+ .../devicetree/bindings/sound/mtk-btcvsd-snd.txt | 24 -
+ .../devicetree/bindings/sound/wlf,wm8524.yaml | 4 +
+ include/sound/soc_sdw_utils.h | 31 +-
+ include/sound/sof/dai-amd.h | 1 +
+ include/sound/sof/dai.h | 3 +
+ include/uapi/sound/sof/tokens.h | 1 +
+ sound/soc/amd/acp-config.c | 12 +
+ sound/soc/amd/acp/acp-i2s.c | 6 +
+ sound/soc/amd/acp/acp-sdw-legacy-mach.c | 2 +-
+ sound/soc/amd/acp/acp-sdw-sof-mach.c | 2 +-
+ sound/soc/amd/mach-config.h | 1 +
+ sound/soc/amd/raven/acp3x-i2s.c | 6 +
+ sound/soc/amd/vangogh/acp5x-i2s.c | 6 +
+ sound/soc/amd/yc/acp6x-mach.c | 12 +-
+ sound/soc/au1x/psc-ac97.c | 4 +-
+ sound/soc/codecs/Kconfig | 32 +-
+ sound/soc/codecs/cs35l32.c | 10 +-
+ sound/soc/codecs/cs35l33.c | 14 +-
+ sound/soc/codecs/cs35l34.c | 14 +-
+ sound/soc/codecs/cs42l42-sdw.c | 14 +-
+ sound/soc/codecs/cs4349.c | 8 +-
+ sound/soc/codecs/es8328.c | 5 +
+ sound/soc/codecs/es8389.c | 236 +++++-
+ sound/soc/codecs/es8389.h | 11 +-
+ sound/soc/codecs/hdac_hda.c | 4 +-
+ sound/soc/codecs/hdac_hdmi.c | 10 +-
+ sound/soc/codecs/lpass-rx-macro.c | 31 +-
+ sound/soc/codecs/lpass-tx-macro.c | 25 +-
+ sound/soc/codecs/lpass-va-macro.c | 131 ++--
+ sound/soc/codecs/lpass-wsa-macro.c | 139 ++--
+ sound/soc/codecs/max98090.c | 9 +-
+ sound/soc/codecs/max98363.c | 7 +-
+ sound/soc/codecs/max98373-i2c.c | 9 +-
+ sound/soc/codecs/max98373-sdw.c | 7 +-
+ sound/soc/codecs/max98388.c | 8 +-
+ sound/soc/codecs/max98390.c | 8 +-
+ sound/soc/codecs/max98396.c | 24 +-
+ sound/soc/codecs/max98927.c | 8 +-
+ sound/soc/codecs/pcm1681.c | 7 +
+ sound/soc/codecs/pcm1754.c | 6 +
+ sound/soc/codecs/pcm1789.c | 7 +
+ sound/soc/codecs/pcm179x.c | 6 +
+ sound/soc/codecs/pcm186x.c | 9 +
+ sound/soc/codecs/pcm3060.c | 8 +
+ sound/soc/codecs/pcm512x.c | 9 +
+ sound/soc/codecs/pm4125-sdw.c | 8 +-
+ sound/soc/codecs/pm4125.c | 3 +-
+ sound/soc/codecs/rt1017-sdca-sdw.c | 7 +-
+ sound/soc/codecs/rt1316-sdw.c | 7 +-
+ sound/soc/codecs/rt1318-sdw.c | 7 +-
+ sound/soc/codecs/rt1320-sdw.c | 833 +++++++++++++++++----
+ sound/soc/codecs/rt1320-sdw.h | 12 +
+ sound/soc/codecs/rt5514.c | 16 +-
+ sound/soc/codecs/rt5645.c | 16 +-
+ sound/soc/codecs/rt5677.c | 17 +
+ sound/soc/codecs/rt5682-sdw.c | 20 +-
+ sound/soc/codecs/rt700-sdw.c | 6 +-
+ sound/soc/codecs/rt712-sdca-dmic.c | 17 +-
+ sound/soc/codecs/rt712-sdca-sdw.c | 17 +-
+ sound/soc/codecs/rt721-sdca-sdw.c | 17 +-
+ sound/soc/codecs/rt722-sdca-sdw.c | 8 +-
+ sound/soc/codecs/rt9120.c | 9 +-
+ sound/soc/codecs/sma1303.c | 2 +
+ sound/soc/codecs/tas2552.c | 10 +-
+ sound/soc/codecs/tas2783-sdw.c | 16 +-
+ sound/soc/codecs/tlv320aic26.c | 6 +
+ sound/soc/codecs/uda1342.c | 9 +-
+ sound/soc/codecs/wcd937x-sdw.c | 8 +-
+ sound/soc/codecs/wcd938x-sdw.c | 8 +-
+ sound/soc/codecs/wcd939x-sdw.c | 8 +-
+ sound/soc/codecs/wm2200.c | 10 +-
+ sound/soc/codecs/wm5100.c | 10 +-
+ sound/soc/codecs/wm8962.c | 9 +-
+ sound/soc/codecs/wsa881x.c | 8 +-
+ sound/soc/codecs/wsa883x.c | 8 +-
+ sound/soc/codecs/wsa884x.c | 8 +-
+ sound/soc/fsl/fsl_asrc.c | 10 +-
+ sound/soc/fsl/fsl_audmix.c | 35 +-
+ sound/soc/fsl/fsl_easrc.c | 36 +-
+ sound/soc/fsl/fsl_esai.c | 16 +-
+ sound/soc/fsl/fsl_spdif.c | 8 +-
+ sound/soc/fsl/fsl_ssi.c | 13 +-
+ sound/soc/fsl/fsl_xcvr.c | 29 +-
+ sound/soc/fsl/imx-audio-rpmsg.c | 25 +-
+ sound/soc/fsl/imx-pcm-rpmsg.c | 69 +-
+ sound/soc/fsl/mpc5200_dma.c | 56 +-
+ sound/soc/fsl/mpc5200_psc_ac97.c | 34 +-
+ sound/soc/fsl/mpc5200_psc_i2s.c | 1 +
+ sound/soc/intel/atom/sst-atom-controls.c | 67 +-
+ sound/soc/intel/atom/sst-mfld-platform-pcm.c | 59 +-
+ sound/soc/intel/atom/sst/sst_ipc.c | 5 +-
+ sound/soc/intel/atom/sst/sst_pci.c | 4 +-
+ sound/soc/intel/atom/sst/sst_pvt.c | 9 +-
+ sound/soc/intel/avs/apl.c | 8 +-
+ sound/soc/intel/avs/control.c | 7 +-
+ sound/soc/intel/avs/core.c | 4 +-
+ sound/soc/intel/avs/debug.h | 10 +-
+ sound/soc/intel/avs/debugfs.c | 19 +-
+ sound/soc/intel/avs/ipc.c | 59 +-
+ sound/soc/intel/avs/loader.c | 15 +-
+ sound/soc/intel/avs/path.c | 30 +-
+ sound/soc/intel/avs/utils.c | 45 +-
+ sound/soc/intel/boards/sof_sdw.c | 2 +-
+ sound/soc/loongson/loongson_card.c | 171 ++++-
+ sound/soc/loongson/loongson_i2s_plat.c | 42 +-
+ sound/soc/mediatek/Kconfig | 2 +-
+ sound/soc/mediatek/mt8173/mt8173-rt5650.c | 2 +-
+ sound/soc/mediatek/mt8365/mt8365-mt6357.c | 9 +-
+ sound/soc/meson/Makefile | 2 +
+ sound/soc/meson/aiu-encoder-i2s.c | 281 +++++--
+ sound/soc/meson/aiu-formatter-i2s.c | 104 +++
+ sound/soc/meson/aiu.c | 32 +-
+ sound/soc/meson/aiu.h | 4 +
+ sound/soc/meson/g12a-toacodec.c | 2 +-
+ sound/soc/meson/g12a-tohdmitx.c | 2 +-
+ sound/soc/meson/gx-formatter.c | 282 +++++++
+ sound/soc/meson/gx-formatter.h | 56 ++
+ sound/soc/meson/gx-interface.h | 48 ++
+ sound/soc/meson/t9015.c | 12 +-
+ sound/soc/renesas/fsi.c | 9 +-
+ sound/soc/samsung/aries_wm8994.c | 1 +
+ sound/soc/samsung/i2s.c | 33 +-
+ sound/soc/samsung/spdif.c | 8 +-
+ sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c | 4 +-
+ sound/soc/sdw_utils/soc_sdw_utils.c | 7 +-
+ sound/soc/sof/amd/Kconfig | 11 +
+ sound/soc/sof/amd/Makefile | 2 +
+ sound/soc/sof/amd/acp-dsp-offset.h | 17 +
+ sound/soc/sof/amd/acp-ipc.c | 13 +-
+ sound/soc/sof/amd/acp-loader.c | 37 +-
+ sound/soc/sof/amd/acp.c | 267 ++++++-
+ sound/soc/sof/amd/acp.h | 20 +
+ sound/soc/sof/amd/acp7x.c | 185 +++++
+ sound/soc/sof/amd/pci-acp7x.c | 116 +++
+ sound/soc/sof/ipc3-pcm.c | 6 +
+ sound/soc/sof/ipc3-topology.c | 39 +-
+ sound/soc/sof/ipc4-topology.c | 2 +
+ sound/soc/sof/nocodec.c | 16 +-
+ sound/soc/sof/topology.c | 15 +-
+ sound/soc/spacemit/k1_i2s.c | 7 +
+ sound/soc/ti/j721e-evm.c | 4 +-
+ 148 files changed, 3982 insertions(+), 1184 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/sound/cirrus,cs35l36.yaml
+ delete mode 100644 Documentation/devicetree/bindings/sound/cs35l36.txt
+ create mode 100644 Documentation/devicetree/bindings/sound/mediatek,mtk-btcvsd-snd.yaml
+ delete mode 100644 Documentation/devicetree/bindings/sound/mtk-btcvsd-snd.txt
+ create mode 100644 sound/soc/meson/aiu-formatter-i2s.c
+ create mode 100644 sound/soc/meson/gx-formatter.c
+ create mode 100644 sound/soc/meson/gx-formatter.h
+ create mode 100644 sound/soc/meson/gx-interface.h
+ create mode 100644 sound/soc/sof/amd/acp7x.c
+ create mode 100644 sound/soc/sof/amd/pci-acp7x.c
+Merging modules/modules-next (852fd31eb074f rust: module_param: return value by copy from `value`)
+$ git merge -m Merge branch 'modules-next' of https://git.kernel.org/pub/scm/linux/kernel/git/modules/linux.git modules/modules-next
+Auto-merging kernel/params.c
+Merge made by the 'ort' strategy.
+ arch/xtensa/platforms/iss/simdisk.c | 38 ++++++++++++++++++++++++++++++++-----
+ include/linux/module.h | 4 ----
+ kernel/module/dups.c | 2 +-
+ kernel/module/main.c | 15 ++++++++-------
+ kernel/module/procfs.c | 2 +-
+ kernel/module/stats.c | 2 +-
+ kernel/params.c | 2 +-
+ rust/kernel/module_param.rs | 18 +++++++++++++++++-
+ samples/rust/rust_minimal.rs | 2 +-
+ scripts/module.lds.S | 5 -----
+ 10 files changed, 63 insertions(+), 27 deletions(-)
+Merging input/next (c8f174900926d Input: sur40 - fix MAX_CONTACTS value based on PixelSense specification)
+$ git merge -m Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git input/next
+Auto-merging Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
+Merge made by the 'ort' strategy.
+ .../devicetree/bindings/input/imagis,isa1200.yaml | 141 ++++++
+ .../bindings/input/microchip,cap11xx.yaml | 92 +++-
+ .../devicetree/bindings/input/syna,rmi4.yaml | 11 +-
+ drivers/input/keyboard/cap11xx.c | 275 +++++++----
+ drivers/input/misc/Kconfig | 12 +
+ drivers/input/misc/Makefile | 1 +
+ drivers/input/misc/isa1200.c | 533 +++++++++++++++++++++
+ drivers/input/mouse/synaptics.c | 1 +
+ drivers/input/touchscreen/mms114.c | 245 +++++-----
+ drivers/input/touchscreen/sur40.c | 4 +-
+ 10 files changed, 1085 insertions(+), 230 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/input/imagis,isa1200.yaml
+ create mode 100644 drivers/input/misc/isa1200.c
+Merging block/for-next (8285cd727ff80 Merge branch 'block-7.2' into for-next)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux.git block/for-next
+Merge made by the 'ort' strategy.
+ block/blk-mq.c | 3 ++-
+ block/blk-wbt.c | 21 ++++++++++++++++++++-
+ block/blk-zoned.c | 42 ++++++++++++++++++++++++++++--------------
+ block/blk.h | 4 ++--
+ block/genhd.c | 2 +-
+ drivers/block/ublk_drv.c | 13 ++++++++++++-
+ drivers/block/xen-blkfront.c | 9 +++++++++
+ include/linux/io_uring_types.h | 2 ++
+ io_uring/io-wq.c | 5 +++++
+ io_uring/io_uring.c | 2 ++
+ io_uring/kbuf.c | 5 +++--
+ io_uring/memmap.c | 2 +-
+ io_uring/msg_ring.c | 34 +++++++++++++++++++++++++++-------
+ io_uring/sqpoll.c | 7 ++++++-
+ io_uring/tw.c | 11 +++++++----
+ io_uring/uring_cmd.c | 4 ++--
+ 16 files changed, 129 insertions(+), 37 deletions(-)
+$ git am -3 ../patches/0001-Revert-block-remove-bio_last_bvec_all.patch
+Applying: Revert "block: remove bio_last_bvec_all"
+$ git reset HEAD^
+Unstaged changes after reset:
+M Documentation/block/biovecs.rst
+M include/linux/bio.h
+$ git add -A .
+$ git commit -v -a --amend
+warning: notes ref refs/notes/commits is invalid
+[master 4ca327ee5f771] Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux.git
+ Date: Fri Jul 10 13:26:59 2026 +0100
+Merging device-mapper/for-next (55c99f2d901c7 dm-zoned-metadata: Use strscpy() to copy device name)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm.git device-mapper/for-next
+Already up to date.
+Merging libata/for-next (e64e6b5dc8675 ata: libata-scsi: scale DSM TRIM payload by MAX PAGES PER DSM COMMAND)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/libata/linux libata/for-next
+Merge made by the 'ort' strategy.
+ drivers/ata/libata-core.c | 6 +-
+ drivers/ata/libata-scsi.c | 418 +++++++++++++++++++++++++++++++++++-----------
+ drivers/ata/libata.h | 2 +-
+ include/linux/ata.h | 13 ++
+ 4 files changed, 335 insertions(+), 104 deletions(-)
+Merging pcmcia/pcmcia-next (b3c26ea81ccc5 pcmcia: remove obsolete host controller drivers)
+$ git merge -m Merge branch 'pcmcia-next' of https://git.kernel.org/pub/scm/linux/kernel/git/brodo/linux.git pcmcia/pcmcia-next
+Already up to date.
+Merging mmc/next (df92d47b3ae73 mmc: Merge branch fixes into next)
+$ git merge -m Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc.git mmc/next
+Auto-merging MAINTAINERS
+Merge made by the 'ort' strategy.
+ .../devicetree/bindings/mmc/qcom,sdhci-msm.yaml | 95 ++++++++++-----
+ Documentation/devicetree/bindings/mmc/sdhci-st.txt | 110 -----------------
+ .../devicetree/bindings/mmc/st,sdhci.yaml | 105 +++++++++++++++++
+ .../devicetree/bindings/mmc/ti,omap2420-mmc.yaml | 60 ++++++++++
+ Documentation/devicetree/bindings/mmc/ti-omap.txt | 26 ----
+ MAINTAINERS | 7 ++
+ arch/arm/boot/dts/st/stih407-family.dtsi | 4 +-
+ arch/arm/boot/dts/st/stih410-b2260.dts | 4 +-
+ arch/arm/boot/dts/st/stih418-b2199.dts | 4 +-
+ arch/arm/boot/dts/st/stih418.dtsi | 2 +-
+ drivers/mmc/core/sd.c | 9 +-
+ drivers/mmc/host/cqhci-core.c | 17 ++-
+ drivers/mmc/host/cqhci.h | 3 +-
+ drivers/mmc/host/dw_mmc.c | 1 +
+ drivers/mmc/host/litex_mmc.c | 131 +++++----------------
+ drivers/mmc/host/moxart-mmc.c | 11 +-
+ drivers/mmc/host/mtk-sd.c | 2 +-
+ drivers/mmc/host/pxamci.c | 3 +-
+ drivers/mmc/host/sdhci-brcmstb.c | 2 +-
+ drivers/mmc/host/sdhci-esdhc-imx.c | 2 +-
+ drivers/mmc/host/sdhci-esdhc-mcf.c | 24 ++--
+ drivers/mmc/host/sdhci-msm.c | 2 +-
+ drivers/mmc/host/sdhci-of-arasan.c | 2 +-
+ drivers/mmc/host/sdhci-of-dwcmshc.c | 2 +-
+ drivers/mmc/host/sdhci-of-ma35d1.c | 1 +
+ drivers/mmc/host/sdhci-pci-core.c | 2 +-
+ drivers/mmc/host/sdhci-pci-gli.c | 2 +-
+ drivers/mmc/host/sdhci-tegra.c | 2 +-
+ drivers/mmc/host/sdhci_am654.c | 2 +-
+ drivers/mmc/host/wbsd.c | 6 +-
+ include/linux/soc/pxa/cpu.h | 56 ---------
+ 31 files changed, 325 insertions(+), 374 deletions(-)
+ delete mode 100644 Documentation/devicetree/bindings/mmc/sdhci-st.txt
+ create mode 100644 Documentation/devicetree/bindings/mmc/st,sdhci.yaml
+ create mode 100644 Documentation/devicetree/bindings/mmc/ti,omap2420-mmc.yaml
+ delete mode 100644 Documentation/devicetree/bindings/mmc/ti-omap.txt
+Merging mfd/for-mfd-next (6384e5c5e0bcf mfd: Unify style of spi_device_id arrays)
+$ git merge -m Merge branch 'for-mfd-next' of https://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git mfd/for-mfd-next
+Auto-merging MAINTAINERS
+Auto-merging drivers/mfd/cs42l43-i2c.c
+Auto-merging drivers/mfd/cs42l43-sdw.c
+Auto-merging drivers/mfd/motorola-cpcap.c
+Auto-merging drivers/mfd/ocelot-spi.c
+Merge made by the 'ort' strategy.
+ Documentation/devicetree/bindings/Makefile | 2 +-
+ .../bindings/mfd/marvell,88pm886-a1.yaml | 2 +-
+ .../bindings/mfd/mediatek,mt8195-scpsys.yaml | 1 +
+ .../devicetree/bindings/mfd/qcom,spmi-pmic.yaml | 1 +
+ .../devicetree/bindings/mfd/syscon-common.yaml | 34 ++
+ Documentation/devicetree/bindings/mfd/syscon.yaml | 116 -----
+ MAINTAINERS | 11 +
+ arch/arm/mach-ux500/cpu-db8500.c | 6 +-
+ drivers/clk/ux500/clk-prcmu.c | 20 +-
+ drivers/clk/ux500/u8500_of_clk.c | 2 +-
+ drivers/cpuidle/cpuidle-ux500.c | 6 +-
+ drivers/mfd/88pm886.c | 21 +-
+ drivers/mfd/Kconfig | 1 -
+ drivers/mfd/ab8500-core.c | 2 +-
+ drivers/mfd/altera-a10sr.c | 2 +-
+ drivers/mfd/arizona-spi.c | 12 +-
+ drivers/mfd/axp20x.c | 2 +-
+ drivers/mfd/cs40l50-spi.c | 4 +-
+ drivers/mfd/cs42l43-i2c.c | 2 -
+ drivers/mfd/cs42l43-sdw.c | 7 -
+ drivers/mfd/cs42l43.c | 15 +-
+ drivers/mfd/da9052-spi.c | 12 +-
+ drivers/mfd/db8500-prcmu.c | 6 +-
+ drivers/mfd/intel-m10-bmc-spi.c | 6 +-
+ drivers/mfd/ipaq-micro.c | 2 +-
+ drivers/mfd/madera-spi.c | 18 +-
+ drivers/mfd/motorola-cpcap.c | 6 +-
+ drivers/mfd/mt6397-core.c | 3 +
+ drivers/mfd/ocelot-spi.c | 2 +-
+ drivers/mfd/rk8xx-spi.c | 2 +-
+ drivers/mfd/rohm-bd71828.c | 125 +++--
+ drivers/mfd/rohm-bd718x7.c | 123 +++--
+ drivers/mfd/rsmu_spi.c | 12 +-
+ drivers/mfd/si476x-cmd.c | 1 -
+ drivers/mfd/si476x-i2c.c | 46 +-
+ drivers/mfd/sprd-sc27xx-spi.c | 3 +-
+ drivers/mfd/stmpe-spi.c | 12 +-
+ drivers/mfd/tps65912-spi.c | 2 +-
+ drivers/mfd/viperboard.c | 3 +-
+ drivers/mfd/wm831x-spi.c | 16 +-
+ drivers/regulator/db8500-prcmu.c | 12 +-
+ drivers/thermal/db8500_thermal.c | 10 +-
+ drivers/watchdog/db8500_wdt.c | 22 +-
+ include/linux/mfd/88pm886.h | 5 +
+ include/linux/mfd/cs42l43.h | 2 -
+ include/linux/mfd/db8500-prcmu.h | 252 ++++++++-
+ include/linux/mfd/dbx500-prcmu.h | 575 ---------------------
+ include/linux/mfd/si476x-core.h | 5 +-
+ include/linux/mfd/si476x-platform.h | 2 -
+ sound/soc/ux500/ux500_msp_dai.c | 2 +-
+ 50 files changed, 637 insertions(+), 919 deletions(-)
+ delete mode 100644 include/linux/mfd/dbx500-prcmu.h
+Merging backlight/for-backlight-next (4b3f5baf67dea MAINTAINERS: Update my email address for the AW99706 backlight driver)
+$ git merge -m Merge branch 'for-backlight-next' of https://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight.git backlight/for-backlight-next
+Auto-merging MAINTAINERS
+Merge made by the 'ort' strategy.
+ .../bindings/leds/backlight/awinic,aw99706.yaml | 2 +-
+ .../bindings/leds/backlight/silergy,sy7758.yaml | 52 +++++
+ MAINTAINERS | 2 +-
+ drivers/video/backlight/Kconfig | 8 +
+ drivers/video/backlight/Makefile | 1 +
+ drivers/video/backlight/sy7758.c | 259 +++++++++++++++++++++
+ 6 files changed, 322 insertions(+), 2 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/leds/backlight/silergy,sy7758.yaml
+ create mode 100644 drivers/video/backlight/sy7758.c
+Merging battery/for-next (a888754e51e91 Documentation: ABI: sysfs-class-reboot-mode-reboot_modes: fix doc warnings)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply.git battery/for-next
+Already up to date.
+Merging regulator/for-next (6b65d28d91d78 Merge remote-tracking branch 'regulator/for-7.3' into regulator-next)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git regulator/for-next
+Merge made by the 'ort' strategy.
+ .../regulator/qcom,sdm845-refgen-regulator.yaml | 31 +-
+ .../regulator/qcom,usb-vbus-regulator.yaml | 50 ++-
+ .../bindings/regulator/richtek,rtq2208.yaml | 4 +-
+ .../bindings/regulator/rohm,bd71815-regulator.yaml | 27 +-
+ .../bindings/regulator/rohm,bd71828-regulator.yaml | 20 +-
+ .../bindings/regulator/rohm,bd71837-regulator.yaml | 16 +-
+ .../bindings/regulator/rohm,bd71847-regulator.yaml | 16 +-
+ .../bindings/regulator/rohm,bd72720-regulator.yaml | 40 +--
+ .../bindings/regulator/rohm,pmic-states.yaml | 57 ++++
+ drivers/regulator/88pg86x.c | 4 +-
+ drivers/regulator/Kconfig | 7 +
+ drivers/regulator/Makefile | 1 +
+ drivers/regulator/act8865-regulator.c | 2 +-
+ drivers/regulator/ad5398.c | 4 +-
+ drivers/regulator/adp5055-regulator.c | 4 +-
+ drivers/regulator/as3722-regulator.c | 1 -
+ drivers/regulator/aw37503-regulator.c | 4 +-
+ drivers/regulator/da9121-regulator.c | 20 +-
+ drivers/regulator/da9210-regulator.c | 4 +-
+ drivers/regulator/da9211-regulator.c | 18 +-
+ drivers/regulator/fan53880.c | 4 +-
+ drivers/regulator/isl6271a-regulator.c | 2 +-
+ drivers/regulator/isl9305.c | 4 +-
+ drivers/regulator/lp3971.c | 2 +-
+ drivers/regulator/lp3972.c | 2 +-
+ drivers/regulator/lp872x.c | 4 +-
+ drivers/regulator/lp8755.c | 4 +-
+ drivers/regulator/ltc3589.c | 6 +-
+ drivers/regulator/ltc3676.c | 2 +-
+ drivers/regulator/max14577-regulator.c | 103 +++++-
+ drivers/regulator/max1586.c | 2 +-
+ drivers/regulator/max20086-regulator.c | 8 +-
+ drivers/regulator/max20411-regulator.c | 2 +-
+ drivers/regulator/max77503-regulator.c | 2 +-
+ drivers/regulator/max77675-regulator.c | 2 +-
+ drivers/regulator/max77826-regulator.c | 2 +-
+ drivers/regulator/max77838-regulator.c | 2 +-
+ drivers/regulator/max77857-regulator.c | 8 +-
+ drivers/regulator/max8649.c | 2 +-
+ drivers/regulator/max8893.c | 2 +-
+ drivers/regulator/max8952.c | 2 +-
+ drivers/regulator/max8973-regulator.c | 6 +-
+ drivers/regulator/max8998.c | 1 -
+ drivers/regulator/mcp16502.c | 2 +-
+ drivers/regulator/mp5416.c | 6 +-
+ drivers/regulator/mp8859.c | 4 +-
+ drivers/regulator/mp886x.c | 6 +-
+ drivers/regulator/mpq7920.c | 4 +-
+ drivers/regulator/mt6311-regulator.c | 4 +-
+ drivers/regulator/pf530x-regulator.c | 8 +-
+ drivers/regulator/pf8x00-regulator.c | 8 +-
+ drivers/regulator/pv88060-regulator.c | 4 +-
+ drivers/regulator/pv88080-regulator.c | 8 +-
+ drivers/regulator/pv88090-regulator.c | 4 +-
+ drivers/regulator/qcom-refgen-regulator.c | 113 ++++++-
+ drivers/regulator/qcom_usb_vbus-regulator.c | 102 +++++-
+ drivers/regulator/rtq2208-regulator.c | 7 +-
+ drivers/regulator/sc2730-regulator.c | 375 +++++++++++++++++++++
+ drivers/regulator/sgm3804-regulator.c | 2 +-
+ drivers/regulator/slg51000-regulator.c | 4 +-
+ drivers/regulator/sy8106a-regulator.c | 2 +-
+ drivers/regulator/sy8824x.c | 8 +-
+ drivers/regulator/sy8827n.c | 4 +-
+ drivers/regulator/tps51632-regulator.c | 4 +-
+ drivers/regulator/tps62360-regulator.c | 10 +-
+ drivers/regulator/tps6286x-regulator.c | 10 +-
+ drivers/regulator/tps6287x-regulator.c | 10 +-
+ drivers/regulator/tps65023-regulator.c | 6 +-
+ drivers/regulator/tps65132-regulator.c | 4 +-
+ drivers/regulator/tps6594-regulator.c | 19 +-
+ include/linux/mfd/max14577-private.h | 3 +
+ 71 files changed, 982 insertions(+), 263 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/regulator/rohm,pmic-states.yaml
+ create mode 100644 drivers/regulator/sc2730-regulator.c
+Merging security/next (0cee720cfd514 selftests/lsm: Fix memory leak in attr_lsm_count)
+$ git merge -m Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/lsm.git security/next
+Merge made by the 'ort' strategy.
+ Documentation/security/credentials.rst | 6 ++----
+ Documentation/translations/zh_CN/security/credentials.rst | 4 +---
+ include/linux/cred.h | 1 -
+ rust/helpers/task.c | 5 -----
+ rust/kernel/task.rs | 11 ++---------
+ security/security.c | 5 ++---
+ tools/testing/selftests/lsm/common.c | 4 +++-
+ 7 files changed, 10 insertions(+), 26 deletions(-)
+Merging apparmor/apparmor-next (dda61023f976d apparmor: fix alternate loaders ability to load compressed policy)
+$ git merge -m Merge branch 'apparmor-next' of https://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor apparmor/apparmor-next
+Merge made by the 'ort' strategy.
+ security/apparmor/af_unix.c | 1 +
+ security/apparmor/apparmorfs.c | 129 +++++++++++++++++++++++++++++-
+ security/apparmor/domain.c | 1 +
+ security/apparmor/include/apparmorfs.h | 3 +
+ security/apparmor/include/capability.h | 1 +
+ security/apparmor/include/path.h | 3 +
+ security/apparmor/include/policy.h | 4 +-
+ security/apparmor/include/policy_unpack.h | 4 +-
+ security/apparmor/include/procattr.h | 2 +
+ security/apparmor/include/task.h | 5 ++
+ security/apparmor/policy.c | 8 +-
+ security/apparmor/policy_unpack.c | 24 +++++-
+ 12 files changed, 174 insertions(+), 11 deletions(-)
+Merging integrity/next-integrity (81429cd0161ae security: ima: rename boot_aggregate when ima is initialised at late_sync)
+$ git merge -m Merge branch 'next-integrity' of https://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity integrity/next-integrity
+Merge made by the 'ort' strategy.
+ include/linux/lsm_hooks.h | 2 ++
+ security/integrity/ima/Kconfig | 10 ++++++++++
+ security/integrity/ima/ima.h | 1 +
+ security/integrity/ima/ima_init.c | 15 +++++++++++----
+ security/integrity/ima/ima_main.c | 4 ++++
+ security/integrity/ima/ima_template_lib.c | 3 ++-
+ security/lsm_init.c | 13 +++++++++++--
+ 7 files changed, 41 insertions(+), 7 deletions(-)
+Merging selinux/next (9a66a80db12e2 Automated merge of 'dev' into 'next')
+$ git merge -m Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux.git selinux/next
+Merge made by the 'ort' strategy.
+ security/selinux/avc.c | 3 +--
+ security/selinux/hooks.c | 44 +++++++++++++++++++++++++++++-------------
+ security/selinux/selinuxfs.c | 19 ++++++++++++------
+ security/selinux/ss/policydb.c | 11 ++++++++---
+ security/selinux/ss/services.c | 18 ++++++++---------
+ 5 files changed, 62 insertions(+), 33 deletions(-)
+Merging smack/next (a7c44fd9f80e3 smack: restrict smackfs/{direct,mapped} values to 0-255)
+$ git merge -m Merge branch 'next' of https://github.com/cschaufler/smack-next smack/next
+Auto-merging security/smack/smack_lsm.c
+Merge made by the 'ort' strategy.
+ security/smack/smack.h | 6 +-
+ security/smack/smack_access.c | 9 ++
+ security/smack/smack_lsm.c | 69 +++++++++----
+ security/smack/smackfs.c | 224 +++++++++++++-----------------------------
+ 4 files changed, 130 insertions(+), 178 deletions(-)
+Merging tomoyo/master (38fe7c9c3dcad kcov: fix data corruption and race conditions on PREEMPT_RT by moving saved remote state to task_struct)
+$ git merge -m Merge branch 'master' of git://git.code.sf.net/p/tomoyo/tomoyo.git tomoyo/master
+Auto-merging fs/namespace.c
+Auto-merging include/linux/sched.h
+Auto-merging lib/Kconfig.debug
+Auto-merging net/core/dev.c
+Auto-merging net/core/lock_debug.c
+Auto-merging net/socket.c
+Merge made by the 'ort' strategy.
+ drivers/block/loop.c | 87 ++++++++++++++++++++-
+ fs/namespace.c | 5 ++
+ include/linux/netdevice.h | 15 ++++
+ include/linux/sched.h | 8 ++
+ include/net/dst.h | 22 +++++-
+ include/net/sock.h | 8 +-
+ kernel/kcov.c | 82 ++++++++++----------
+ kernel/softirq.c | 4 +
+ kernel/workqueue.c | 4 +
+ lib/Kconfig.debug | 12 ++-
+ net/bridge/br_nf_core.c | 1 +
+ net/core/dev.c | 188 ++++++++++++++++++++++++++++++++++++++++++++++
+ net/core/dst.c | 85 +++++++++++++++++++++
+ net/core/lock_debug.c | 1 +
+ net/socket.c | 32 ++++++--
+ security/apparmor/Kconfig | 1 +
+ 16 files changed, 498 insertions(+), 57 deletions(-)
+Merging tpmdd-tpm/for-next-tpm (4ece5759c1a29 tpm: tpm_i2c_nuvoton: disable IRQ on wait timeout)
+$ git merge -m Merge branch 'for-next-tpm' of https://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd.git tpmdd-tpm/for-next-tpm
+Merge made by the 'ort' strategy.
+ drivers/char/tpm/tpm_i2c_nuvoton.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+Merging tpmdd-keys/for-next-keys (51cb1aa1250c3 Merge tag 'loongarch-7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson)
+$ git merge -m Merge branch 'for-next-keys' of https://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd.git tpmdd-keys/for-next-keys
+Already up to date.
+Merging watchdog/watchdog-next (a182c680d77fe watchdog: pretimeout: Add "dump" pretimeout governor)
+$ git merge -m Merge branch 'watchdog-next' of https://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git watchdog/watchdog-next
+Auto-merging drivers/watchdog/cros_ec_wdt.c
+Auto-merging drivers/watchdog/max63xx_wdt.c
+Auto-merging drivers/watchdog/max77620_wdt.c
+Merge made by the 'ort' strategy.
+ .../devicetree/bindings/watchdog/apple,wdt.yaml | 1 +
+ .../devicetree/bindings/watchdog/qcom-wdt.yaml | 1 +
+ drivers/watchdog/Kconfig | 19 ++++++++-
+ drivers/watchdog/Makefile | 1 +
+ drivers/watchdog/cros_ec_wdt.c | 4 +-
+ drivers/watchdog/max63xx_wdt.c | 14 +++----
+ drivers/watchdog/max77620_wdt.c | 6 +--
+ drivers/watchdog/pretimeout_dump.c | 45 ++++++++++++++++++++++
+ drivers/watchdog/watchdog_pretimeout.h | 4 +-
+ 9 files changed, 81 insertions(+), 14 deletions(-)
+ create mode 100644 drivers/watchdog/pretimeout_dump.c
+Merging iommu/next (750356af88d61 Merge branches 'mediatek', 'qualcomm/msm', 'riscv', 'amd/amd-vi' and 'core' into next)
+$ git merge -m Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/iommu/linux.git iommu/next
+Merge made by the 'ort' strategy.
+ drivers/iommu/amd/init.c | 57 ++++++++++++++++++++++-------
+ drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 9 ++++-
+ drivers/iommu/intel/iommu.c | 15 ++++++--
+ drivers/iommu/msm_iommu.c | 2 +-
+ drivers/iommu/mtk_iommu_v1.c | 2 +-
+ drivers/iommu/riscv/iommu-pci.c | 6 +--
+ drivers/pci/ats.c | 13 +++++--
+ rust/kernel/iommu/pgtable.rs | 3 +-
+ 8 files changed, 78 insertions(+), 29 deletions(-)
+Merging audit/next (1715cd1303c70 Automated merge of 'dev' into 'next')
+$ git merge -m Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/audit.git audit/next
+Merge made by the 'ort' strategy.
+ include/asm-generic/audit_change_attr.h | 3 +++
+ include/asm-generic/audit_read.h | 31 +++++++++++++++++++++++++++++++
+ include/asm-generic/audit_write.h | 3 +++
+ kernel/audit.c | 21 ++++++++++++++-------
+ 4 files changed, 51 insertions(+), 7 deletions(-)
+Merging devicetree/for-next (4ec74681d93e8 dt-bindings: bus: Convert DA8XX MSTPRI to DT schema)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git devicetree/for-next
+Auto-merging Documentation/devicetree/bindings/arm/qcom.yaml
+Auto-merging Documentation/devicetree/bindings/clock/qcom,rpmcc.yaml
+Auto-merging Documentation/devicetree/bindings/regulator/richtek,rtq2208.yaml
+Merge made by the 'ort' strategy.
+ .../devicetree/bindings/arm/qcom-soc.yaml | 4 +-
+ Documentation/devicetree/bindings/arm/qcom.yaml | 4 +-
+ .../bindings/arm/samsung/samsung-soc.yaml | 4 +-
+ Documentation/devicetree/bindings/arm/xen.txt | 62 ------------
+ Documentation/devicetree/bindings/arm/xen.yaml | 110 +++++++++++++++++++++
+ .../devicetree/bindings/bus/ti,da850-mstpri.txt | 20 ----
+ .../devicetree/bindings/bus/ti,da850-mstpri.yaml | 37 +++++++
+ .../bindings/clock/qcom,dispcc-sm8x50.yaml | 2 +-
+ .../bindings/clock/qcom,gcc-apq8064.yaml | 2 +-
+ .../bindings/clock/qcom,gcc-apq8084.yaml | 2 +-
+ .../bindings/clock/qcom,gcc-ipq6018.yaml | 2 +-
+ .../bindings/clock/qcom,gcc-ipq8064.yaml | 2 +-
+ .../bindings/clock/qcom,gcc-mdm9607.yaml | 2 +-
+ .../bindings/clock/qcom,gcc-mdm9615.yaml | 2 +-
+ .../bindings/clock/qcom,gcc-msm8660.yaml | 2 +-
+ .../bindings/clock/qcom,gcc-msm8909.yaml | 2 +-
+ .../bindings/clock/qcom,gcc-msm8916.yaml | 2 +-
+ .../bindings/clock/qcom,gcc-msm8953.yaml | 2 +-
+ .../bindings/clock/qcom,gcc-msm8974.yaml | 2 +-
+ .../devicetree/bindings/clock/qcom,gcc-sdm660.yaml | 2 +-
+ .../devicetree/bindings/clock/qcom,gpucc.yaml | 2 +-
+ .../bindings/clock/qcom,ipq5018-gcc.yaml | 2 +-
+ .../bindings/clock/qcom,ipq9574-gcc.yaml | 2 +-
+ .../bindings/clock/qcom,qca8k-nsscc.yaml | 2 +-
+ .../bindings/clock/qcom,qcm2290-gpucc.yaml | 2 +-
+ .../devicetree/bindings/clock/qcom,rpmcc.yaml | 2 +-
+ .../bindings/clock/qcom,sc7280-lpasscorecc.yaml | 2 +-
+ .../bindings/clock/qcom,sc8280xp-lpasscc.yaml | 2 +-
+ .../bindings/clock/qcom,sm6115-lpasscc.yaml | 2 +-
+ .../bindings/clock/qcom,sm8350-videocc.yaml | 2 +-
+ .../devicetree/bindings/clock/qcom,videocc.yaml | 2 +-
+ .../bindings/clock/samsung,exynos5260-clock.yaml | 6 +-
+ .../bindings/clock/samsung,exynos5410-clock.yaml | 2 +-
+ .../bindings/clock/samsung,exynos5433-clock.yaml | 2 +-
+ .../bindings/clock/samsung,exynos7-clock.yaml | 2 +-
+ .../bindings/clock/samsung,exynos850-clock.yaml | 2 +-
+ .../bindings/clock/samsung,exynosautov9-clock.yaml | 2 +-
+ .../clock/samsung,exynosautov920-clock.yaml | 2 +-
+ .../bindings/clock/samsung,s5pv210-clock.yaml | 2 +-
+ .../bindings/display/msm/dsi-controller-main.yaml | 20 ++--
+ .../bindings/display/samsung/samsung,fimd.yaml | 4 +-
+ .../bindings/display/verisilicon,dc.yaml | 2 +
+ .../bindings/i2c/samsung,s3c2410-i2c.yaml | 2 +-
+ .../bindings/interconnect/qcom,msm8998-bwmon.yaml | 2 +-
+ .../bindings/interconnect/samsung,exynos-bus.yaml | 14 +--
+ .../devicetree/bindings/leds/qcom,pm8058-led.yaml | 4 +-
+ .../devicetree/bindings/leds/skyworks,aat1290.yaml | 6 +-
+ .../devicetree/bindings/media/cec/cec-gpio.yaml | 2 +-
+ .../bindings/mmc/samsung,exynos-dw-mshc.yaml | 2 +-
+ .../bindings/phy/samsung,mipi-video-phy.yaml | 4 +-
+ .../devicetree/bindings/phy/samsung,usb2-phy.yaml | 2 +-
+ .../bindings/phy/samsung,usb3-drd-phy.yaml | 2 +-
+ .../bindings/pinctrl/samsung,pinctrl.yaml | 2 +-
+ .../bindings/power/renesas,rcar-sysc.yaml | 2 +-
+ .../bindings/power/reset/restart-handler.yaml | 8 +-
+ .../bindings/regulator/maxim,max77802.yaml | 4 +-
+ .../bindings/regulator/richtek,rtq2208.yaml | 2 +-
+ .../bindings/serial/qcom,msm-uartdm.yaml | 2 +-
+ .../devicetree/bindings/slimbus/slimbus.yaml | 4 +-
+ .../bindings/soc/qcom/qcom,apr-services.yaml | 2 +-
+ .../bindings/soc/qcom/qcom,rpmh-rsc.yaml | 8 +-
+ .../devicetree/bindings/soc/qcom/qcom,wcnss.yaml | 2 +-
+ .../bindings/soc/renesas/renesas-soc.yaml | 4 +-
+ .../devicetree/bindings/sound/qcom,q6asm-dais.yaml | 2 +-
+ .../devicetree/bindings/sram/qcom,imem.yaml | 20 ++++
+ .../bindings/thermal/samsung,exynos-thermal.yaml | 4 +-
+ .../devicetree/bindings/usb/qcom,dwc3.yaml | 12 +--
+ .../devicetree/bindings/usb/qcom,snps-dwc3.yaml | 12 +--
+ 68 files changed, 276 insertions(+), 189 deletions(-)
+ delete mode 100644 Documentation/devicetree/bindings/arm/xen.txt
+ create mode 100644 Documentation/devicetree/bindings/arm/xen.yaml
+ delete mode 100644 Documentation/devicetree/bindings/bus/ti,da850-mstpri.txt
+ create mode 100644 Documentation/devicetree/bindings/bus/ti,da850-mstpri.yaml
+Merging dt-krzk/for-next (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-dt.git dt-krzk/for-next
+Already up to date.
+Merging mailbox/for-next (36cac4b5101f8 mailbox: imx: Don't force-thread the primary handler)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/jassibrar/mailbox.git mailbox/for-next
+Already up to date.
+Merging spi/for-next (5f1b513690edf Merge remote-tracking branch 'spi/for-7.3' into spi-next)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git spi/for-next
+Merge made by the 'ort' strategy.
+ .../bindings/spi/cavium,octeon-3010-spi.yaml | 61 ++++++++++++
+ .../bindings/spi/qcom,sa8255p-geni-spi.yaml | 64 +++++++++++++
+ .../devicetree/bindings/spi/spi-octeon.txt | 33 -------
+ .../devicetree/bindings/spi/st,stm32-qspi.yaml | 3 +
+ drivers/spi/spi-atcspi200.c | 5 +-
+ drivers/spi/spi-bcm-qspi.c | 6 +-
+ drivers/spi/spi-bcm63xx-hsspi.c | 6 +-
+ drivers/spi/spi-bcm63xx.c | 5 +-
+ drivers/spi/spi-bcmbca-hsspi.c | 6 +-
+ drivers/spi/spi-fsl-dspi.c | 21 ++++-
+ drivers/spi/spi-geni-qcom.c | 105 ++++++++++-----------
+ drivers/spi/spi-npcm-fiu.c | 15 +--
+ drivers/spi/spi-nxp-fspi.c | 31 ++++--
+ drivers/spi/spi-qpic-snand.c | 6 +-
+ 14 files changed, 256 insertions(+), 111 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/spi/cavium,octeon-3010-spi.yaml
+ create mode 100644 Documentation/devicetree/bindings/spi/qcom,sa8255p-geni-spi.yaml
+ delete mode 100644 Documentation/devicetree/bindings/spi/spi-octeon.txt
+Merging tip/master (c50d2a841739b Merge branch into tip/master: 'x86/msr')
+$ git merge -m Merge branch 'master' of https://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git tip/master
+Auto-merging MAINTAINERS
+Auto-merging arch/x86/events/intel/ds.c
+Auto-merging arch/x86/include/asm/pgtable.h
+Auto-merging arch/x86/kvm/vmx/vmx.c
+Auto-merging drivers/irqchip/irq-gic-v5-iwb.c
+Auto-merging include/linux/cpuset.h
+Auto-merging include/linux/sched.h
+Auto-merging kernel/cgroup/cpuset.c
+Auto-merging kernel/events/core.c
+Auto-merging kernel/fork.c
+Auto-merging kernel/irq/manage.c
+Auto-merging kernel/locking/lockdep.c
+Auto-merging tools/lib/bpf/usdt.c
+Merge made by the 'ort' strategy.
+ Documentation/admin-guide/sysctl/kernel.rst | 17 +
+ Documentation/arch/x86/amd-memory-encryption.rst | 2 +-
+ .../interrupt-controller/realtek,rtl-intc.yaml | 5 +-
+ MAINTAINERS | 1 +
+ arch/Kconfig | 10 +
+ arch/arm/vdso/vdso.lds.S | 2 +
+ arch/arm/vdso/vgettimeofday.c | 14 +-
+ arch/arm64/kernel/vdso32/vdso.lds.S | 2 +
+ arch/arm64/kernel/vdso32/vgettimeofday.c | 14 +-
+ arch/mips/vdso/vdso.lds.S | 2 +
+ arch/mips/vdso/vgettimeofday.c | 3 +
+ arch/parisc/kernel/smp.c | 2 +-
+ arch/powerpc/kernel/vdso/gettimeofday.S | 8 +
+ arch/powerpc/kernel/vdso/vdso32.lds.S | 8 +-
+ arch/powerpc/kernel/vdso/vgettimeofday.c | 16 +-
+ arch/sparc/vdso/vclock_gettime.c | 4 +
+ arch/sparc/vdso/vdso32/vdso32.lds.S | 6 +-
+ arch/um/include/asm/cpufeature.h | 16 +-
+ arch/x86/boot/compressed/head_64.S | 18 +-
+ arch/x86/entry/vdso/common/vclock_gettime.c | 20 +-
+ arch/x86/entry/vdso/vdso32/vdso32.lds.S | 2 +
+ arch/x86/events/amd/core.c | 2 +-
+ arch/x86/events/amd/uncore.c | 31 +
+ arch/x86/events/core.c | 3 +-
+ arch/x86/events/intel/core.c | 62 +-
+ arch/x86/events/intel/ds.c | 13 -
+ arch/x86/events/intel/lbr.c | 38 +-
+ arch/x86/events/intel/uncore.c | 227 ++--
+ arch/x86/events/intel/uncore.h | 39 +-
+ arch/x86/events/intel/uncore_discovery.c | 21 +-
+ arch/x86/events/intel/uncore_discovery.h | 6 +-
+ arch/x86/events/intel/uncore_nhmex.c | 3 +-
+ arch/x86/events/intel/uncore_snb.c | 82 +-
+ arch/x86/events/intel/uncore_snbep.c | 77 +-
+ arch/x86/events/perf_event.h | 6 +-
+ arch/x86/hyperv/hv_apic.c | 12 +-
+ arch/x86/include/asm/archrandom.h | 4 +-
+ arch/x86/include/asm/cpufeature.h | 10 +-
+ arch/x86/include/asm/debugreg.h | 2 +-
+ arch/x86/include/asm/linkage.h | 2 +-
+ arch/x86/include/asm/microcode.h | 2 -
+ arch/x86/include/asm/nospec-branch.h | 1 +
+ arch/x86/include/asm/pgtable.h | 4 +-
+ arch/x86/include/asm/processor.h | 1 +
+ arch/x86/include/asm/resctrl.h | 5 +-
+ arch/x86/include/asm/sync_core.h | 4 +-
+ arch/x86/kernel/alternative.c | 12 +-
+ arch/x86/kernel/apic/apic.c | 39 +-
+ arch/x86/kernel/apic/apic_numachip.c | 2 +-
+ arch/x86/kernel/cpu/amd.c | 34 +-
+ arch/x86/kernel/cpu/bugs.c | 10 +-
+ arch/x86/kernel/cpu/cacheinfo.c | 2 +-
+ arch/x86/kernel/cpu/centaur.c | 35 +-
+ arch/x86/kernel/cpu/common.c | 12 +-
+ arch/x86/kernel/cpu/hygon.c | 5 +-
+ arch/x86/kernel/cpu/intel.c | 43 +-
+ arch/x86/kernel/cpu/mce/amd.c | 87 +-
+ arch/x86/kernel/cpu/mce/core.c | 2 +-
+ arch/x86/kernel/cpu/mce/p5.c | 16 +-
+ arch/x86/kernel/cpu/mce/winchip.c | 10 +-
+ arch/x86/kernel/cpu/microcode/intel.c | 36 -
+ arch/x86/kernel/cpu/resctrl/core.c | 7 +-
+ arch/x86/kernel/cpu/resctrl/monitor.c | 27 +-
+ arch/x86/kernel/cpu/resctrl/pseudo_lock.c | 12 +-
+ arch/x86/kernel/cpu/transmeta.c | 9 +-
+ arch/x86/kernel/cpu/zhaoxin.c | 12 +-
+ arch/x86/kernel/fpu/core.c | 20 +-
+ arch/x86/kernel/fpu/signal.c | 2 +-
+ arch/x86/kernel/kprobes/opt.c | 2 +-
+ arch/x86/kernel/ldt.c | 2 +-
+ arch/x86/kernel/process.c | 10 +-
+ arch/x86/kernel/process_64.c | 6 +-
+ arch/x86/kernel/signal_32.c | 2 +-
+ arch/x86/kernel/time.c | 2 +-
+ arch/x86/kernel/tsc.c | 6 +-
+ arch/x86/kernel/tsc_msr.c | 15 +-
+ arch/x86/kernel/uprobes.c | 408 ++++---
+ arch/x86/kernel/vmlinux.lds.S | 8 +-
+ arch/x86/kvm/cpuid.c | 4 +-
+ arch/x86/kvm/svm/svm.c | 22 +-
+ arch/x86/kvm/vmx/vmx.c | 6 +-
+ arch/x86/kvm/x86.c | 6 +-
+ arch/x86/kvm/xen.c | 2 +-
+ arch/x86/lib/copy_mc.c | 4 +-
+ arch/x86/lib/msr-smp.c | 8 +-
+ arch/x86/lib/usercopy_32.c | 2 +-
+ arch/x86/mm/extable.c | 2 +-
+ arch/x86/mm/ident_map.c | 2 +-
+ arch/x86/mm/pat/set_memory.c | 2 +-
+ arch/x86/mm/tlb.c | 14 +-
+ arch/x86/pci/mmconfig-shared.c | 8 +-
+ arch/x86/platform/intel-quark/imr.c | 4 +-
+ arch/x86/platform/olpc/olpc-xo1-sci.c | 11 +-
+ arch/x86/ras/Kconfig | 23 -
+ drivers/edac/ie31200_edac.c | 10 +-
+ drivers/edac/mce_amd.c | 8 +-
+ drivers/firewire/ohci.c | 2 +-
+ drivers/gpu/drm/drm_cache.c | 8 +-
+ drivers/gpu/drm/i915/gem/i915_gem_domain.c | 4 +-
+ drivers/gpu/drm/i915/i915_memcpy.c | 2 +-
+ drivers/hwmon/hwmon-vid.c | 11 +-
+ drivers/irqchip/Kconfig | 5 -
+ drivers/irqchip/Makefile | 1 -
+ drivers/irqchip/irq-gic-v3-its.c | 12 +-
+ drivers/irqchip/irq-gic-v5-iwb.c | 2 +-
+ drivers/irqchip/irq-imgpdc.c | 495 --------
+ drivers/irqchip/irq-realtek-rtl.c | 152 ++-
+ drivers/irqchip/qcom-pdc.c | 548 +++++++--
+ drivers/md/dm-writecache.c | 2 +-
+ .../x86/intel/speed_select_if/isst_tpmi_core.c | 2 +-
+ drivers/ras/Kconfig | 24 +-
+ drivers/thermal/intel/therm_throt.c | 2 +-
+ include/asm-generic/vdso/vsyscall.h | 4 +-
+ include/linux/cpuset.h | 6 +
+ include/linux/entry-common.h | 6 +-
+ include/linux/hrtimer.h | 34 +-
+ include/linux/{hrtimer_defs.h => hrtimer_bases.h} | 14 +-
+ include/linux/hrtimer_rearm.h | 5 +
+ include/linux/irqdesc.h | 2 +-
+ include/linux/sched.h | 4 +-
+ include/linux/syscall_user_dispatch.h | 28 +-
+ include/linux/syscall_user_dispatch_types.h | 2 +-
+ include/linux/timekeeper_internal.h | 30 +-
+ include/linux/timekeeping.h | 10 +-
+ include/linux/uprobes.h | 5 -
+ include/uapi/linux/time_types.h | 2 +-
+ include/vdso/datapage.h | 6 +-
+ include/vdso/helpers.h | 4 +-
+ include/vdso/processor.h | 4 +-
+ include/vdso/vsyscall.h | 4 +-
+ kernel/cgroup/cpuset.c | 22 +
+ kernel/entry/Makefile | 3 +-
+ kernel/entry/syscall_user_dispatch.c | 38 +-
+ kernel/events/core.c | 41 +-
+ kernel/events/uprobes.c | 10 -
+ kernel/fork.c | 1 -
+ kernel/futex/core.c | 3 +-
+ kernel/irq/irqdesc.c | 11 +-
+ kernel/irq/irqdomain.c | 8 +-
+ kernel/irq/manage.c | 6 +-
+ kernel/locking/lockdep.c | 34 +-
+ kernel/sched/core.c | 5 +-
+ kernel/sched/deadline.c | 6 +-
+ kernel/sched/debug.c | 92 +-
+ kernel/sched/fair.c | 1226 +++++++++++---------
+ kernel/sched/pelt.c | 6 +-
+ kernel/sched/psi.c | 2 +-
+ kernel/sched/rt.c | 3 +-
+ kernel/sched/sched.h | 49 +-
+ kernel/smp.c | 26 +-
+ kernel/sys_ni.c | 4 +
+ kernel/time/clocksource.c | 9 +-
+ kernel/time/hrtimer.c | 56 +-
+ kernel/time/namespace.c | 6 +-
+ kernel/time/namespace_vdso.c | 7 +-
+ kernel/time/ntp.c | 312 ++++-
+ kernel/time/ntp_internal.h | 4 +-
+ kernel/time/posix-cpu-timers.c | 9 +-
+ kernel/time/tick-internal.h | 1 +
+ kernel/time/time.c | 25 +-
+ kernel/time/timekeeping.c | 141 ++-
+ kernel/time/timekeeping_internal.h | 21 +
+ kernel/time/timer_list.c | 17 +-
+ kernel/time/timer_migration.c | 4 +-
+ lib/vdso/datastore.c | 63 +-
+ lib/vdso/gettimeofday.c | 20 +
+ sound/drivers/dummy.c | 1 +
+ tools/lib/bpf/features.c | 4 +-
+ tools/lib/bpf/usdt.c | 16 +-
+ tools/testing/selftests/bpf/bench.c | 20 +-
+ tools/testing/selftests/bpf/benchs/bench_trigger.c | 38 +-
+ .../selftests/bpf/benchs/run_bench_uprobes.sh | 2 +-
+ .../selftests/bpf/prog_tests/uprobe_syscall.c | 325 +++++-
+ tools/testing/selftests/bpf/prog_tests/usdt.c | 74 +-
+ tools/testing/selftests/bpf/progs/test_usdt.c | 25 +
+ tools/testing/selftests/bpf/usdt.h | 2 +-
+ tools/testing/selftests/bpf/usdt_2.c | 15 +-
+ .../testing/selftests/futex/functional/.gitignore | 1 +
+ tools/testing/selftests/futex/functional/Makefile | 6 +-
+ .../futex/functional/futex_lock_pi_exiting.c | 263 +++++
+ .../selftests/futex/functional/futex_numa_mpol.c | 127 +-
+ .../selftests/futex/functional/futex_priv_hash.c | 163 +--
+ .../selftests/futex/functional/futex_requeue.c | 60 +-
+ .../selftests/futex/functional/futex_requeue_pi.c | 157 +--
+ .../functional/futex_requeue_pi_mismatched_ops.c | 41 +-
+ .../functional/futex_requeue_pi_signal_restart.c | 74 +-
+ .../selftests/futex/functional/futex_wait.c | 129 +-
+ .../functional/futex_wait_private_mapped_file.c | 36 +-
+ .../futex/functional/futex_wait_timeout.c | 106 +-
+ .../functional/futex_wait_uninitialized_heap.c | 35 +-
+ .../futex/functional/futex_wait_wouldblock.c | 34 +-
+ .../selftests/futex/functional/futex_waitv.c | 146 +--
+ .../selftests/futex/functional/robust_list.c | 183 +--
+ tools/testing/selftests/futex/functional/run.sh | 3 +
+ tools/testing/selftests/futex/include/futex2test.h | 10 +
+ .../testing/selftests/futex/include/futex_thread.h | 115 ++
+ .../selftests/rseq/rseq-x86-thread-pointer.h | 4 +-
+ tools/testing/selftests/rseq/rseq.c | 2 +-
+ .../testing/selftests/syscall_user_dispatch/config | 2 +-
+ tools/testing/selftests/timers/Makefile | 2 +-
+ tools/testing/selftests/timers/adjtick.c | 5 +-
+ .../testing/selftests/timers/alarmtimer-suspend.c | 3 +-
+ .../testing/selftests/timers/inconsistency-check.c | 3 +-
+ tools/testing/selftests/timers/leap-a-day.c | 22 +-
+ tools/testing/selftests/timers/mqueue-lat.c | 3 +-
+ tools/testing/selftests/timers/nanosleep.c | 3 +-
+ tools/testing/selftests/timers/nsleep-lat.c | 3 +-
+ tools/testing/selftests/timers/posix_timers.c | 4 +-
+ tools/testing/selftests/timers/raw_skew.c | 3 +-
+ tools/testing/selftests/timers/set-2038.c | 3 +-
+ tools/testing/selftests/timers/set-timer-lat.c | 3 +-
+ tools/testing/selftests/timers/valid-adjtimex.c | 4 +-
+ 212 files changed, 4799 insertions(+), 3076 deletions(-)
+ delete mode 100644 arch/x86/ras/Kconfig
+ delete mode 100644 drivers/irqchip/irq-imgpdc.c
+ rename include/linux/{hrtimer_defs.h => hrtimer_bases.h} (93%)
+ create mode 100644 tools/testing/selftests/futex/functional/futex_lock_pi_exiting.c
+ create mode 100644 tools/testing/selftests/futex/include/futex_thread.h
+$ git am -3 ../patches/0001-vdso-Merge-fixup-with-mm.patch
+Applying: vdso: Merge fixup with mm
+Using index info to reconstruct a base tree...
+M kernel/time/namespace_vdso.c
+Falling back to patching base and 3-way merge...
+Auto-merging kernel/time/namespace_vdso.c
+No changes -- Patch already applied.
+Merging kexec/kexec-next (af78cec42d1b0 Merge branch 'crashkernel-cma' into kexec-next)
+$ git merge -m Merge branch 'kexec-next' of https://git.kernel.org/pub/scm/linux/kernel/git/liveupdate/linux.git kexec/kexec-next
+Auto-merging Documentation/admin-guide/kernel-parameters.txt
+Auto-merging arch/riscv/mm/init.c
+Merge made by the 'ort' strategy.
+ Documentation/admin-guide/kernel-parameters.txt | 16 ++--
+ arch/arm64/kernel/machine_kexec_file.c | 40 +++-------
+ arch/arm64/mm/init.c | 5 +-
+ arch/loongarch/kernel/machine_kexec_file.c | 40 +++-------
+ arch/powerpc/include/asm/kexec_ranges.h | 1 -
+ arch/powerpc/kexec/crash.c | 5 +-
+ arch/powerpc/kexec/ranges.c | 101 +-----------------------
+ arch/riscv/kernel/machine_kexec_file.c | 39 +++------
+ arch/riscv/mm/init.c | 5 +-
+ arch/x86/kernel/crash.c | 89 +++------------------
+ drivers/of/fdt.c | 9 ++-
+ drivers/of/kexec.c | 9 +++
+ include/linux/crash_core.h | 9 +++
+ include/linux/crash_reserve.h | 4 +-
+ include/linux/kexec.h | 2 +-
+ kernel/crash_core.c | 89 ++++++++++++++++++++-
+ kernel/kexec_file.c | 27 +++++++
+ 17 files changed, 208 insertions(+), 282 deletions(-)
+Merging liveupdate/next (57e2c35f4e727 Merge branch 'misc' into next)
+$ git merge -m Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/liveupdate/linux.git liveupdate/next
+Auto-merging MAINTAINERS
+Merge made by the 'ort' strategy.
+ MAINTAINERS | 1 +
+ arch/x86/boot/compressed/kaslr.c | 2 +
+ arch/x86/include/asm/Kbuild | 1 +
+ arch/x86/include/asm/setup.h | 2 -
+ arch/x86/kernel/setup.c | 1 +
+ include/asm-generic/kexec_handover.h | 12 +
+ include/linux/kexec_handover.h | 6 +-
+ tools/testing/selftests/liveupdate/.gitignore | 1 +
+ tools/testing/selftests/liveupdate/config | 1 +
+ tools/testing/selftests/liveupdate/config.aarch64 | 2 +
+ tools/testing/selftests/liveupdate/config.x86_64 | 2 +
+ tools/testing/selftests/liveupdate/init.c | 179 ++++++++++++++
+ .../testing/selftests/liveupdate/luo_test_utils.c | 15 +-
+ tools/testing/selftests/liveupdate/run-vmtests.sh | 97 ++++++++
+ tools/testing/selftests/liveupdate/vmtest.sh | 263 +++++++++++++++++++++
+ 15 files changed, 569 insertions(+), 16 deletions(-)
+ create mode 100644 include/asm-generic/kexec_handover.h
+ create mode 100644 tools/testing/selftests/liveupdate/config.aarch64
+ create mode 100644 tools/testing/selftests/liveupdate/config.x86_64
+ create mode 100644 tools/testing/selftests/liveupdate/init.c
+ create mode 100755 tools/testing/selftests/liveupdate/run-vmtests.sh
+ create mode 100755 tools/testing/selftests/liveupdate/vmtest.sh
+Merging clockevents/timers/drivers/next (a9ac745bc320c clocksource: move NXP timer selection to drivers/clocksource)
+$ git merge -m Merge branch 'timers/drivers/next' of https://git.kernel.org/pub/scm/linux/kernel/git/daniel.lezcano/linux.git clockevents/timers/drivers/next
+Already up to date.
+Merging edac/edac-for-next (17c8b40ef28be Merge ras/edac-amd-atl into for-next)
+$ git merge -m Merge branch 'edac-for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/ras/ras.git edac/edac-for-next
+Auto-merging CREDITS
+Auto-merging MAINTAINERS
+Merge made by the 'ort' strategy.
+ CREDITS | 4 +++
+ MAINTAINERS | 10 ++-----
+ drivers/edac/amd64_edac.c | 2 ++
+ drivers/edac/debugfs.c | 65 +-------------------------------------------
+ drivers/edac/edac_mc_sysfs.c | 2 +-
+ drivers/ras/amd/atl/core.c | 1 -
+ include/linux/edac.h | 3 --
+ 7 files changed, 11 insertions(+), 76 deletions(-)
+Merging ftrace/for-next (030bb1d8bb077 Merge probes/for-next)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace.git ftrace/for-next
+Auto-merging MAINTAINERS
+Auto-merging Makefile
+Auto-merging arch/x86/Kconfig
+Auto-merging arch/x86/kernel/setup.c
+Auto-merging init/Kconfig
+Auto-merging init/main.c
+Auto-merging kernel/trace/trace.c
+Auto-merging lib/Makefile
+Merge made by the 'ort' strategy.
+ Documentation/admin-guide/bootconfig.rst | 81 +++
+ Documentation/trace/eprobetrace.rst | 7 +-
+ Documentation/trace/fprobetrace.rst | 10 +
+ Documentation/trace/kprobetrace.rst | 11 +
+ MAINTAINERS | 1 +
+ Makefile | 27 +-
+ arch/x86/Kconfig | 1 +
+ arch/x86/kernel/setup.c | 14 +-
+ include/asm-generic/kprobes.h | 4 +-
+ include/linux/bootconfig.h | 14 +
+ init/Kconfig | 36 ++
+ init/main.c | 52 +-
+ kernel/trace/Kconfig | 12 +
+ kernel/trace/trace.c | 8 +-
+ kernel/trace/trace_eprobe.c | 2 +
+ kernel/trace/trace_fprobe.c | 6 +-
+ kernel/trace/trace_kprobe.c | 2 +
+ kernel/trace/trace_probe.c | 612 +++++++++++++++++----
+ kernel/trace/trace_probe.h | 102 ++--
+ kernel/trace/trace_probe_tmpl.h | 27 +-
+ kernel/trace/trace_uprobe.c | 3 +
+ lib/Makefile | 16 +
+ lib/bootconfig.c | 139 ++++-
+ lib/embedded-cmdline.S | 16 +
+ samples/trace_events/trace-events-sample.c | 40 +-
+ samples/trace_events/trace-events-sample.h | 34 +-
+ tools/bootconfig/Makefile | 4 +-
+ tools/bootconfig/scripts/ftrace2bconf.sh | 2 +
+ .../ftrace/test.d/dynevent/btf_probe_event.tc | 51 ++
+ .../test.d/dynevent/btf_typecast_accepted.tc | 103 ++++
+ .../test.d/dynevent/eprobes_syntax_errors.tc | 12 +-
+ .../ftrace/test.d/dynevent/fprobe_syntax_errors.tc | 12 +
+ .../ftrace/test.d/kprobe/kprobe_syntax_errors.tc | 12 +
+ .../ftrace/test.d/kprobe/uprobe_syntax_errors.tc | 5 +
+ 34 files changed, 1274 insertions(+), 204 deletions(-)
+ create mode 100644 lib/embedded-cmdline.S
+ create mode 100644 tools/testing/selftests/ftrace/test.d/dynevent/btf_probe_event.tc
+ create mode 100644 tools/testing/selftests/ftrace/test.d/dynevent/btf_typecast_accepted.tc
+$ git am -3 ../patches/0001-ftrace-Fix-semantic-conflict-with-mm-tree.patch
+Applying: ftrace: Fix semantic conflict with mm tree
+Using index info to reconstruct a base tree...
+M kernel/trace/trace_printk.c
+Falling back to patching base and 3-way merge...
+Auto-merging kernel/trace/trace_printk.c
+No changes -- Patch already applied.
+Merging rcu/next (e853c1b28580e Merge branches 'rcutorture.2026.05.24' and 'misc.2026.05.24' into rcu-merge.2026.05.24)
+$ git merge -m Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/rcu/linux rcu/next
+Already up to date.
+Merging paulmck/non-rcu/next (48f7a50c027dd stop_machine: Fix the documentation for a NULL cpus argument)
+$ git merge -m Merge branch 'non-rcu/next' of https://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git paulmck/non-rcu/next
+Already up to date.
+Merging kvm/next (a204badd8432f Merge branch 'kvm-chainsaw' into HEAD)
+$ git merge -m Merge branch 'next' of git://git.kernel.org/pub/scm/virt/kvm/kvm.git kvm/next
+Auto-merging arch/x86/kvm/cpuid.c
+Auto-merging arch/x86/kvm/mmu/mmu.c
+Auto-merging arch/x86/kvm/mmu/spte.c
+Auto-merging arch/x86/kvm/pmu.c
+Auto-merging arch/x86/kvm/svm/svm.c
+Auto-merging arch/x86/kvm/vmx/vmx.c
+Auto-merging arch/x86/kvm/x86.c
+CONFLICT (content): Merge conflict in arch/x86/kvm/x86.c
+Auto-merging tools/testing/selftests/kvm/Makefile.kvm
+Resolved 'arch/x86/kvm/x86.c' using previous resolution.
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit --no-edit -v -a
+[master d9b292f64e4bc] Merge branch 'next' of git://git.kernel.org/pub/scm/virt/kvm/kvm.git
+$ git diff -M --stat --summary HEAD^..
+ arch/x86/include/asm/kvm_host.h | 655 +---
+ arch/x86/kvm/Makefile | 4 +-
+ arch/x86/kvm/cpuid.c | 1 +
+ arch/x86/kvm/fpu.h | 26 +
+ arch/x86/kvm/hyperv.c | 7 +-
+ arch/x86/kvm/hyperv.h | 3 +-
+ arch/x86/kvm/ioapic.c | 1 +
+ arch/x86/kvm/ioapic.h | 12 +
+ arch/x86/kvm/irq.c | 7 +
+ arch/x86/kvm/irq.h | 6 +
+ arch/x86/kvm/lapic.h | 8 +
+ arch/x86/kvm/mmu.h | 121 +-
+ arch/x86/kvm/mmu/mmu.c | 541 +--
+ arch/x86/kvm/mmu/mmu_internal.h | 66 -
+ arch/x86/kvm/mmu/paging_tmpl.h | 88 +-
+ arch/x86/kvm/mmu/spte.c | 4 +-
+ arch/x86/kvm/mmu/spte.h | 69 +-
+ arch/x86/kvm/mmu/tdp_mmu.c | 3 +-
+ arch/x86/kvm/msrs.c | 2745 ++++++++++++++
+ arch/x86/kvm/msrs.h | 156 +
+ arch/x86/kvm/mtrr.c | 2 +-
+ arch/x86/kvm/pmu.c | 12 +
+ arch/x86/kvm/regs.c | 874 +++++
+ arch/x86/kvm/regs.h | 60 +
+ arch/x86/kvm/svm/nested.c | 14 +-
+ arch/x86/kvm/svm/svm.c | 6 +-
+ arch/x86/kvm/tss.h | 7 +
+ arch/x86/kvm/vmx/nested.c | 16 +-
+ arch/x86/kvm/vmx/vmx.c | 26 +-
+ arch/x86/kvm/x86.c | 3762 +-------------------
+ arch/x86/kvm/x86.h | 462 ++-
+ tools/testing/selftests/kvm/Makefile.kvm | 1 +
+ tools/testing/selftests/kvm/include/x86/pmu.h | 6 +
+ .../testing/selftests/kvm/include/x86/processor.h | 10 +
+ tools/testing/selftests/kvm/include/x86/svm_util.h | 5 +-
+ tools/testing/selftests/kvm/include/x86/vmx.h | 4 +-
+ tools/testing/selftests/kvm/lib/x86/memstress.c | 19 +-
+ tools/testing/selftests/kvm/lib/x86/processor.c | 45 +-
+ tools/testing/selftests/kvm/lib/x86/svm.c | 6 +-
+ tools/testing/selftests/kvm/lib/x86/vmx.c | 6 +-
+ tools/testing/selftests/kvm/x86/aperfmperf_test.c | 9 +-
+ .../selftests/kvm/x86/evmcs_smm_controls_test.c | 5 +-
+ tools/testing/selftests/kvm/x86/hyperv_evmcs.c | 6 +-
+ tools/testing/selftests/kvm/x86/hyperv_svm_test.c | 6 +-
+ tools/testing/selftests/kvm/x86/kvm_buslock_test.c | 9 +-
+ .../selftests/kvm/x86/nested_close_kvm_test.c | 12 +-
+ .../selftests/kvm/x86/nested_dirty_log_test.c | 8 +-
+ .../selftests/kvm/x86/nested_emulation_test.c | 4 +-
+ .../selftests/kvm/x86/nested_exceptions_test.c | 9 +-
+ .../selftests/kvm/x86/nested_invalid_cr3_test.c | 10 +-
+ .../selftests/kvm/x86/nested_tdp_fault_test.c | 9 +-
+ .../selftests/kvm/x86/nested_tsc_adjust_test.c | 10 +-
+ .../selftests/kvm/x86/nested_tsc_scaling_test.c | 10 +-
+ .../selftests/kvm/x86/nested_vmsave_vmload_test.c | 6 +-
+ tools/testing/selftests/kvm/x86/smm_test.c | 8 +-
+ tools/testing/selftests/kvm/x86/state_test.c | 11 +-
+ tools/testing/selftests/kvm/x86/svm_int_ctl_test.c | 5 +-
+ .../selftests/kvm/x86/svm_lbr_nested_state.c | 6 +-
+ .../selftests/kvm/x86/svm_nested_clear_efer_svme.c | 7 +-
+ .../selftests/kvm/x86/svm_nested_pat_test.c | 8 +-
+ .../selftests/kvm/x86/svm_nested_shutdown_test.c | 5 +-
+ .../kvm/x86/svm_nested_soft_inject_test.c | 6 +-
+ .../selftests/kvm/x86/svm_nested_vmcb12_gpa.c | 13 +-
+ .../selftests/kvm/x86/svm_pmu_host_guest_test.c | 215 ++
+ tools/testing/selftests/kvm/x86/svm_vmcall_test.c | 5 +-
+ .../selftests/kvm/x86/triple_fault_event_test.c | 9 +-
+ .../selftests/kvm/x86/vmx_apic_access_test.c | 5 +-
+ .../selftests/kvm/x86/vmx_apicv_updates_test.c | 4 +-
+ .../kvm/x86/vmx_invalid_nested_guest_state.c | 6 +-
+ .../selftests/kvm/x86/vmx_nested_la57_state_test.c | 5 +-
+ .../selftests/kvm/x86/vmx_preemption_timer_test.c | 5 +-
+ 71 files changed, 5273 insertions(+), 5029 deletions(-)
+ create mode 100644 arch/x86/kvm/msrs.c
+ create mode 100644 arch/x86/kvm/msrs.h
+ create mode 100644 arch/x86/kvm/regs.c
+ create mode 100644 tools/testing/selftests/kvm/x86/svm_pmu_host_guest_test.c
+$ git am -3 ../patches/kvm-x86-static-cpu-has
+Patch format detection failed.
+Merging kvm-arm/next (1ee27dacbe5dc Merge branch kvm-arm64/nv-mmu-7.2 into kvmarm-master/next)
+$ git merge -m Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm.git kvm-arm/next
+Already up to date.
+Merging kvms390/next (babe08404e199 KVM: s390: Return failure in case of failure in kvm_s390_set_cmma_bits())
+$ git merge -m Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux.git kvms390/next
+Already up to date.
+Merging kvm-ppc/topic/ppc-kvm (8cdeaa50eae8d Linux 7.2-rc2)
+$ git merge -m Merge branch 'topic/ppc-kvm' of https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git kvm-ppc/topic/ppc-kvm
+Already up to date.
+Merging kvm-riscv/riscv_kvm_next (52738352a6f29 riscv: kvm: Use endian-specific __lelong for NACL shared memory)
+$ git merge -m Merge branch 'riscv_kvm_next' of https://github.com/kvm-riscv/linux.git kvm-riscv/riscv_kvm_next
+Already up to date.
+Merging kvm-x86/next (f1e5ada5ab62d Merge branches 'fixes', 'generic', 'irq_test', 'misc', 'svm' and 'vmx')
+$ git merge -m Merge branch 'next' of https://github.com/kvm-x86/linux.git kvm-x86/next
+Auto-merging arch/x86/kvm/cpuid.c
+Auto-merging arch/x86/kvm/svm/svm.c
+Auto-merging arch/x86/kvm/vmx/vmx.c
+Auto-merging arch/x86/kvm/x86.c
+Auto-merging arch/x86/kvm/xen.c
+Auto-merging tools/testing/selftests/kvm/Makefile.kvm
+Auto-merging virt/kvm/kvm_main.c
+Merge made by the 'ort' strategy.
+ arch/x86/include/asm/kvm-x86-nested-ops.h | 36 ++
+ arch/x86/include/asm/kvm_host.h | 206 +-----------
+ arch/x86/kvm/cpuid.c | 12 +-
+ arch/x86/kvm/emulate.c | 49 ++-
+ arch/x86/kvm/hyperv.c | 70 ++--
+ arch/x86/kvm/hyperv.h | 117 ++++++-
+ arch/x86/kvm/irq.c | 4 +-
+ arch/x86/kvm/lapic.c | 18 +-
+ arch/x86/kvm/lapic.h | 33 ++
+ arch/x86/kvm/mmu.h | 11 +-
+ arch/x86/kvm/mmu/mmu.c | 2 +-
+ arch/x86/kvm/mmu/paging_tmpl.h | 2 +-
+ arch/x86/kvm/msrs.h | 4 +-
+ arch/x86/kvm/regs.h | 38 +++
+ arch/x86/kvm/svm/avic.c | 96 ++++--
+ arch/x86/kvm/svm/nested.c | 3 +-
+ arch/x86/kvm/svm/sev.c | 17 +-
+ arch/x86/kvm/svm/svm.c | 20 +-
+ arch/x86/kvm/svm/svm.h | 4 +-
+ arch/x86/kvm/tss.h | 7 +
+ arch/x86/kvm/vmx/main.c | 3 +-
+ arch/x86/kvm/vmx/nested.c | 151 ++++-----
+ arch/x86/kvm/vmx/nested.h | 6 +-
+ arch/x86/kvm/vmx/tdx.c | 7 +-
+ arch/x86/kvm/vmx/vmx.c | 20 +-
+ arch/x86/kvm/vmx/vmx.h | 7 +
+ arch/x86/kvm/x86.c | 75 +++--
+ arch/x86/kvm/x86.h | 8 +-
+ arch/x86/kvm/xen.c | 43 ++-
+ include/linux/kvm_host.h | 7 +
+ tools/testing/selftests/kvm/Makefile.kvm | 7 +-
+ tools/testing/selftests/kvm/arch_timer.c | 2 +-
+ .../selftests/kvm/arm64/arch_timer_edge_cases.c | 2 +-
+ tools/testing/selftests/kvm/demand_paging_test.c | 2 +-
+ tools/testing/selftests/kvm/dirty_log_perf_test.c | 4 +-
+ tools/testing/selftests/kvm/dirty_log_test.c | 11 +-
+ tools/testing/selftests/kvm/include/kvm_syscalls.h | 7 +
+ tools/testing/selftests/kvm/include/kvm_util.h | 12 +
+ tools/testing/selftests/kvm/include/proc_util.h | 11 +
+ tools/testing/selftests/kvm/include/test_util.h | 25 +-
+ .../selftests/kvm/include/x86/kvm_util_arch.h | 4 +-
+ tools/testing/selftests/kvm/irq_test.c | 362 +++++++++++++++++++++
+ tools/testing/selftests/kvm/lib/assert.c | 8 +-
+ tools/testing/selftests/kvm/lib/kvm_util.c | 54 ++-
+ tools/testing/selftests/kvm/lib/memstress.c | 8 +-
+ tools/testing/selftests/kvm/lib/proc_util.c | 54 +++
+ tools/testing/selftests/kvm/lib/test_util.c | 27 +-
+ tools/testing/selftests/kvm/mmu_stress_test.c | 15 +-
+ tools/testing/selftests/kvm/rseq_test.c | 6 +-
+ tools/testing/selftests/kvm/steal_time.c | 22 +-
+ tools/testing/selftests/kvm/x86/sev_dbg_test.c | 2 +-
+ .../testing/selftests/kvm/x86/sev_migrate_tests.c | 47 +++
+ tools/testing/selftests/kvm/x86/xapic_ipi_test.c | 2 +-
+ virt/kvm/kvm_main.c | 9 +
+ 54 files changed, 1237 insertions(+), 542 deletions(-)
+ create mode 100644 arch/x86/include/asm/kvm-x86-nested-ops.h
+ create mode 100644 tools/testing/selftests/kvm/include/proc_util.h
+ create mode 100644 tools/testing/selftests/kvm/irq_test.c
+ create mode 100644 tools/testing/selftests/kvm/lib/proc_util.c
+$ git am -3 ../patches/0001-KVM-selftests-Fix-up-semantic-changes.patch
+Applying: KVM: selftests: Fix up semantic changes
+Using index info to reconstruct a base tree...
+M tools/testing/selftests/kvm/lib/kvm_util.c
+Falling back to patching base and 3-way merge...
+Auto-merging tools/testing/selftests/kvm/lib/kvm_util.c
+No changes -- Patch already applied.
+Merging xen-tip/linux-next (fcd245ea7528d x86/Xen: correct commentary and parameter naming of xen_exchange_memory())
+$ git merge -m Merge branch 'linux-next' of https://git.kernel.org/pub/scm/linux/kernel/git/xen/tip.git xen-tip/linux-next
+Already up to date.
+Merging percpu/for-next (8f0b4cce4481f Linux 6.19-rc1)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/dennis/percpu.git percpu/for-next
+Already up to date.
+Merging workqueues/for-next (dbff1ec23f686 docs: workqueue: Fix bracket)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/tj/wq.git workqueues/for-next
+Auto-merging kernel/workqueue.c
+Merge made by the 'ort' strategy.
+ Documentation/core-api/workqueue.rst | 2 +-
+ kernel/workqueue.c | 140 +++++++++++++++++++++++++++++++----
+ tools/workqueue/wq_dump.py | 10 +--
+ tools/workqueue/wq_monitor.py | 6 +-
+ 4 files changed, 133 insertions(+), 25 deletions(-)
+Merging sched-ext/for-next (a742176b89344 Merge branch 'for-7.3' into for-next)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/tj/sched_ext.git sched-ext/for-next
+Auto-merging kernel/sched/sched.h
+Merge made by the 'ort' strategy.
+ Documentation/scheduler/sched-ext.rst | 8 +-
+ include/linux/sched/ext.h | 4 +-
+ kernel/rcu/tree.c | 3 +
+ kernel/rcu/tree_exp.h | 5 +-
+ kernel/rcu/tree_stall.h | 13 +-
+ kernel/sched/build_policy.c | 2 +
+ kernel/sched/ext/arena.c | 13 +-
+ kernel/sched/ext/cid.c | 55 +-
+ kernel/sched/ext/cid.h | 2 -
+ kernel/sched/ext/ext.c | 1560 +++++----------------
+ kernel/sched/ext/internal.h | 232 ++-
+ kernel/sched/ext/sub.c | 674 +++++++++
+ kernel/sched/ext/sub.h | 161 +++
+ kernel/sched/sched.h | 3 +-
+ tools/sched_ext/include/scx/cid.bpf.h | 88 +-
+ tools/sched_ext/include/scx/common.bpf.h | 7 +-
+ tools/sched_ext/include/scx/compat.bpf.h | 17 -
+ tools/sched_ext/include/scx/compat.h | 10 +-
+ tools/sched_ext/scx_cpu0.c | 2 +-
+ tools/sched_ext/scx_flatcg.bpf.c | 5 +-
+ tools/sched_ext/scx_qmap.c | 21 +-
+ tools/sched_ext/scx_qmap.h | 34 +-
+ tools/sched_ext/scx_sdt.c | 2 +-
+ tools/sched_ext/scx_simple.c | 2 +-
+ tools/sched_ext/scx_userland.c | 2 +-
+ tools/testing/selftests/sched_ext/Makefile | 1 +
+ tools/testing/selftests/sched_ext/nohz_tick.bpf.c | 65 +
+ tools/testing/selftests/sched_ext/nohz_tick.c | 347 +++++
+ tools/testing/selftests/sched_ext/prog_run.c | 36 +-
+ 29 files changed, 1985 insertions(+), 1389 deletions(-)
+ create mode 100644 kernel/sched/ext/sub.c
+ create mode 100644 kernel/sched/ext/sub.h
+ create mode 100644 tools/testing/selftests/sched_ext/nohz_tick.bpf.c
+ create mode 100644 tools/testing/selftests/sched_ext/nohz_tick.c
+Merging drivers-x86/for-next (62b57396c26a1 platform/x86: ishtp_eclite: Fix ACPI device reference leak in probe error path)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86.git drivers-x86/for-next
+Auto-merging drivers/platform/x86/asus-armoury.h
+Merge made by the 'ort' strategy.
+ .../ABI/testing/sysfs-driver-uniwill-laptop | 25 +
+ .../admin-guide/laptops/thinkpad-acpi.rst | 24 +
+ .../admin-guide/laptops/uniwill-laptop.rst | 27 +
+ arch/x86/platform/olpc/olpc-xo15-sci.c | 5 -
+ drivers/char/sonypi.c | 2 -
+ drivers/platform/surface/surface_aggregator_hub.c | 9 +-
+ .../platform/surface/surface_aggregator_tabletsw.c | 9 +-
+ drivers/platform/surface/surfacepro3_button.c | 8 +-
+ drivers/platform/x86/Kconfig | 1 -
+ drivers/platform/x86/amd/hsmp/acpi.c | 53 +-
+ drivers/platform/x86/amd/hsmp/hsmp.c | 13 +
+ drivers/platform/x86/asus-armoury.c | 66 ++-
+ drivers/platform/x86/asus-armoury.h | 124 ++++
+ drivers/platform/x86/asus-laptop.c | 9 +-
+ drivers/platform/x86/asus-wmi.c | 24 +
+ drivers/platform/x86/dell/dell-wmi-base.c | 19 +-
+ drivers/platform/x86/dell/dell-wmi-ddv.c | 22 +-
+ drivers/platform/x86/dell/dell-wmi-privacy.c | 4 +-
+ .../x86/dell/dell-wmi-sysman/biosattr-interface.c | 1 -
+ drivers/platform/x86/eeepc-laptop.c | 7 +-
+ drivers/platform/x86/fujitsu-laptop.c | 18 +-
+ drivers/platform/x86/fujitsu-tablet.c | 13 +-
+ drivers/platform/x86/hp/hp-wmi.c | 270 ++++++---
+ drivers/platform/x86/huawei-wmi.c | 99 ++++
+ drivers/platform/x86/intel/ishtp_eclite.c | 5 +-
+ drivers/platform/x86/lenovo/thinkpad_acpi.c | 127 +++-
+ drivers/platform/x86/lenovo/ymc.c | 8 +-
+ drivers/platform/x86/lg-laptop.c | 652 +++++++++++++--------
+ drivers/platform/x86/msi-ec.c | 81 +++
+ drivers/platform/x86/msi-wmi.c | 97 ++-
+ drivers/platform/x86/panasonic-laptop.c | 4 -
+ drivers/platform/x86/sony-laptop.c | 5 +-
+ drivers/platform/x86/topstar-laptop.c | 2 -
+ drivers/platform/x86/toshiba_acpi.c | 6 +-
+ drivers/platform/x86/toshiba_bluetooth.c | 6 +-
+ drivers/platform/x86/toshiba_haps.c | 4 +-
+ drivers/platform/x86/uniwill/uniwill-acpi.c | 609 ++++++++++++++++++-
+ drivers/platform/x86/uniwill/uniwill-wmi.h | 2 +
+ drivers/platform/x86/xo15-ebook.c | 8 +-
+ drivers/power/supply/surface_battery.c | 11 +-
+ drivers/power/supply/surface_charger.c | 7 +-
+ include/linux/platform_data/x86/asus-wmi.h | 5 +
+ 42 files changed, 1976 insertions(+), 515 deletions(-)
+$ git am -3 ../patches/0001-hid-Fix-up-mismerge.patch
+Applying: hid: Fix up mismerge
+$ git reset HEAD^
+Unstaged changes after reset:
+M arch/x86/kvm/msrs.c
+M drivers/hid/hid-asus.c
+$ git add -A .
+$ git commit -v -a --amend
+warning: notes ref refs/notes/commits is invalid
+[master 78641de8a8faf] Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86.git
+ Date: Fri Jul 10 13:28:25 2026 +0100
+Merging chrome-platform/for-next (d1ceb2b232471 platform/chrome: sensorhub: Fix memory overread in ring handler)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux.git chrome-platform/for-next
+Auto-merging drivers/platform/chrome/cros_ec_chardev.c
+Auto-merging drivers/platform/chrome/cros_ec_debugfs.c
+Auto-merging drivers/platform/chrome/cros_ec_lightbar.c
+Auto-merging drivers/platform/chrome/cros_ec_sensorhub.c
+Auto-merging drivers/platform/chrome/cros_ec_sysfs.c
+Auto-merging drivers/platform/chrome/cros_ec_vbc.c
+Auto-merging drivers/platform/chrome/cros_kbd_led_backlight.c
+Auto-merging drivers/platform/chrome/cros_usbpd_logger.c
+Auto-merging drivers/platform/chrome/cros_usbpd_notify.c
+Auto-merging drivers/platform/chrome/wilco_ec/core.c
+Auto-merging drivers/platform/chrome/wilco_ec/debugfs.c
+Auto-merging drivers/platform/chrome/wilco_ec/telemetry.c
+Merge made by the 'ort' strategy.
+ drivers/platform/chrome/chromeos_of_hw_prober.c | 2 +-
+ drivers/platform/chrome/cros_ec_chardev.c | 4 ++--
+ drivers/platform/chrome/cros_ec_debugfs.c | 4 ++--
+ drivers/platform/chrome/cros_ec_lightbar.c | 4 ++--
+ drivers/platform/chrome/cros_ec_sensorhub.c | 4 ++--
+ drivers/platform/chrome/cros_ec_sensorhub_ring.c | 17 ++++++++++++++++-
+ drivers/platform/chrome/cros_ec_sysfs.c | 4 ++--
+ drivers/platform/chrome/cros_ec_typec.c | 6 ++++++
+ drivers/platform/chrome/cros_ec_vbc.c | 4 ++--
+ drivers/platform/chrome/cros_kbd_led_backlight.c | 4 ++--
+ drivers/platform/chrome/cros_usbpd_logger.c | 4 ++--
+ drivers/platform/chrome/cros_usbpd_notify.c | 4 ++--
+ drivers/platform/chrome/wilco_ec/core.c | 4 ++--
+ drivers/platform/chrome/wilco_ec/debugfs.c | 4 ++--
+ drivers/platform/chrome/wilco_ec/telemetry.c | 4 ++--
+ 15 files changed, 47 insertions(+), 26 deletions(-)
+Merging chrome-platform-firmware/for-firmware-next (dd06eb60e86a1 docs: ABI: testing: Fix typo)
+$ git merge -m Merge branch 'for-firmware-next' of https://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux.git chrome-platform-firmware/for-firmware-next
+Merge made by the 'ort' strategy.
+ Documentation/ABI/testing/sysfs-firmware-gsmi | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+Merging hsi/for-next (254f49634ee16 Linux 7.1-rc1)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-hsi.git hsi/for-next
+Already up to date.
+Merging leds-lj/for-leds-next (96fa4d69958cf leds: st1202: Correct and extend hw_pattern documentation)
+$ git merge -m Merge branch 'for-leds-next' of https://git.kernel.org/pub/scm/linux/kernel/git/lee/leds.git leds-lj/for-leds-next
+Auto-merging drivers/leds/rgb/leds-pwm-multicolor.c
+Merge made by the 'ort' strategy.
+ Documentation/leds/leds-st1202.rst | 9 ++-
+ drivers/leds/leds-pca9532.c | 6 +-
+ drivers/leds/leds-st1202.c | 102 ++++++++++++++++++++-------------
+ drivers/leds/rgb/leds-lp5860-core.c | 3 +-
+ drivers/leds/rgb/leds-lp5860-spi.c | 10 ++--
+ drivers/leds/rgb/leds-pwm-multicolor.c | 2 +
+ drivers/leds/trigger/ledtrig-netdev.c | 46 ++++++++++++++-
+ include/linux/leds.h | 4 ++
+ 8 files changed, 127 insertions(+), 55 deletions(-)
+Merging ipmi/for-next (6d920a75df9a8 ipmi: si: Fix NULL pointer dereference after failed registration)
+$ git merge -m Merge branch 'for-next' of https://github.com/cminyard/linux-ipmi.git ipmi/for-next
+Merge made by the 'ort' strategy.
+ drivers/char/ipmi/ipmb_dev_int.c | 5 +++--
+ drivers/char/ipmi/ipmi_msghandler.c | 1 +
+ 2 files changed, 4 insertions(+), 2 deletions(-)
+Merging driver-core/driver-core-next (5dcef303b29f0 rust: io: fix example in `register!` macro)
+$ git merge -m Merge branch 'driver-core-next' of https://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core.git driver-core/driver-core-next
+Merge made by the 'ort' strategy.
+ drivers/base/isa.c | 16 +++++++++-------
+ drivers/base/module.c | 2 +-
+ fs/debugfs/file.c | 3 ++-
+ rust/kernel/io/register.rs | 2 +-
+ 4 files changed, 13 insertions(+), 10 deletions(-)
+Merging usb/usb-next (0f1dabb7af982 usb: dwc3: am62: Propagate USB2 refclk enable failures)
+$ git merge -m Merge branch 'usb-next' of https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb/usb-next
+Auto-merging Documentation/devicetree/bindings/usb/qcom,snps-dwc3.yaml
+Auto-merging drivers/usb/dwc3/core.c
+Auto-merging drivers/usb/dwc3/gadget.c
+Auto-merging drivers/usb/typec/class.c
+Auto-merging drivers/usb/typec/mux/tusb1046.c
+Auto-merging drivers/usb/typec/tcpm/tcpm.c
+Auto-merging drivers/usb/typec/ucsi/ucsi.c
+Auto-merging drivers/usb/typec/ucsi/ucsi.h
+Merge made by the 'ort' strategy.
+ Documentation/ABI/testing/sysfs-bus-usb | 2 +-
+ .../devicetree/bindings/usb/qcom,snps-dwc3.yaml | 3 +
+ .../devicetree/bindings/usb/renesas,usbhs.yaml | 1 +
+ drivers/usb/cdns3/cdns3-plat.c | 4 +-
+ drivers/usb/core/devices.c | 7 +-
+ drivers/usb/dwc3/core.c | 99 +++++++++++++++++++---
+ drivers/usb/dwc3/core.h | 7 +-
+ drivers/usb/dwc3/dwc3-am62.c | 13 ++-
+ drivers/usb/dwc3/dwc3-qcom.c | 2 +-
+ drivers/usb/dwc3/dwc3-xilinx.c | 18 ++--
+ drivers/usb/dwc3/gadget.c | 15 +++-
+ drivers/usb/gadget/udc/r8a66597-udc.c | 1 -
+ drivers/usb/host/ohci-dbg.c | 9 +-
+ drivers/usb/typec/altmodes/displayport.c | 18 +++-
+ drivers/usb/typec/altmodes/thunderbolt.c | 4 +
+ drivers/usb/typec/class.c | 71 ++++++++++++++++
+ drivers/usb/typec/mux/tusb1046.c | 1 +
+ drivers/usb/typec/tcpm/tcpm.c | 11 +--
+ drivers/usb/typec/tipd/core.c | 9 +-
+ drivers/usb/typec/tipd/tps6598x.h | 10 ++-
+ drivers/usb/typec/ucsi/debugfs.c | 5 +-
+ drivers/usb/typec/ucsi/ucsi.c | 6 +-
+ drivers/usb/typec/ucsi/ucsi.h | 1 +
+ include/linux/usb/typec.h | 1 +
+ rust/kernel/usb.rs | 31 +++----
+ 25 files changed, 265 insertions(+), 84 deletions(-)
+Merging thunderbolt/next (d49d71ebec8f0 thunderbolt: xdomain: Notify peers after enumeration)
+$ git merge -m Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/westeri/thunderbolt.git thunderbolt/next
+Auto-merging drivers/net/thunderbolt/main.c
+Auto-merging drivers/thunderbolt/stream.c
+Auto-merging drivers/thunderbolt/tb.c
+Auto-merging include/linux/thunderbolt.h
+Merge made by the 'ort' strategy.
+ drivers/net/thunderbolt/main.c | 4 ++--
+ drivers/thunderbolt/dma_test.c | 4 ++--
+ drivers/thunderbolt/domain.c | 4 +---
+ drivers/thunderbolt/nhi.c | 2 ++
+ drivers/thunderbolt/pci.c | 28 +++++++++++++++++++++++-----
+ drivers/thunderbolt/stream.c | 4 ++--
+ drivers/thunderbolt/switch.c | 11 ++++++++++-
+ drivers/thunderbolt/tb.c | 21 +++++++++++++++++++++
+ drivers/thunderbolt/tb.h | 1 +
+ drivers/thunderbolt/xdomain.c | 4 ++++
+ include/linux/thunderbolt.h | 8 +++++++-
+ 11 files changed, 75 insertions(+), 16 deletions(-)
+Merging usb-serial/usb-next (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'usb-next' of https://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial.git usb-serial/usb-next
+Already up to date.
+Merging tty/tty-next (9505146e885b1 tty: tty_jobctrl: use guard() in tiocgsid())
+$ git merge -m Merge branch 'tty-next' of https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tty/tty-next
+Auto-merging drivers/tty/goldfish.c
+Auto-merging drivers/tty/serial/max310x.c
+Merge made by the 'ort' strategy.
+ .../devicetree/bindings/serial/maxim,max310x.yaml | 92 +++++++++++++++++++++-
+ drivers/tty/amiserial.c | 14 ++--
+ drivers/tty/goldfish.c | 23 +++---
+ drivers/tty/serial/8250/8250_exar.c | 30 +++----
+ drivers/tty/serial/max310x.c | 91 ++++++++++++++++-----
+ drivers/tty/serial/men_z135_uart.c | 7 +-
+ drivers/tty/serial/pch_uart.c | 6 +-
+ drivers/tty/serial/rp2.c | 2 +-
+ drivers/tty/tty_jobctrl.c | 41 ++++------
+ drivers/tty/vt/vc_screen.c | 6 +-
+ include/linux/goldfish.h | 24 ------
+ 11 files changed, 221 insertions(+), 115 deletions(-)
+Merging char-misc/char-misc-next (9e32d2a978473 rust: binder: enable `clippy::cast_lossless`)
+$ git merge -m Merge branch 'char-misc-next' of https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git char-misc/char-misc-next
+Auto-merging drivers/android/binder/allocation.rs
+Auto-merging drivers/android/binder/freeze.rs
+Auto-merging drivers/android/binder/node.rs
+Auto-merging drivers/android/binder/process.rs
+Auto-merging drivers/android/binder/thread.rs
+Auto-merging drivers/android/binder/transaction.rs
+Merge made by the 'ort' strategy.
+ drivers/android/binder/allocation.rs | 4 ++--
+ drivers/android/binder/defs.rs | 8 +++++---
+ drivers/android/binder/freeze.rs | 2 +-
+ drivers/android/binder/node.rs | 14 ++++++++------
+ drivers/android/binder/node/wrapper.rs | 2 +-
+ drivers/android/binder/page_range.rs | 8 ++++----
+ drivers/android/binder/process.rs | 14 +++++++-------
+ drivers/android/binder/rust_binder_main.rs | 10 ++--------
+ drivers/android/binder/thread.rs | 24 +++++++++++++-----------
+ drivers/android/binder/trace.rs | 4 +++-
+ drivers/android/binder/transaction.rs | 14 ++++++++------
+ 11 files changed, 54 insertions(+), 50 deletions(-)
+$ git am -3 ../patches/0001-bus-mhi-Fix-up-interaction-with-net-next-tree.patch
+Applying: bus: mhi: Fix up interaction with net-next tree
+Using index info to reconstruct a base tree...
+M drivers/net/wireless/ath/ath12k/wifi7/mhi.c
+Falling back to patching base and 3-way merge...
+No changes -- Patch already applied.
+Merging coresight/next (98495b5a4d77d coresight: ultrasoc-smb: Fix OOB write in smb_sync_perf_buffer())
+$ git merge -m Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/coresight/linux.git coresight/next
+Already up to date.
+Merging fastrpc/for-next (17ec912dc87bf Merge branches 'fastrpc-fixes' and 'fastrpc-for-7.3' into fastrpc-for-next)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/srini/fastrpc.git fastrpc/for-next
+Auto-merging MAINTAINERS
+Merge made by the 'ort' strategy.
+ MAINTAINERS | 2 +-
+ drivers/misc/fastrpc.c | 46 ++++++++++++++++++++++++++++------------------
+ 2 files changed, 29 insertions(+), 19 deletions(-)
+Merging fpga/for-next (b5ba63e247075 fpga: dfl: fme: add error handling)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/fpga/linux-fpga.git fpga/for-next
+Merge made by the 'ort' strategy.
+ drivers/fpga/dfl-fme-perf.c | 2 ++
+ drivers/fpga/stratix10-soc.c | 21 ++++++++++++---------
+ drivers/fpga/xilinx-pr-decoupler.c | 20 ++------------------
+ 3 files changed, 16 insertions(+), 27 deletions(-)
+Merging icc/icc-next (e11872288b4b3 Merge branch 'icc-maili' into icc-next)
+$ git merge -m Merge branch 'icc-next' of https://git.kernel.org/pub/scm/linux/kernel/git/djakov/icc.git icc/icc-next
+Auto-merging drivers/interconnect/qcom/sc8280xp.c
+Merge made by the 'ort' strategy.
+ .../bindings/interconnect/qcom,maili-rpmh.yaml | 127 ++
+ .../bindings/interconnect/qcom,osm-l3.yaml | 2 +
+ .../bindings/interconnect/qcom,sc8280xp-rpmh.yaml | 101 +-
+ .../bindings/interconnect/qcom,x1e80100-rpmh.yaml | 72 +
+ drivers/interconnect/qcom/Kconfig | 11 +
+ drivers/interconnect/qcom/Makefile | 2 +
+ drivers/interconnect/qcom/maili.c | 2091 ++++++++++++++++++++
+ drivers/interconnect/qcom/osm-l3.c | 16 +-
+ drivers/interconnect/qcom/sc8280xp.c | 356 ++++
+ drivers/interconnect/qcom/x1e80100.c | 485 +++++
+ include/dt-bindings/interconnect/qcom,maili-rpmh.h | 171 ++
+ 11 files changed, 3431 insertions(+), 3 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/interconnect/qcom,maili-rpmh.yaml
+ create mode 100644 drivers/interconnect/qcom/maili.c
+ create mode 100644 include/dt-bindings/interconnect/qcom,maili-rpmh.h
+Merging iio/togreg (2e2f2de7532cb iio: hid-sensors: Use implicit NULL pointer checks)
+$ git merge -m Merge branch 'togreg' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git iio/togreg
+Auto-merging .mailmap
+Auto-merging Documentation/devicetree/bindings/vendor-prefixes.yaml
+Auto-merging MAINTAINERS
+Auto-merging drivers/iio/accel/bmc150-accel-core.c
+Auto-merging drivers/iio/adc/Kconfig
+Auto-merging drivers/iio/adc/ti-ads124s08.c
+Auto-merging drivers/iio/imu/bmi160/bmi160_core.c
+Auto-merging drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
+Auto-merging drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c
+Auto-merging drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h
+Auto-merging drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
+Auto-merging drivers/iio/light/gp2ap002.c
+Auto-merging drivers/iio/orientation/hid-sensor-rotation.c
+Auto-merging lib/vsprintf.c
+Auto-merging sound/soc/samsung/aries_wm8994.c
+Merge made by the 'ort' strategy.
+ .mailmap | 1 +
+ Documentation/ABI/testing/sysfs-bus-iio | 11 +-
+ Documentation/ABI/testing/sysfs-bus-iio-adc-ad7192 | 2 +-
+ Documentation/ABI/testing/sysfs-bus-iio-frequency | 11 +
+ .../ABI/testing/sysfs-bus-iio-frequency-adf4350 | 10 -
+ .../devicetree/bindings/iio/adc/avia-hx711.yaml | 21 +
+ .../bindings/iio/adc/mediatek,mt6359-auxadc.yaml | 3 +-
+ .../bindings/iio/adc/xlnx,versal-sysmon.yaml | 154 +++
+ .../bindings/iio/chemical/sensirion,scd30.yaml | 1 +
+ .../devicetree/bindings/iio/dac/adi,ad3530r.yaml | 16 +-
+ .../devicetree/bindings/iio/dac/adi,ad5686.yaml | 72 +-
+ .../devicetree/bindings/iio/dac/adi,ad5696.yaml | 73 +-
+ .../bindings/iio/frequency/adi,adf41513.yaml | 227 ++++
+ .../iio/magnetometer/qstcorp,qmc5883l.yaml | 52 +
+ .../bindings/iio/temperature/ti,tmp117.yaml | 16 +-
+ .../devicetree/bindings/vendor-prefixes.yaml | 2 +
+ Documentation/iio/adf41513.rst | 199 ++++
+ Documentation/iio/index.rst | 1 +
+ MAINTAINERS | 34 +-
+ drivers/extcon/extcon-adc-jack.c | 1 +
+ drivers/hwmon/iio_hwmon.c | 1 +
+ drivers/hwmon/ntc_thermistor.c | 1 +
+ drivers/iio/TODO | 13 +-
+ drivers/iio/accel/adxl345_spi.c | 4 +-
+ drivers/iio/accel/adxl355_spi.c | 4 +-
+ drivers/iio/accel/adxl367_spi.c | 2 +-
+ drivers/iio/accel/adxl372_spi.c | 4 +-
+ drivers/iio/accel/adxl380_spi.c | 8 +-
+ drivers/iio/accel/bma220_spi.c | 2 +-
+ drivers/iio/accel/bma400_spi.c | 2 +-
+ drivers/iio/accel/bmc150-accel-core.c | 6 +-
+ drivers/iio/accel/bmc150-accel-spi.c | 18 +-
+ drivers/iio/accel/bmi088-accel-spi.c | 6 +-
+ drivers/iio/accel/fxls8962af-core.c | 2 +
+ drivers/iio/accel/fxls8962af-spi.c | 4 +-
+ drivers/iio/accel/hid-sensor-accel-3d.c | 68 +-
+ drivers/iio/accel/kxsd9-spi.c | 2 +-
+ drivers/iio/accel/mma7455_spi.c | 4 +-
+ drivers/iio/accel/sca3000.c | 8 +-
+ drivers/iio/accel/sca3300.c | 4 +-
+ drivers/iio/accel/st_accel_spi.c | 40 +-
+ drivers/iio/accel/stk8312.c | 12 +-
+ drivers/iio/accel/stk8ba50.c | 9 +-
+ drivers/iio/adc/Kconfig | 47 +-
+ drivers/iio/adc/Makefile | 4 +
+ drivers/iio/adc/ad4000.c | 62 +-
+ drivers/iio/adc/ad4030.c | 14 +-
+ drivers/iio/adc/ad4080.c | 22 +-
+ drivers/iio/adc/ad4130.c | 12 +-
+ drivers/iio/adc/ad4134.c | 2 +-
+ drivers/iio/adc/ad4170-4.c | 6 +-
+ drivers/iio/adc/ad4851.c | 18 +-
+ drivers/iio/adc/ad7091r8.c | 6 +-
+ drivers/iio/adc/ad7124.c | 4 +-
+ drivers/iio/adc/ad7173.c | 26 +-
+ drivers/iio/adc/ad7191.c | 2 +-
+ drivers/iio/adc/ad7192.c | 10 +-
+ drivers/iio/adc/ad7266.c | 4 +-
+ drivers/iio/adc/ad7280a.c | 2 +-
+ drivers/iio/adc/ad7292.c | 2 +-
+ drivers/iio/adc/ad7298.c | 2 +-
+ drivers/iio/adc/ad7380.c | 36 +-
+ drivers/iio/adc/ad7476.c | 60 +-
+ drivers/iio/adc/ad7606_spi.c | 22 +-
+ drivers/iio/adc/ad7766.c | 12 +-
+ drivers/iio/adc/ad7768-1.c | 8 +-
+ drivers/iio/adc/ad7779.c | 6 +-
+ drivers/iio/adc/ad7780.c | 8 +-
+ drivers/iio/adc/ad7791.c | 10 +-
+ drivers/iio/adc/ad7793.c | 18 +-
+ drivers/iio/adc/ad7887.c | 2 +-
+ drivers/iio/adc/ad7923.c | 14 +-
+ drivers/iio/adc/ad7944.c | 6 +-
+ drivers/iio/adc/ad7949.c | 6 +-
+ drivers/iio/adc/ad9467.c | 14 +-
+ drivers/iio/adc/ade9000.c | 4 +-
+ drivers/iio/adc/envelope-detector.c | 1 +
+ drivers/iio/adc/hi8435.c | 2 +-
+ drivers/iio/adc/hx711.c | 98 +-
+ drivers/iio/adc/max1027.c | 12 +-
+ drivers/iio/adc/max1118.c | 6 +-
+ drivers/iio/adc/max11205.c | 4 +-
+ drivers/iio/adc/max11410.c | 2 +-
+ drivers/iio/adc/max1241.c | 9 +-
+ drivers/iio/adc/max14001.c | 4 +-
+ drivers/iio/adc/mcp320x.c | 26 +-
+ drivers/iio/adc/mcp3564.c | 24 +-
+ drivers/iio/adc/mcp3911.c | 14 +-
+ drivers/iio/adc/mt6323-auxadc.c | 314 +++++
+ drivers/iio/adc/rohm-bd79112.c | 2 +-
+ drivers/iio/adc/rtq6056.c | 4 +-
+ drivers/iio/adc/stm32-dfsdm-adc.c | 12 +-
+ drivers/iio/adc/ti-adc081c.c | 6 +-
+ drivers/iio/adc/ti-adc0832.c | 8 +-
+ drivers/iio/adc/ti-adc084s021.c | 8 +-
+ drivers/iio/adc/ti-adc108s102.c | 2 +-
+ drivers/iio/adc/ti-adc12138.c | 6 +-
+ drivers/iio/adc/ti-adc128s052.c | 24 +-
+ drivers/iio/adc/ti-adc161s626.c | 4 +-
+ drivers/iio/adc/ti-ads1015.c | 46 +-
+ drivers/iio/adc/ti-ads1018.c | 4 +-
+ drivers/iio/adc/ti-ads124s08.c | 4 +-
+ drivers/iio/adc/ti-ads1298.c | 2 +-
+ drivers/iio/adc/ti-ads131e08.c | 6 +-
+ drivers/iio/adc/ti-ads131m02.c | 10 +-
+ drivers/iio/adc/ti-ads7950.c | 24 +-
+ drivers/iio/adc/ti-ads8688.c | 4 +-
+ drivers/iio/adc/ti-lmp92064.c | 2 +-
+ drivers/iio/adc/ti-tlc4541.c | 4 +-
+ drivers/iio/adc/ti-tsc2046.c | 25 +-
+ drivers/iio/adc/versal-sysmon-core.c | 1052 +++++++++++++++++
+ drivers/iio/adc/versal-sysmon-i2c.c | 134 +++
+ drivers/iio/adc/versal-sysmon.c | 92 ++
+ drivers/iio/adc/versal-sysmon.h | 120 ++
+ drivers/iio/addac/ad74115.c | 2 +-
+ drivers/iio/afe/iio-rescale.c | 1 +
+ drivers/iio/amplifiers/ad8366.c | 26 +-
+ drivers/iio/amplifiers/ada4250.c | 2 +-
+ drivers/iio/buffer/industrialio-buffer-cb.c | 1 +
+ drivers/iio/buffer/industrialio-hw-consumer.c | 1 +
+ drivers/iio/chemical/bme680_spi.c | 2 +-
+ drivers/iio/chemical/ens160_spi.c | 2 +-
+ drivers/iio/chemical/scd30_core.c | 10 +-
+ drivers/iio/chemical/scd30_i2c.c | 4 +-
+ drivers/iio/chemical/scd30_serial.c | 4 +-
+ drivers/iio/chemical/sps30_i2c.c | 4 +-
+ drivers/iio/chemical/sps30_serial.c | 4 +-
+ .../iio/common/hid-sensors/hid-sensor-attributes.c | 81 +-
+ .../iio/common/hid-sensors/hid-sensor-trigger.c | 7 +-
+ .../iio/common/hid-sensors/hid-sensor-trigger.h | 2 +-
+ drivers/iio/dac/Kconfig | 18 +-
+ drivers/iio/dac/Makefile | 1 +
+ drivers/iio/dac/ad3530r.c | 359 +++++-
+ drivers/iio/dac/ad5064.c | 32 +-
+ drivers/iio/dac/ad5360.c | 16 +-
+ drivers/iio/dac/ad5380.c | 32 +-
+ drivers/iio/dac/ad5446-spi.c | 62 +-
+ drivers/iio/dac/ad5449.c | 14 +-
+ drivers/iio/dac/ad5504.c | 4 +-
+ drivers/iio/dac/ad5624r_spi.c | 12 +-
+ drivers/iio/dac/ad5686.c | 40 +-
+ drivers/iio/dac/ad5686.h | 4 +
+ drivers/iio/dac/ad5706r.c | 2 +-
+ drivers/iio/dac/ad5755.c | 10 +-
+ drivers/iio/dac/ad5758.c | 2 +-
+ drivers/iio/dac/ad5761.c | 8 +-
+ drivers/iio/dac/ad5764.c | 8 +-
+ drivers/iio/dac/ad5766.c | 4 +-
+ drivers/iio/dac/ad5770r.c | 2 +-
+ drivers/iio/dac/ad5791.c | 10 +-
+ drivers/iio/dac/ad7293.c | 2 +-
+ drivers/iio/dac/ad7303.c | 2 +-
+ drivers/iio/dac/ad8460.c | 1 +
+ drivers/iio/dac/ad8801.c | 4 +-
+ drivers/iio/dac/ad9739a.c | 2 +-
+ drivers/iio/dac/dpot-dac.c | 1 +
+ drivers/iio/dac/ltc1660.c | 4 +-
+ drivers/iio/dac/ltc2632.c | 44 +-
+ drivers/iio/dac/ltc2664.c | 4 +-
+ drivers/iio/dac/ltc2688.c | 2 +-
+ drivers/iio/dac/max22007.c | 2 +-
+ drivers/iio/dac/max5522.c | 31 +-
+ drivers/iio/dac/mcf54415_dac.c | 180 +++
+ drivers/iio/dac/mcp4821.c | 12 +-
+ drivers/iio/dac/mcp4922.c | 8 +-
+ drivers/iio/dac/rohm-bd79703.c | 8 +-
+ drivers/iio/dac/ti-dac082s085.c | 12 +-
+ drivers/iio/dac/ti-dac7311.c | 6 +-
+ drivers/iio/dac/ti-dac7612.c | 2 +-
+ drivers/iio/filter/admv8818.c | 2 +-
+ drivers/iio/frequency/Kconfig | 10 +
+ drivers/iio/frequency/Makefile | 1 +
+ drivers/iio/frequency/ad9523.c | 3 +-
+ drivers/iio/frequency/adf41513.c | 1246 ++++++++++++++++++++
+ drivers/iio/frequency/adf4350.c | 4 +-
+ drivers/iio/frequency/adf4371.c | 4 +-
+ drivers/iio/frequency/adf4377.c | 85 +-
+ drivers/iio/frequency/admv1013.c | 2 +-
+ drivers/iio/frequency/admv1014.c | 2 +-
+ drivers/iio/frequency/adrf6780.c | 2 +-
+ drivers/iio/gyro/adis16080.c | 4 +-
+ drivers/iio/gyro/adis16136.c | 8 +-
+ drivers/iio/gyro/adis16260.c | 12 +-
+ drivers/iio/gyro/adxrs450.c | 4 +-
+ drivers/iio/gyro/bmg160_spi.c | 7 +-
+ drivers/iio/gyro/fxas21002c_spi.c | 2 +-
+ drivers/iio/gyro/hid-sensor-gyro-3d.c | 57 +-
+ drivers/iio/gyro/st_gyro_spi.c | 18 +-
+ drivers/iio/health/afe4403.c | 2 +-
+ drivers/iio/humidity/hid-sensor-humidity.c | 35 +-
+ drivers/iio/humidity/hts221_spi.c | 2 +-
+ drivers/iio/iio_core_trigger.h | 2 +-
+ drivers/iio/imu/adis16400.c | 30 +-
+ drivers/iio/imu/adis16460.c | 2 +-
+ drivers/iio/imu/adis16475.c | 54 +-
+ drivers/iio/imu/adis16480.c | 44 +-
+ drivers/iio/imu/adis16550.c | 89 +-
+ drivers/iio/imu/bmi160/bmi160_core.c | 2 +-
+ drivers/iio/imu/bmi160/bmi160_spi.c | 4 +-
+ drivers/iio/imu/bmi270/bmi270_spi.c | 5 +-
+ drivers/iio/imu/bmi323/bmi323_core.c | 2 +-
+ drivers/iio/imu/bmi323/bmi323_spi.c | 2 +-
+ drivers/iio/imu/fxos8700_core.c | 2 +-
+ drivers/iio/imu/fxos8700_spi.c | 2 +-
+ drivers/iio/imu/inv_icm42600/inv_icm42600.h | 10 +-
+ drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c | 18 +-
+ drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c | 45 +-
+ drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h | 3 +-
+ drivers/iio/imu/inv_icm42600/inv_icm42600_core.c | 12 +-
+ drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c | 16 +-
+ drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c | 6 +-
+ drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c | 20 +-
+ drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c | 3 +-
+ drivers/iio/imu/inv_icm45600/inv_icm45600.h | 2 +-
+ drivers/iio/imu/inv_icm45600/inv_icm45600_buffer.c | 7 +-
+ drivers/iio/imu/inv_icm45600/inv_icm45600_core.c | 2 +-
+ drivers/iio/imu/inv_icm45600/inv_icm45600_i2c.c | 2 +-
+ drivers/iio/imu/inv_icm45600/inv_icm45600_spi.c | 16 +-
+ drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c | 4 +-
+ drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c | 34 +-
+ drivers/iio/imu/smi240.c | 2 +-
+ drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c | 48 +-
+ drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c | 4 +-
+ drivers/iio/industrialio-backend.c | 8 +-
+ drivers/iio/industrialio-core.c | 49 +-
+ drivers/iio/inkern.c | 54 +-
+ drivers/iio/light/cm3605.c | 1 +
+ drivers/iio/light/gp2ap002.c | 1 +
+ drivers/iio/light/hid-sensor-als.c | 52 +-
+ drivers/iio/light/hid-sensor-prox.c | 49 +-
+ drivers/iio/light/opt3001.c | 381 +++---
+ drivers/iio/light/st_uvis25_spi.c | 2 +-
+ drivers/iio/light/tcs3472.c | 317 ++++-
+ drivers/iio/magnetometer/Kconfig | 11 +
+ drivers/iio/magnetometer/Makefile | 2 +
+ drivers/iio/magnetometer/bmc150_magn.c | 50 +-
+ drivers/iio/magnetometer/bmc150_magn_spi.c | 6 +-
+ drivers/iio/magnetometer/hid-sensor-magn-3d.c | 73 +-
+ drivers/iio/magnetometer/hmc5843_spi.c | 6 +-
+ drivers/iio/magnetometer/mmc5983.c | 2 +-
+ drivers/iio/magnetometer/qmc5883l.c | 516 ++++++++
+ drivers/iio/magnetometer/st_magn_spi.c | 12 +-
+ drivers/iio/multiplexer/iio-mux.c | 1 +
+ drivers/iio/orientation/hid-sensor-incl-3d.c | 55 +-
+ drivers/iio/orientation/hid-sensor-rotation.c | 48 +-
+ .../iio/position/hid-sensor-custom-intel-hinge.c | 19 +-
+ drivers/iio/potentiometer/max5481.c | 8 +-
+ drivers/iio/potentiometer/max5487.c | 6 +-
+ drivers/iio/potentiometer/mcp41010.c | 12 +-
+ drivers/iio/potentiometer/mcp4131.c | 128 +-
+ drivers/iio/potentiometer/x9250.c | 4 +-
+ drivers/iio/potentiostat/lmp91000.c | 1 +
+ drivers/iio/pressure/abp2030pa_spi.c | 2 +-
+ drivers/iio/pressure/bmp280-core.c | 32 +-
+ drivers/iio/pressure/bmp280-spi.c | 14 +-
+ drivers/iio/pressure/hid-sensor-press.c | 57 +-
+ drivers/iio/pressure/hsc030pa_spi.c | 2 +-
+ drivers/iio/pressure/mpl115_spi.c | 2 +-
+ drivers/iio/pressure/mprls0025pa_spi.c | 2 +-
+ drivers/iio/pressure/ms5611_spi.c | 4 +-
+ drivers/iio/pressure/rohm-bm1390.c | 23 +-
+ drivers/iio/pressure/st_pressure_spi.c | 24 +-
+ drivers/iio/pressure/zpa2326_spi.c | 2 +-
+ drivers/iio/proximity/as3935.c | 2 +-
+ drivers/iio/proximity/vl53l1x-i2c.c | 39 +-
+ drivers/iio/resolver/ad2s1200.c | 4 +-
+ drivers/iio/resolver/ad2s1210.c | 32 +-
+ drivers/iio/resolver/ad2s90.c | 2 +-
+ drivers/iio/temperature/hid-sensor-temperature.c | 34 +-
+ drivers/iio/temperature/ltc2983.c | 10 +-
+ drivers/iio/temperature/max31856.c | 2 +-
+ drivers/iio/temperature/max31865.c | 2 +-
+ drivers/iio/temperature/maxim_thermocouple.c | 18 +-
+ drivers/iio/temperature/tmp117.c | 13 +
+ drivers/iio/test/iio-test-format.c | 97 +-
+ drivers/iio/test/iio-test-rescale.c | 2 +-
+ drivers/input/joystick/adc-joystick.c | 1 +
+ drivers/input/keyboard/adc-keys.c | 1 +
+ drivers/input/touchscreen/colibri-vf50-ts.c | 1 +
+ drivers/input/touchscreen/resistive-adc-touch.c | 1 +
+ drivers/phy/motorola/phy-cpcap-usb.c | 1 +
+ drivers/power/supply/ab8500_btemp.c | 1 +
+ drivers/power/supply/ab8500_charger.c | 1 +
+ drivers/power/supply/ab8500_fg.c | 1 +
+ drivers/power/supply/axp20x_ac_power.c | 1 +
+ drivers/power/supply/axp20x_battery.c | 1 +
+ drivers/power/supply/axp20x_usb_power.c | 1 +
+ drivers/power/supply/axp288_fuel_gauge.c | 1 +
+ drivers/power/supply/cpcap-battery.c | 1 +
+ drivers/power/supply/cpcap-charger.c | 1 +
+ drivers/power/supply/da9150-charger.c | 1 +
+ drivers/power/supply/generic-adc-battery.c | 1 +
+ drivers/power/supply/ingenic-battery.c | 1 +
+ drivers/power/supply/intel_dc_ti_battery.c | 1 +
+ drivers/power/supply/lego_ev3_battery.c | 1 +
+ drivers/power/supply/lp8788-charger.c | 1 +
+ drivers/power/supply/max17040_battery.c | 1 +
+ drivers/power/supply/mp2629_charger.c | 1 +
+ drivers/power/supply/mt6370-charger.c | 1 +
+ drivers/power/supply/qcom_smbx.c | 1 +
+ drivers/power/supply/rn5t618_power.c | 1 +
+ drivers/power/supply/rx51_battery.c | 1 +
+ drivers/power/supply/sc27xx_fuel_gauge.c | 1 +
+ drivers/power/supply/twl4030_charger.c | 1 +
+ drivers/power/supply/twl4030_madc_battery.c | 1 +
+ drivers/power/supply/twl6030_charger.c | 1 +
+ drivers/staging/iio/adc/ad7816.c | 6 +-
+ drivers/staging/iio/addac/adt7316-spi.c | 13 +-
+ drivers/staging/iio/frequency/ad9832.c | 24 +-
+ drivers/staging/iio/frequency/ad9834.c | 30 +-
+ drivers/staging/iio/frequency/dds.h | 24 +-
+ drivers/thermal/qcom/qcom-spmi-adc-tm5.c | 1 +
+ drivers/thermal/qcom/qcom-spmi-temp-alarm.c | 1 +
+ drivers/thermal/renesas/rzg3s_thermal.c | 1 +
+ drivers/thermal/thermal-generic-adc.c | 1 +
+ .../dt-bindings/iio/adc/mediatek,mt6323-auxadc.h | 24 +
+ include/linux/iio/types.h | 20 +
+ include/linux/kstrtox.h | 3 +
+ include/linux/math64.h | 18 +
+ lib/kstrtox.c | 115 +-
+ lib/kstrtox.h | 17 +-
+ lib/math/div64.c | 15 +
+ lib/math/test_mul_u64_u64_div_u64.c | 1 +
+ lib/test-kstrtox.c | 182 +++
+ lib/vsprintf.c | 2 +-
+ sound/soc/codecs/audio-iio-aux.c | 1 +
+ sound/soc/samsung/aries_wm8994.c | 1 +
+ sound/soc/samsung/midas_wm1811.c | 1 +
+ sound/soc/stm/stm32_adfsdm.c | 1 +
+ 329 files changed, 7677 insertions(+), 1999 deletions(-)
+ create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-frequency
+ create mode 100644 Documentation/devicetree/bindings/iio/adc/xlnx,versal-sysmon.yaml
+ create mode 100644 Documentation/devicetree/bindings/iio/frequency/adi,adf41513.yaml
+ create mode 100644 Documentation/devicetree/bindings/iio/magnetometer/qstcorp,qmc5883l.yaml
+ create mode 100644 Documentation/iio/adf41513.rst
+ create mode 100644 drivers/iio/adc/mt6323-auxadc.c
+ create mode 100644 drivers/iio/adc/versal-sysmon-core.c
+ create mode 100644 drivers/iio/adc/versal-sysmon-i2c.c
+ create mode 100644 drivers/iio/adc/versal-sysmon.c
+ create mode 100644 drivers/iio/adc/versal-sysmon.h
+ create mode 100644 drivers/iio/dac/mcf54415_dac.c
+ create mode 100644 drivers/iio/frequency/adf41513.c
+ create mode 100644 drivers/iio/magnetometer/qmc5883l.c
+ create mode 100644 include/dt-bindings/iio/adc/mediatek,mt6323-auxadc.h
+Merging nfc/for-next (ed85d4cbbfaa4 nfc: llcp: bound SNL TLV parsing to the skb and add length checks)
+$ git merge -m Merge branch 'for-next' of https://codeberg.org/linux-nfc/linux.git nfc/for-next
+Auto-merging MAINTAINERS
+Auto-merging net/nfc/nci/rsp.c
+CONFLICT (content): Merge conflict in net/nfc/nci/rsp.c
+Resolved 'net/nfc/nci/rsp.c' using previous resolution.
+Automatic merge failed; fix conflicts and then commit the result.
+$ git commit --no-edit -v -a
+[master 46eee5cb8f7ff] Merge branch 'for-next' of https://codeberg.org/linux-nfc/linux.git
+$ git diff -M --stat --summary HEAD^..
+ net/nfc/nci/rsp.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+Merging phy-next/next (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy.git phy-next/next
+Already up to date.
+Merging soundwire/next (90af3209742db soundwire: dmi-quirks: Disable ghost Realtek on Asus Expertbook)
+$ git merge -m Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire.git soundwire/next
+Merge made by the 'ort' strategy.
+ .../bindings/soundwire/qcom,soundwire.yaml | 20 ++++++++++----------
+ drivers/soundwire/dmi-quirks.c | 7 +++++++
+ drivers/soundwire/qcom.c | 9 ++++++---
+ 3 files changed, 23 insertions(+), 13 deletions(-)
+Merging extcon/extcon-next (254f49634ee16 Linux 7.1-rc1)
+$ git merge -m Merge branch 'extcon-next' of https://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/extcon.git extcon/extcon-next
+Already up to date.
+Merging gnss/gnss-next (5d6919055dec1 Linux 7.1-rc3)
+$ git merge -m Merge branch 'gnss-next' of https://git.kernel.org/pub/scm/linux/kernel/git/johan/gnss.git gnss/gnss-next
+Already up to date.
+Merging vfio/next (785562e31dbcd vfio: selftests: Ensure libvfio output dirs are always created)
+$ git merge -m Merge branch 'next' of https://github.com/awilliam/linux-vfio.git vfio/next
+Already up to date.
+Merging w1/for-next (169ae5e65e5aa w1: ds28e17: reject an oversize length on an I2C block read)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-w1.git w1/for-next
+Merge made by the 'ort' strategy.
+ Documentation/devicetree/bindings/w1/omap-hdq.txt | 22 -------
+ Documentation/devicetree/bindings/w1/ti,hdq.yaml | 70 +++++++++++++++++++++++
+ Documentation/w1/masters/omap-hdq.rst | 2 +-
+ drivers/w1/masters/ds2482.c | 8 +++
+ drivers/w1/slaves/w1_ds28e17.c | 8 +++
+ 5 files changed, 87 insertions(+), 23 deletions(-)
+ delete mode 100644 Documentation/devicetree/bindings/w1/omap-hdq.txt
+ create mode 100644 Documentation/devicetree/bindings/w1/ti,hdq.yaml
+Merging spmi/spmi-next (8cdeaa50eae8d Linux 7.2-rc2)
+$ git merge -m Merge branch 'spmi-next' of https://git.kernel.org/pub/scm/linux/kernel/git/sboyd/spmi.git spmi/spmi-next
+Already up to date.
+Merging staging/staging-next (b46e70613266e staging: rtl8723bs: sdio_intf.c: cleanup function)
+$ git merge -m Merge branch 'staging-next' of https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git staging/staging-next
+Auto-merging drivers/staging/rtl8723bs/core/rtw_ieee80211.c
+Auto-merging drivers/staging/rtl8723bs/core/rtw_mlme_ext.c
+Auto-merging drivers/staging/rtl8723bs/core/rtw_wlan_util.c
+Auto-merging drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c
+Auto-merging drivers/staging/rtl8723bs/os_dep/xmit_linux.c
+Merge made by the 'ort' strategy.
+ drivers/staging/axis-fifo/axis-fifo.c | 3 +-
+ drivers/staging/fbtft/fb_upd161704.c | 2 +-
+ drivers/staging/fbtft/fbtft-sysfs.c | 2 +-
+ drivers/staging/greybus/audio_codec.c | 5 +-
+ drivers/staging/greybus/audio_gb.c | 13 ++
+ drivers/staging/greybus/audio_manager_sysfs.c | 2 +-
+ drivers/staging/greybus/authentication.c | 2 -
+ drivers/staging/greybus/hid.c | 2 +-
+ drivers/staging/greybus/loopback.c | 26 ---
+ drivers/staging/greybus/power_supply.c | 4 +-
+ drivers/staging/greybus/vibrator.c | 2 +-
+ drivers/staging/nvec/nvec.c | 4 +-
+ drivers/staging/octeon/ethernet-rx.c | 20 +-
+ drivers/staging/octeon/ethernet-rx.h | 2 +-
+ drivers/staging/octeon/ethernet-tx.c | 19 +-
+ drivers/staging/octeon/ethernet-tx.h | 2 +-
+ drivers/staging/octeon/ethernet.c | 66 ++++--
+ drivers/staging/rtl8723bs/core/rtw_ap.c | 162 +++-----------
+ drivers/staging/rtl8723bs/core/rtw_cmd.c | 207 +++++++++---------
+ drivers/staging/rtl8723bs/core/rtw_efuse.c | 6 +-
+ drivers/staging/rtl8723bs/core/rtw_ieee80211.c | 12 +-
+ drivers/staging/rtl8723bs/core/rtw_io.c | 7 -
+ drivers/staging/rtl8723bs/core/rtw_ioctl_set.c | 24 +--
+ drivers/staging/rtl8723bs/core/rtw_mlme.c | 60 ++----
+ drivers/staging/rtl8723bs/core/rtw_mlme_ext.c | 200 ++++++++---------
+ drivers/staging/rtl8723bs/core/rtw_pwrctrl.c | 28 +--
+ drivers/staging/rtl8723bs/core/rtw_recv.c | 30 +--
+ drivers/staging/rtl8723bs/core/rtw_security.c | 32 +--
+ drivers/staging/rtl8723bs/core/rtw_sta_mgt.c | 4 +-
+ drivers/staging/rtl8723bs/core/rtw_wlan_util.c | 71 +++---
+ drivers/staging/rtl8723bs/core/rtw_xmit.c | 65 +++---
+ drivers/staging/rtl8723bs/hal/HalBtc8723b2Ant.c | 26 +--
+ drivers/staging/rtl8723bs/hal/HalPhyRf.c | 12 +-
+ drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.c | 58 ++---
+ drivers/staging/rtl8723bs/hal/HalPwrSeqCmd.c | 38 ++--
+ drivers/staging/rtl8723bs/hal/hal_btcoex.c | 8 +-
+ drivers/staging/rtl8723bs/hal/hal_com.c | 8 +-
+ drivers/staging/rtl8723bs/hal/hal_com_phycfg.c | 2 +-
+ drivers/staging/rtl8723bs/hal/hal_intf.c | 14 +-
+ drivers/staging/rtl8723bs/hal/hal_sdio.c | 2 +-
+ drivers/staging/rtl8723bs/hal/odm_DIG.c | 2 +-
+ drivers/staging/rtl8723bs/hal/odm_EdcaTurboCheck.c | 2 +-
+ drivers/staging/rtl8723bs/hal/odm_HWConfig.c | 3 +-
+ drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c | 240 +++++++++------------
+ drivers/staging/rtl8723bs/hal/rtl8723b_dm.c | 4 +-
+ drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c | 40 ++--
+ drivers/staging/rtl8723bs/hal/rtl8723b_phycfg.c | 2 +-
+ drivers/staging/rtl8723bs/hal/rtl8723b_rf6052.c | 67 ++----
+ drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c | 10 +-
+ drivers/staging/rtl8723bs/hal/sdio_halinit.c | 58 +++--
+ drivers/staging/rtl8723bs/include/drv_types.h | 2 +-
+ drivers/staging/rtl8723bs/include/hal_com_reg.h | 6 +-
+ drivers/staging/rtl8723bs/include/hal_data.h | 3 -
+ drivers/staging/rtl8723bs/include/hal_intf.h | 2 +-
+ drivers/staging/rtl8723bs/include/ieee80211.h | 30 +--
+ drivers/staging/rtl8723bs/include/ioctl_cfg80211.h | 4 +-
+ .../rtl8723bs/include/osdep_service_linux.h | 3 -
+ drivers/staging/rtl8723bs/include/rtl8192c_recv.h | 3 -
+ drivers/staging/rtl8723bs/include/rtw_ap.h | 2 +-
+ drivers/staging/rtl8723bs/include/rtw_cmd.h | 144 ++++++-------
+ drivers/staging/rtl8723bs/include/rtw_event.h | 4 -
+ drivers/staging/rtl8723bs/include/rtw_ioctl_set.h | 2 +-
+ drivers/staging/rtl8723bs/include/rtw_mlme.h | 61 +++---
+ drivers/staging/rtl8723bs/include/rtw_mlme_ext.h | 56 ++---
+ drivers/staging/rtl8723bs/include/rtw_pwrctrl.h | 6 +-
+ drivers/staging/rtl8723bs/include/rtw_security.h | 4 +-
+ drivers/staging/rtl8723bs/include/sta_info.h | 2 +-
+ drivers/staging/rtl8723bs/include/wifi.h | 34 +--
+ drivers/staging/rtl8723bs/include/wlan_bssdef.h | 38 +---
+ drivers/staging/rtl8723bs/include/xmit_osdep.h | 2 +-
+ drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c | 98 ++++-----
+ drivers/staging/rtl8723bs/os_dep/os_intfs.c | 16 +-
+ drivers/staging/rtl8723bs/os_dep/sdio_intf.c | 18 +-
+ drivers/staging/rtl8723bs/os_dep/wifi_regd.c | 4 +-
+ drivers/staging/rtl8723bs/os_dep/xmit_linux.c | 6 +-
+ drivers/staging/sm750fb/Kconfig | 1 +
+ drivers/staging/sm750fb/sm750.c | 27 +--
+ drivers/staging/sm750fb/sm750.h | 17 +-
+ drivers/staging/sm750fb/sm750_hw.c | 28 +--
+ 79 files changed, 1007 insertions(+), 1296 deletions(-)
+Merging counter-next/counter-next (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'counter-next' of https://git.kernel.org/pub/scm/linux/kernel/git/wbg/counter.git counter-next/counter-next
+Already up to date.
+Merging mux/for-next (59b723cd2adba Linux 6.12-rc6)
+$ git merge -m Merge branch 'for-next' of https://gitlab.com/peda-linux/mux.git mux/for-next
+Already up to date.
+Merging dmaengine/next (0d3e3376b289c dmaengine: pl330: remove debugfs file on teardown)
+$ git merge -m Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine.git dmaengine/next
+Auto-merging drivers/crypto/atmel-aes.c
+Merge made by the 'ort' strategy.
+ .../devicetree/bindings/dma/mediatek,uart-dma.yaml | 1 +
+ .../bindings/dma/xilinx/xlnx,axi-dma.yaml | 13 +-
+ Documentation/driver-api/dmaengine/client.rst | 9 ++
+ drivers/crypto/atmel-aes.c | 10 +-
+ drivers/dma/dmaengine.c | 2 +
+ drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 2 +-
+ drivers/dma/dw-edma/dw-edma-core.c | 41 ++++--
+ drivers/dma/hisi_dma.c | 2 +-
+ drivers/dma/mediatek/mtk-uart-apdma.c | 2 +-
+ drivers/dma/pl330.c | 19 ++-
+ drivers/dma/tegra210-adma.c | 12 +-
+ drivers/dma/xilinx/xilinx_dma.c | 64 +++++----
+ drivers/dma/xilinx/zynqmp_dma.c | 6 +-
+ drivers/nvme/target/pci-epf.c | 33 +----
+ drivers/pci/endpoint/functions/pci-epf-mhi.c | 52 +++----
+ drivers/pci/endpoint/functions/pci-epf-test.c | 8 +-
+ include/linux/dmaengine.h | 149 +++++++++++++++++++--
+ 17 files changed, 282 insertions(+), 143 deletions(-)
+Merging cgroup/for-next (37f35256008bb Merge branch 'for-7.2-fixes' into for-next)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git cgroup/for-next
+Auto-merging Documentation/admin-guide/cgroup-v2.rst
+Auto-merging kernel/cgroup/cpuset.c
+Merge made by the 'ort' strategy.
+ Documentation/admin-guide/cgroup-v1/memcg_test.rst | 2 +-
+ Documentation/admin-guide/cgroup-v1/rdma.rst | 66 +++
+ Documentation/admin-guide/cgroup-v2.rst | 50 ++-
+ include/linux/cgroup-defs.h | 2 +-
+ include/linux/cgroup.h | 2 +-
+ kernel/cgroup/cpuset-internal.h | 12 +-
+ kernel/cgroup/cpuset.c | 462 +++++++++++++--------
+ tools/cgroup/iocost_monitor.py | 10 +-
+ .../selftests/cgroup/lib/include/cgroup_util.h | 1 +
+ tools/testing/selftests/cgroup/test_cpu.c | 43 +-
+ tools/testing/selftests/cgroup/test_cpuset_prs.sh | 11 +-
+ 11 files changed, 462 insertions(+), 199 deletions(-)
+Merging scsi/for-next (cf1af0ccca54d Merge branch 'misc' into for-next)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git scsi/for-next
+Merge made by the 'ort' strategy.
+Merging scsi-mkp/for-next (57a6ed0b41677 scsi: bfa: Reduce kernel stack usage in bfa_fcs_lport_fdmi_build_portattr_block())
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git scsi-mkp/for-next
+Auto-merging drivers/scsi/scsi_lib.c
+Merge made by the 'ort' strategy.
+ drivers/scsi/bfa/bfa_fcs_lport.c | 2 +-
+ drivers/scsi/scsi_lib.c | 8 --------
+ drivers/scsi/scsi_priv.h | 1 +
+ drivers/xen/xen-scsiback.c | 30 +++++++++++++++++++++++-------
+ include/scsi/scsi_device.h | 1 -
+ 5 files changed, 25 insertions(+), 17 deletions(-)
+Merging vhost/linux-next (1f673033c0273 vduse: Add suspend)
+$ git merge -m Merge branch 'linux-next' of https://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost.git vhost/linux-next
+Auto-merging drivers/vdpa/vdpa_user/vduse_dev.c
+Merge made by the 'ort' strategy.
+ drivers/vdpa/vdpa_user/vduse_dev.c | 136 +++++++++++++++++++++++++++++++++----
+ include/uapi/linux/vduse.h | 29 +++++++-
+ 2 files changed, 150 insertions(+), 15 deletions(-)
+Merging rpmsg/for-next (066e0d00bee13 Merge branch 'rproc-next' into for-next)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux.git rpmsg/for-next
+Merge made by the 'ort' strategy.
+ .../devicetree/bindings/remoteproc/qcom,adsp.yaml | 82 ++++-----
+ .../remoteproc/qcom,kaanapali-soccp-pas.yaml | 156 ++++++++++++++++
+ .../bindings/remoteproc/qcom,milos-pas.yaml | 26 ++-
+ .../bindings/remoteproc/qcom,pas-common.yaml | 28 ++-
+ .../bindings/remoteproc/qcom,qcs404-pas.yaml | 22 ++-
+ .../bindings/remoteproc/qcom,sa8775p-pas.yaml | 22 ++-
+ .../bindings/remoteproc/qcom,sc7180-pas.yaml | 28 +++
+ .../bindings/remoteproc/qcom,sc8280xp-pas.yaml | 28 +++
+ .../bindings/remoteproc/qcom,sdx55-pas.yaml | 24 ++-
+ .../bindings/remoteproc/qcom,shikra-pas.yaml | 20 ++
+ .../bindings/remoteproc/qcom,sm6115-pas.yaml | 28 +++
+ .../bindings/remoteproc/qcom,sm6350-pas.yaml | 28 +++
+ .../bindings/remoteproc/qcom,sm6375-pas.yaml | 28 +++
+ .../bindings/remoteproc/qcom,sm8150-pas.yaml | 28 +++
+ .../bindings/remoteproc/qcom,sm8350-pas.yaml | 28 +++
+ .../bindings/remoteproc/qcom,sm8550-pas.yaml | 28 +++
+ drivers/firmware/xilinx/zynqmp.c | 93 ++++++++++
+ drivers/remoteproc/Kconfig | 4 +-
+ drivers/remoteproc/imx_dsp_rproc.c | 41 +----
+ drivers/remoteproc/imx_rproc.c | 40 +---
+ drivers/remoteproc/keystone_remoteproc.c | 2 +-
+ drivers/remoteproc/mtk_scp.c | 9 +-
+ drivers/remoteproc/omap_remoteproc.c | 2 +-
+ drivers/remoteproc/qcom_common.h | 6 +
+ drivers/remoteproc/qcom_q6v5.c | 3 +-
+ drivers/remoteproc/qcom_q6v5_mss.c | 5 +-
+ drivers/remoteproc/qcom_q6v5_pas.c | 137 +++++++++++---
+ drivers/remoteproc/qcom_sysmon.c | 19 ++
+ drivers/remoteproc/qcom_wcnss.c | 12 +-
+ drivers/remoteproc/rcar_rproc.c | 41 +----
+ drivers/remoteproc/remoteproc_core.c | 15 +-
+ drivers/remoteproc/remoteproc_internal.h | 54 ++++++
+ drivers/remoteproc/st_remoteproc.c | 31 +---
+ drivers/remoteproc/stm32_rproc.c | 39 +---
+ drivers/remoteproc/ti_k3_r5_remoteproc.c | 8 +-
+ drivers/remoteproc/xlnx_r5_remoteproc.c | 204 +++++++++------------
+ drivers/soc/qcom/mdt_loader.c | 12 +-
+ include/linux/firmware/xlnx-zynqmp.h | 12 ++
+ include/linux/soc/qcom/mdt_loader.h | 6 +-
+ 39 files changed, 982 insertions(+), 417 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/remoteproc/qcom,kaanapali-soccp-pas.yaml
+Merging gpio-brgl/gpio/for-next (611fd6cfe1399 gpio: swnode: remove deprecated lookup mechanism)
+$ git merge -m Merge branch 'gpio/for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git gpio-brgl/gpio/for-next
+Auto-merging drivers/gpio/gpio-mvebu.c
+Merge made by the 'ort' strategy.
+ .../bindings/gpio/realtek,rtd1625-gpio.yaml | 71 +++
+ drivers/gpio/Kconfig | 14 +-
+ drivers/gpio/Makefile | 1 +
+ drivers/gpio/gpio-amd-fch.c | 22 +-
+ drivers/gpio/gpio-mt7621.c | 40 +-
+ drivers/gpio/gpio-mvebu.c | 40 +-
+ drivers/gpio/gpio-nomadik.c | 64 +--
+ drivers/gpio/gpio-pca9570.c | 2 +-
+ drivers/gpio/gpio-rcar.c | 1 -
+ drivers/gpio/gpio-rockchip.c | 16 +-
+ drivers/gpio/gpio-rtd1625.c | 611 +++++++++++++++++++++
+ drivers/gpio/gpio-sifive.c | 1 +
+ drivers/gpio/gpio-tb10x.c | 5 +-
+ drivers/gpio/gpiolib-cdev.c | 9 +-
+ drivers/gpio/gpiolib-kunit.c | 280 +++++++++-
+ drivers/gpio/gpiolib-swnode.c | 23 +-
+ 16 files changed, 1064 insertions(+), 136 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/gpio/realtek,rtd1625-gpio.yaml
+ create mode 100644 drivers/gpio/gpio-rtd1625.c
+Merging gpio-intel/for-next (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-gpio-intel.git gpio-intel/for-next
+Already up to date.
+Merging pinctrl/for-next (94cb9e8f27079 pinctrl: s32cc: implement GPIO functionality)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl.git pinctrl/for-next
+Auto-merging MAINTAINERS
+Merge made by the 'ort' strategy.
+ .../pinctrl/aspeed,ast2700-soc1-pinctrl.yaml | 1 +
+ .../bindings/pinctrl/nxp,s32g2-siul2-pinctrl.yaml | 90 ++-
+ MAINTAINERS | 7 +
+ drivers/pinctrl/aspeed/pinctrl-aspeed-g7-soc1.c | 6 +-
+ drivers/pinctrl/bcm/pinctrl-bcm2835.c | 1 -
+ drivers/pinctrl/freescale/pinctrl-imx1-core.c | 7 +-
+ drivers/pinctrl/nxp/Kconfig | 3 +-
+ drivers/pinctrl/nxp/pinctrl-s32.h | 35 +-
+ drivers/pinctrl/nxp/pinctrl-s32cc.c | 768 ++++++++++++++++++---
+ drivers/pinctrl/nxp/pinctrl-s32g2.c | 47 +-
+ drivers/pinctrl/pinctrl-tb10x.c | 2 +-
+ 11 files changed, 856 insertions(+), 111 deletions(-)
+Merging pinctrl-intel/for-next (ed1608d5e3c44 Merge patch series "upboard pinctrl support for device id INTC1055")
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/pinctrl/intel.git pinctrl-intel/for-next
+Auto-merging drivers/pinctrl/intel/pinctrl-tigerlake.c
+Merge made by the 'ort' strategy.
+ drivers/pinctrl/intel/pinctrl-tigerlake.c | 32 +++++++++++++++++++++++++++++++
+ drivers/pinctrl/pinctrl-upboard.c | 21 ++++++++++++++++++++
+ 2 files changed, 53 insertions(+)
+Merging pinctrl-renesas/renesas-pinctrl (5a653cedec948 pinctrl: renesas: rza2: Embed pins in the priv struct)
+$ git merge -m Merge branch 'renesas-pinctrl' of https://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers.git pinctrl-renesas/renesas-pinctrl
+Merge made by the 'ort' strategy.
+ drivers/pinctrl/renesas/pinctrl-rza2.c | 26 +++++++++++---------------
+ 1 file changed, 11 insertions(+), 15 deletions(-)
+Merging pinctrl-samsung/for-next (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/pinctrl/samsung.git pinctrl-samsung/for-next
+Already up to date.
+Merging pinctrl-qcom/pinctrl-qcom/for-next (77fbc756d9cbe Revert "pinctrl: qcom: x1e80100: Bypass PDC wakeup parent for now")
+$ git merge -m Merge branch 'pinctrl-qcom/for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git pinctrl-qcom/pinctrl-qcom/for-next
+Auto-merging drivers/pinctrl/qcom/pinctrl-msm.c
+Merge made by the 'ort' strategy.
+ .../bindings/pinctrl/qcom,maili-tlmm.yaml | 120 ++
+ .../bindings/pinctrl/qcom,pmic-gpio.yaml | 3 +
+ drivers/pinctrl/qcom/Kconfig.msm | 10 +
+ drivers/pinctrl/qcom/Makefile | 1 +
+ drivers/pinctrl/qcom/pinctrl-maili.c | 1625 ++++++++++++++++++++
+ drivers/pinctrl/qcom/pinctrl-msm.c | 24 +-
+ drivers/pinctrl/qcom/pinctrl-spmi-gpio.c | 1 +
+ drivers/pinctrl/qcom/pinctrl-x1e80100.c | 4 +-
+ drivers/pinctrl/qcom/tlmm-test.c | 3 -
+ 9 files changed, 1778 insertions(+), 13 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/pinctrl/qcom,maili-tlmm.yaml
+ create mode 100644 drivers/pinctrl/qcom/pinctrl-maili.c
+Merging pwm/pwm/for-next (0062b71a3e546 pwm: lpss-pci: Unify coding style of pci_device_id array)
+$ git merge -m Merge branch 'pwm/for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/ukleinek/linux.git pwm/pwm/for-next
+Auto-merging drivers/pwm/pwm-adp5585.c
+Auto-merging drivers/pwm/pwm-apple.c
+Auto-merging drivers/pwm/pwm-berlin.c
+Auto-merging drivers/pwm/pwm-lpc18xx-sct.c
+Auto-merging drivers/pwm/pwm-lpss-platform.c
+Auto-merging drivers/pwm/pwm-pxa.c
+Auto-merging drivers/pwm/pwm-sifive.c
+Auto-merging drivers/pwm/pwm-sl28cpld.c
+Auto-merging drivers/pwm/pwm-sprd.c
+Auto-merging drivers/pwm/pwm-sunplus.c
+Auto-merging drivers/pwm/pwm-vt8500.c
+Merge made by the 'ort' strategy.
+ drivers/pwm/Kconfig | 2 +-
+ drivers/pwm/pwm-adp5585.c | 4 ++--
+ drivers/pwm/pwm-apple.c | 2 +-
+ drivers/pwm/pwm-argon-fan-hat.c | 2 +-
+ drivers/pwm/pwm-atmel-hlcdc.c | 15 ++++++---------
+ drivers/pwm/pwm-atmel-tcb.c | 6 +++---
+ drivers/pwm/pwm-atmel.c | 3 +--
+ drivers/pwm/pwm-bcm-iproc.c | 2 +-
+ drivers/pwm/pwm-bcm-kona.c | 2 +-
+ drivers/pwm/pwm-bcm2835.c | 2 +-
+ drivers/pwm/pwm-berlin.c | 2 +-
+ drivers/pwm/pwm-brcmstb.c | 2 +-
+ drivers/pwm/pwm-clk.c | 2 +-
+ drivers/pwm/pwm-clps711x.c | 2 +-
+ drivers/pwm/pwm-cros-ec.c | 2 +-
+ drivers/pwm/pwm-hibvt.c | 2 +-
+ drivers/pwm/pwm-imx-tpm.c | 2 +-
+ drivers/pwm/pwm-imx1.c | 2 +-
+ drivers/pwm/pwm-imx27.c | 2 +-
+ drivers/pwm/pwm-ipq.c | 4 ++--
+ drivers/pwm/pwm-jz4740.c | 2 +-
+ drivers/pwm/pwm-loongson.c | 2 +-
+ drivers/pwm/pwm-lp3943.c | 2 +-
+ drivers/pwm/pwm-lpc18xx-sct.c | 2 +-
+ drivers/pwm/pwm-lpc32xx.c | 2 +-
+ drivers/pwm/pwm-lpss-pci.c | 2 +-
+ drivers/pwm/pwm-lpss-platform.c | 10 +++++-----
+ drivers/pwm/pwm-mc33xs2410.c | 2 +-
+ drivers/pwm/pwm-mediatek.c | 2 +-
+ drivers/pwm/pwm-meson.c | 9 ++++-----
+ drivers/pwm/pwm-mtk-disp.c | 8 ++++----
+ drivers/pwm/pwm-mxs.c | 2 +-
+ drivers/pwm/pwm-omap-dmtimer.c | 4 ++--
+ drivers/pwm/pwm-pca9685.c | 6 +++---
+ drivers/pwm/pwm-pxa.c | 30 ++++++++++++------------------
+ drivers/pwm/pwm-raspberrypi-poe.c | 2 +-
+ drivers/pwm/pwm-rcar.c | 4 ++--
+ drivers/pwm/pwm-renesas-tpu.c | 10 +++++-----
+ drivers/pwm/pwm-rockchip.c | 8 ++++----
+ drivers/pwm/pwm-rzg2l-gpt.c | 2 +-
+ drivers/pwm/pwm-samsung.c | 2 +-
+ drivers/pwm/pwm-sifive.c | 2 +-
+ drivers/pwm/pwm-sl28cpld.c | 2 +-
+ drivers/pwm/pwm-sophgo-sg2042.c | 7 +++----
+ drivers/pwm/pwm-sprd.c | 4 ++--
+ drivers/pwm/pwm-sti.c | 2 +-
+ drivers/pwm/pwm-stm32-lp.c | 4 ++--
+ drivers/pwm/pwm-stm32.c | 6 +++---
+ drivers/pwm/pwm-sun4i.c | 2 +-
+ drivers/pwm/pwm-sunplus.c | 4 ++--
+ drivers/pwm/pwm-tiecap.c | 6 +++---
+ drivers/pwm/pwm-tiehrpwm.c | 2 +-
+ drivers/pwm/pwm-twl-led.c | 2 +-
+ drivers/pwm/pwm-twl.c | 2 +-
+ drivers/pwm/pwm-visconti.c | 2 +-
+ drivers/pwm/pwm-vt8500.c | 2 +-
+ drivers/pwm/pwm-xilinx.c | 4 ++--
+ 57 files changed, 108 insertions(+), 120 deletions(-)
+Merging ktest/for-next (932cdaf3e273a ktest: Add logfile to failure directory)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-ktest.git ktest/for-next
+Already up to date.
+Merging kselftest/next (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest.git kselftest/next
+Already up to date.
+Merging kunit/test (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'test' of https://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest.git kunit/test
+Already up to date.
+Merging kunit-next/kunit (f47180b0e9cc5 kunit: string-stream: Replace strlcat() with strscpy() and seq_buf)
+$ git merge -m Merge branch 'kunit' of https://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest.git kunit-next/kunit
+Merge made by the 'ort' strategy.
+ Documentation/dev-tools/kunit/faq.rst | 43 ++++++++++++++++++---------------
+ Documentation/dev-tools/kunit/style.rst | 7 +++---
+ include/kunit/test.h | 1 +
+ lib/kunit/debugfs.c | 28 +++++++++++++++------
+ lib/kunit/kunit-example-test.c | 29 ++++++++++++++++++++++
+ lib/kunit/string-stream.c | 9 +++++--
+ lib/kunit/test.c | 17 ++++++++++++-
+ rust/kernel/kunit.rs | 1 +
+ 8 files changed, 102 insertions(+), 33 deletions(-)
+Merging livepatching/for-next (0839c8963b7b2 Merge tag 'livepatching-for-7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/livepatching/livepatching)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/livepatching/livepatching.git livepatching/for-next
+Already up to date.
+Merging rtc/rtc-next (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'rtc-next' of https://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux.git rtc/rtc-next
+Already up to date.
+Merging nvdimm/libnvdimm-for-next (86e411b6ec277 MAINTAINERS: nvdimm: Include maintainer profile)
+$ git merge -m Merge branch 'libnvdimm-for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm.git nvdimm/libnvdimm-for-next
+Already up to date.
+Merging at24/at24/for-next (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'at24/for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git at24/at24/for-next
+Already up to date.
+Merging ntb/ntb-next (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'ntb-next' of https://github.com/jonmason/ntb.git ntb/ntb-next
+Already up to date.
+Merging seccomp/for-next/seccomp (41fa043273841 selftests/seccomp: Add hard-coded __NR_uprobe for x86_64)
+$ git merge -m Merge branch 'for-next/seccomp' of https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git seccomp/for-next/seccomp
+Already up to date.
+Merging slimbus/for-next (c922423ce66bc slimbus: qcom-ngd-ctrl: Use the unified QMI service ID instead of defining it locally)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/srini/slimbus.git slimbus/for-next
+Merge made by the 'ort' strategy.
+ drivers/slimbus/qcom-ngd-ctrl.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+Merging nvmem/for-next (ea87821719eea nvmem: protect nvmem_device::ops with SRCU)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/srini/nvmem.git nvmem/for-next
+Auto-merging drivers/nvmem/nintendo-otp.c
+Merge made by the 'ort' strategy.
+ .../bindings/nvmem/airoha,smc-efuses.yaml | 67 +++++
+ .../bindings/nvmem/microchip,lan9662-otpc.yaml | 1 +
+ .../devicetree/bindings/nvmem/qcom,qfprom.yaml | 4 +
+ drivers/nvmem/Kconfig | 22 +-
+ drivers/nvmem/Makefile | 2 +
+ drivers/nvmem/airoha-smc-efuses.c | 125 ++++++++
+ drivers/nvmem/core.c | 319 +++++++++++----------
+ drivers/nvmem/internals.h | 13 +-
+ drivers/nvmem/lan9662-otpc.c | 12 +-
+ drivers/nvmem/layouts/u-boot-env.c | 5 +-
+ drivers/nvmem/nintendo-otp.c | 9 +-
+ drivers/nvmem/rockchip-otp.c | 9 +-
+ 12 files changed, 413 insertions(+), 175 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/nvmem/airoha,smc-efuses.yaml
+ create mode 100644 drivers/nvmem/airoha-smc-efuses.c
+Merging hyperv/hyperv-next (a4ffc59238be8 mshv: add bounds check on vp_index in mshv_intercept_isr())
+$ git merge -m Merge branch 'hyperv-next' of https://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux.git hyperv/hyperv-next
+Already up to date.
+Merging auxdisplay/for-next (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-auxdisplay.git auxdisplay/for-next
+Already up to date.
+Merging kgdb/kgdb/for-next (fdbdd0ccb30af kdb: remove redundant check for scancode 0xe0)
+$ git merge -m Merge branch 'kgdb/for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/danielt/linux.git kgdb/kgdb/for-next
+Already up to date.
+Merging hmm/hmm (19272b37aa4f8 Linux 6.16-rc1)
+$ git merge -m Merge branch 'hmm' of https://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma.git hmm/hmm
+Already up to date.
+Merging cfi/cfi/next (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'cfi/next' of https://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git cfi/cfi/next
+Already up to date.
+Merging mhi/mhi-next (34c66fc4c223a bus: mhi: host: Flush the posted write after writing to MHI_SOC_RESET_REQ_OFFSET)
+$ git merge -m Merge branch 'mhi-next' of https://git.kernel.org/pub/scm/linux/kernel/git/mani/mhi.git mhi/mhi-next
+Auto-merging MAINTAINERS
+Auto-merging drivers/bus/mhi/ep/main.c
+Merge made by the 'ort' strategy.
+ MAINTAINERS | 1 +
+ drivers/bus/mhi/ep/main.c | 15 ++++++++++-----
+ drivers/bus/mhi/host/main.c | 6 ++++++
+ drivers/bus/mhi/host/pm.c | 14 +++-----------
+ 4 files changed, 20 insertions(+), 16 deletions(-)
+$ git am -3 ../patches/0001-fix-up-for-net-qrtr-Drop-the-MHI-auto_queue-feature-.patch
+Applying: fix up for "net: qrtr: Drop the MHI auto_queue feature for IPCR DL channels"
+Using index info to reconstruct a base tree...
+M drivers/net/wireless/ath/ath12k/wifi7/mhi.c
+Falling back to patching base and 3-way merge...
+No changes -- Patch already applied.
+Merging memblock/for-next (1a6e6a79b8df1 Merge branch 'misc' into for-next)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/rppt/memblock.git memblock/for-next
+Auto-merging arch/riscv/mm/init.c
+Auto-merging drivers/base/arch_numa.c
+Auto-merging mm/hugetlb.c
+Auto-merging mm/mm_init.c
+Merge made by the 'ort' strategy.
+ arch/arm/mm/kasan_init.c | 6 ----
+ arch/arm64/mm/kasan_init.c | 3 --
+ arch/loongarch/kernel/numa.c | 1 -
+ arch/loongarch/mm/kasan_init.c | 3 --
+ arch/powerpc/mm/kasan/init_book3e_64.c | 3 --
+ arch/powerpc/mm/kasan/init_book3s_64.c | 3 --
+ arch/riscv/mm/init.c | 2 --
+ arch/riscv/mm/kasan_init.c | 3 --
+ arch/x86/mm/amdtopology.c | 1 -
+ arch/x86/mm/numa.c | 1 -
+ drivers/base/arch_numa.c | 4 ---
+ drivers/of/of_numa.c | 5 +--
+ mm/hugetlb.c | 7 ++--
+ mm/memblock.c | 4 +--
+ mm/mm_init.c | 63 +++-------------------------------
+ mm/numa_memblks.c | 41 ++++++++++------------
+ 16 files changed, 27 insertions(+), 123 deletions(-)
+Merging cxl/next (31adec5c3dc48 Merge branch 'for-7.3/cxl-fixes' into cxl-for-next)
+$ git merge -m Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl.git cxl/next
+Merge made by the 'ort' strategy.
+ Documentation/driver-api/cxl/linux/dax-driver.rst | 4 +-
+ drivers/cxl/core/features.c | 8 +-
+ drivers/cxl/core/mbox.c | 14 +-
+ drivers/cxl/core/mce.c | 27 +-
+ drivers/cxl/core/region.c | 43 +-
+ drivers/cxl/cxl.h | 8 +-
+ drivers/cxl/cxlmem.h | 4 +-
+ drivers/cxl/pci.c | 6 -
+ tools/testing/cxl/test/Kbuild | 2 +
+ tools/testing/cxl/test/accel.c | 66 ++
+ tools/testing/cxl/test/cxl.c | 842 +++++++++++++++++-----
+ tools/testing/cxl/test/hmem_test.c | 3 +-
+ tools/testing/cxl/test/mock.h | 2 +
+ 13 files changed, 756 insertions(+), 273 deletions(-)
+ create mode 100644 tools/testing/cxl/test/accel.c
+Merging zstd/zstd-next (65d1f5507ed2c zstd: Import upstream v1.5.7)
+$ git merge -m Merge branch 'zstd-next' of https://github.com/terrelln/linux.git zstd/zstd-next
+Already up to date.
+Merging efi/next (cf790fdb85186 efi/runtime-wrappers: retire the worker if a wedged call ever returns)
+$ git merge -m Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git efi/next
+Merge made by the 'ort' strategy.
+ arch/x86/platform/efi/quirks.c | 9 +----
+ drivers/firmware/efi/runtime-wrappers.c | 68 ++++++++++++++++++++++++++++-----
+ include/linux/efi.h | 6 ++-
+ 3 files changed, 64 insertions(+), 19 deletions(-)
+Merging unicode/for-next (bcfee135d5847 utf8: Remove unused utf8_normalize)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/krisman/unicode.git unicode/for-next
+Auto-merging fs/unicode/utf8-core.c
+Merge made by the 'ort' strategy.
+ fs/unicode/utf8-core.c | 22 ----------------------
+ include/linux/unicode.h | 3 ---
+ 2 files changed, 25 deletions(-)
+Merging slab/slab/for-next (23dae2e639711 mm/slab: extract __free_to_pcs_batch() from free_to_pcs_bulk())
+$ git merge -m Merge branch 'slab/for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/vbabka/slab.git slab/slab/for-next
+Auto-merging Documentation/admin-guide/kernel-parameters.txt
+Auto-merging mm/slub.c
+Merge made by the 'ort' strategy.
+ Documentation/ABI/testing/sysfs-kernel-slab | 18 ++-
+ Documentation/admin-guide/kernel-parameters.txt | 5 +
+ mm/mempool.c | 35 +++--
+ mm/slub.c | 164 +++++++++++-------------
+ 4 files changed, 113 insertions(+), 109 deletions(-)
+$ git am -3 ../patches/0001-drm-panthor-I-love-Werror.patch
+Applying: drm/panthor: I love -Werror
+Using index info to reconstruct a base tree...
+M drivers/gpu/drm/panthor/panthor_mmu.c
+Falling back to patching base and 3-way merge...
+Auto-merging drivers/gpu/drm/panthor/panthor_mmu.c
+No changes -- Patch already applied.
+Merging random/master (bb9ff576fdff4 virt: vmgenid: remap memory as decrypted)
+$ git merge -m Merge branch 'master' of https://git.kernel.org/pub/scm/linux/kernel/git/crng/random.git random/master
+Merge made by the 'ort' strategy.
+ drivers/virt/vmgenid.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+Merging landlock/next (55f82176ef8dd selftests/landlock: Fix spelling error in fs_test comment)
+$ git merge -m Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/mic/linux.git landlock/next
+Merge made by the 'ort' strategy.
+ Documentation/admin-guide/LSM/landlock.rst | 1 +
+ include/uapi/linux/landlock.h | 8 +-
+ security/landlock/net.c | 8 ++
+ security/landlock/ruleset.h | 4 +-
+ security/landlock/task.c | 20 +++--
+ tools/testing/selftests/landlock/fs_test.c | 2 +-
+ tools/testing/selftests/landlock/net_test.c | 97 ++++++++++++++++++++++
+ .../selftests/landlock/scoped_signal_test.c | 67 ++++++++++-----
+ 8 files changed, 171 insertions(+), 36 deletions(-)
+Merging sysctl/sysctl-next (dccde188b7fc1 sysctl: add Returns: kernel-doc for all functions)
+$ git merge -m Merge branch 'sysctl-next' of https://git.kernel.org/pub/scm/linux/kernel/git/sysctl/sysctl.git sysctl/sysctl-next
+Merge made by the 'ort' strategy.
+ fs/pipe.c | 2 +-
+ include/linux/sysctl.h | 125 ++++++++----
+ kernel/sysctl.c | 530 ++++++++++++++++++++++++++-----------------------
+ kernel/time/jiffies.c | 28 ++-
+ 4 files changed, 395 insertions(+), 290 deletions(-)
+Merging execve/for-next/execve (9bf092c97b86a sched: update task_struct->comm comment)
+$ git merge -m Merge branch 'for-next/execve' of https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git execve/for-next/execve
+Already up to date.
+Merging bitmap/bitmap-for-next (df2f996d1bcc6 bitmap: Properly initialise destination bitmap for scatter & gather test)
+$ git merge -m Merge branch 'bitmap-for-next' of https://github.com/norov/linux.git bitmap/bitmap-for-next
+Auto-merging arch/x86/events/amd/uncore.c
+Auto-merging arch/x86/events/intel/core.c
+Auto-merging arch/x86/events/intel/uncore.c
+Auto-merging drivers/devfreq/event/rockchip-dfi.c
+Auto-merging drivers/fpga/dfl-fme-perf.c
+Auto-merging drivers/pci/pci-sysfs.c
+Auto-merging kernel/events/core.c
+Merge made by the 'ort' strategy.
+ arch/arm/mach-imx/mmdc.c | 2 +-
+ arch/arm/mm/cache-l2x0-pmu.c | 2 +-
+ arch/powerpc/kernel/cacheinfo.c | 3 ++-
+ arch/powerpc/perf/hv-24x7.c | 2 +-
+ arch/powerpc/perf/hv-gpci.c | 2 +-
+ arch/powerpc/perf/imc-pmu.c | 2 +-
+ arch/x86/events/amd/iommu.c | 2 +-
+ arch/x86/events/amd/power.c | 2 +-
+ arch/x86/events/amd/uncore.c | 2 +-
+ arch/x86/events/intel/core.c | 2 +-
+ arch/x86/events/intel/uncore.c | 2 +-
+ drivers/base/cpu.c | 2 +-
+ drivers/devfreq/event/rockchip-dfi.c | 2 +-
+ drivers/devfreq/hisi_uncore_freq.c | 2 +-
+ drivers/firmware/psci/psci_checker.c | 15 ++---------
+ drivers/fpga/dfl-fme-perf.c | 2 +-
+ drivers/hwtracing/ptt/hisi_ptt.c | 2 +-
+ drivers/infiniband/hw/hfi1/sdma.c | 3 ++-
+ drivers/pci/pci-sysfs.c | 7 +++---
+ drivers/perf/alibaba_uncore_drw_pmu.c | 2 +-
+ drivers/perf/amlogic/meson_ddr_pmu_core.c | 2 +-
+ drivers/perf/arm-cci.c | 2 +-
+ drivers/perf/arm-ccn.c | 2 +-
+ drivers/perf/arm-cmn.c | 2 +-
+ drivers/perf/arm-ni.c | 2 +-
+ drivers/perf/arm_cspmu/arm_cspmu.c | 2 +-
+ drivers/perf/arm_dmc620_pmu.c | 4 +--
+ drivers/perf/arm_dsu_pmu.c | 2 +-
+ drivers/perf/arm_pmu.c | 2 +-
+ drivers/perf/arm_smmuv3_pmu.c | 2 +-
+ drivers/perf/arm_spe_pmu.c | 2 +-
+ drivers/perf/cxl_pmu.c | 2 +-
+ drivers/perf/dwc_pcie_pmu.c | 2 +-
+ drivers/perf/fsl_imx8_ddr_perf.c | 2 +-
+ drivers/perf/fsl_imx9_ddr_perf.c | 2 +-
+ drivers/perf/fujitsu_uncore_pmu.c | 2 +-
+ drivers/perf/hisilicon/hisi_pcie_pmu.c | 2 +-
+ drivers/perf/hisilicon/hisi_uncore_pmu.c | 2 +-
+ drivers/perf/marvell_cn10k_ddr_pmu.c | 2 +-
+ drivers/perf/marvell_cn10k_tad_pmu.c | 2 +-
+ drivers/perf/marvell_pem_pmu.c | 2 +-
+ drivers/perf/nvidia_t410_c2c_pmu.c | 2 +-
+ drivers/perf/nvidia_t410_cmem_latency_pmu.c | 2 +-
+ drivers/perf/qcom_l2_pmu.c | 2 +-
+ drivers/perf/qcom_l3_pmu.c | 2 +-
+ drivers/perf/starfive_starlink_pmu.c | 2 +-
+ drivers/perf/thunderx2_pmu.c | 2 +-
+ drivers/perf/xgene_pmu.c | 2 +-
+ include/asm-generic/bitops/le.h | 18 ++++++-------
+ include/linux/bitmap.h | 4 +--
+ include/linux/bits.h | 6 ++---
+ include/linux/cpumask.h | 19 --------------
+ kernel/events/core.c | 2 +-
+ lib/bitmap-str.c | 9 +++----
+ lib/bitmap.c | 32 +++++++++++++----------
+ lib/find_bit_benchmark.c | 17 +++++++++++++
+ lib/test_bitmap.c | 39 +++++++++++++++++++++++++++++
+ tools/include/linux/bits.h | 6 ++---
+ 58 files changed, 152 insertions(+), 118 deletions(-)
+Merging hte/for-next (005b25ad11717 hte: tegra194: Add Tegra264 GTE support)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/pateldipen1984/linux.git hte/for-next
+Already up to date.
+Merging kspp/for-next/kspp (c2606fb910d7c Merge branch 'for-next/hardening' into for-next/kspp)
+$ git merge -m Merge branch 'for-next/kspp' of https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git kspp/for-next/kspp
+Merge made by the 'ort' strategy.
+Merging nolibc/for-next (a3b2181459a2c tools/nolibc: mark arg1 operand in __nolibc_syscall0() as write-only)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/nolibc/linux-nolibc.git nolibc/for-next
+Merge made by the 'ort' strategy.
+ tools/include/nolibc/arch-sparc.h | 2 +-
+ tools/include/nolibc/unistd.h | 58 ++++++++++++++++++++++++++++
+ tools/testing/selftests/nolibc/nolibc-test.c | 53 +++++++++++++++++++++++++
+ 3 files changed, 112 insertions(+), 1 deletion(-)
+Merging iommufd/for-next (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/jgg/iommufd.git iommufd/for-next
+Already up to date.
+Merging turbostat/next (1c996a37fd244 tools/power turbostat: pmt: Improve sscanf() hygiene)
+$ git merge -m Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux.git turbostat/next
+Merge made by the 'ort' strategy.
+ tools/power/x86/turbostat/turbostat.8 | 6 +-
+ tools/power/x86/turbostat/turbostat.c | 567 ++++++++++++++++------------------
+ 2 files changed, 266 insertions(+), 307 deletions(-)
+Merging pwrseq/pwrseq/for-next (162ea02941a93 power: sequencing: pwrseq-pcie-m2: Add QCC2072 BT PCI device ID)
+$ git merge -m Merge branch 'pwrseq/for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git pwrseq/pwrseq/for-next
+Auto-merging drivers/power/sequencing/pwrseq-pcie-m2.c
+Merge made by the 'ort' strategy.
+ drivers/power/sequencing/pwrseq-pcie-m2.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+Merging capabilities-next/caps-next (0715881360074 ipc: don't audit capability check in ipc_permissions())
+$ git merge -m Merge branch 'caps-next' of https://git.kernel.org/pub/scm/linux/kernel/git/sergeh/linux.git capabilities-next/caps-next
+Already up to date.
+$ git am -3 ../patches/0001-sign-file-Fix-up-merge-issue.patch
+Applying: sign-file: Fix up merge issue
+Using index info to reconstruct a base tree...
+M scripts/sign-file.c
+Falling back to patching base and 3-way merge...
+Auto-merging scripts/sign-file.c
+No changes -- Patch already applied.
+Merging ipe/next (028ef9c96e961 Linux 7.0)
+$ git merge -m Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/wufan/ipe.git ipe/next
+Already up to date.
+Merging kcsan/next (07a1a6562ce29 kcsan: Silence -Wmaybe-uninitialized when calling __kcsan_check_access())
+$ git merge -m Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/melver/linux.git kcsan/next
+Already up to date.
+Merging crc/crc-next (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'crc-next' of https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git crc/crc-next
+Already up to date.
+Merging keys-next/keys-next (965e9a2cf23b0 pkcs7: Change a pr_warn() to pr_warn_once())
+$ git merge -m Merge branch 'keys-next' of https://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs.git keys-next/keys-next
+Already up to date.
+Merging fwctl/for-next (dc59e4fea9d83 Linux 7.2-rc1)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/fwctl/fwctl.git fwctl/for-next
+Already up to date.
+Merging devsec-tsm/next (3177779ae17db virt: coco: change tsm_class to a const struct)
+$ git merge -m Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/devsec/tsm.git devsec-tsm/next
+Already up to date.
+Merging hisilicon/for-next (a5db65458a911 Merge branch 'next/dt64' into for-next)
+$ git merge -m Merge branch 'for-next' of https://github.com/hisilicon/linux-hisi.git hisilicon/for-next
+Merge made by the 'ort' strategy.
+ arch/arm64/boot/dts/hisilicon/hi3798cv200.dtsi | 4 ----
+ arch/arm64/boot/dts/hisilicon/hip05.dtsi | 14 +++++++-------
+ 2 files changed, 7 insertions(+), 11 deletions(-)
+Merging device-id/device-id-rework (995832b2cebe6 Replace <linux/mod_devicetable.h> by more specific <linux/device-id/*.h> (c files))
+$ git merge -m Merge branch 'device-id-rework' of https://git.kernel.org/pub/scm/linux/kernel/git/ukleinek/linux.git device-id/device-id-rework
+Already up to date.
+Merging kthread/for-next (fa39ec4f89f26 doc: Add housekeeping documentation)
+$ git merge -m Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/frederic/linux-dynticks.git kthread/for-next
+Already up to date.
diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile
index 32a44b02d2fa..4ffc03122784 100644
--- a/arch/arm/boot/dts/qcom/Makefile
+++ b/arch/arm/boot/dts/qcom/Makefile
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
dtb-$(CONFIG_ARCH_QCOM) += \
msm8226-motorola-falcon.dtb \
+ msm8226-motorola-titan.dtb \
qcom-apq8016-sbc.dtb \
qcom-apq8026-asus-sparrow.dtb \
qcom-apq8026-huawei-sturgeon.dtb \
diff --git a/arch/arm/boot/dts/qcom/msm8226-motorola-titan.dts b/arch/arm/boot/dts/qcom/msm8226-motorola-titan.dts
new file mode 100644
index 000000000000..1609fb21c544
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msm8226-motorola-titan.dts
@@ -0,0 +1,350 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2026, David Wales <daviewales@disroot.org>
+ */
+
+/dts-v1/;
+
+#include "qcom-msm8226.dtsi"
+#include "pm8226.dtsi"
+
+/delete-node/ &smem_region;
+
+/ {
+ model = "Motorola Moto G2 (2014)";
+ compatible = "motorola,titan", "qcom,msm8226";
+ chassis-type = "handset";
+
+ aliases {
+ mmc0 = &sdhc_1; /* eMMC */
+ };
+
+ chosen {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ framebuffer@3200000 {
+ compatible = "simple-framebuffer";
+ reg = <0x03200000 0x800000>;
+ width = <720>;
+ height = <1280>;
+ stride = <(720 * 3)>;
+ format = "r8g8b8";
+ vsp-supply = <&reg_lcd_pos>;
+ vsn-supply = <&reg_lcd_neg>;
+ vddio-supply = <&vddio_disp_vreg>;
+
+ clocks = <&mmcc MDSS_AHB_CLK>,
+ <&mmcc MDSS_AXI_CLK>,
+ <&mmcc MDSS_BYTE0_CLK>,
+ <&mmcc MDSS_ESC0_CLK>,
+ <&mmcc MDSS_MDP_CLK>,
+ <&mmcc MMSS_MISC_AHB_CLK>,
+ <&mmcc MDSS_PCLK0_CLK>,
+ <&mmcc MDSS_VSYNC_CLK>;
+ power-domains = <&mmcc MDSS_GDSC>;
+ };
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+
+ event-hall-sensor {
+ label = "Hall Effect Sensor";
+ gpios = <&tlmm 109 GPIO_ACTIVE_LOW>;
+ linux,input-type = <EV_SW>;
+ linux,code = <SW_LID>;
+ linux,can-disable;
+ };
+
+ key-volume-down {
+ label = "Volume Down";
+ gpios = <&tlmm 107 GPIO_ACTIVE_LOW>;
+ linux,code = <KEY_VOLUMEDOWN>;
+ debounce-interval = <15>;
+ };
+
+ key-volume-up {
+ label = "Volume Up";
+ gpios = <&tlmm 106 GPIO_ACTIVE_LOW>;
+ linux,code = <KEY_VOLUMEUP>;
+ debounce-interval = <15>;
+ };
+ };
+
+ vddio_disp_vreg: regulator-vddio-disp {
+ compatible = "regulator-fixed";
+ regulator-name = "vddio_disp";
+
+ gpio = <&tlmm 10 GPIO_ACTIVE_HIGH>;
+ startup-delay-us = <300>;
+ enable-active-high;
+ regulator-boot-on;
+ };
+
+ reserved-memory {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ framebuffer@3200000 {
+ reg = <0x03200000 0xfa0000>;
+ no-map;
+ };
+
+ dhob@f500000 {
+ reg = <0x0f500000 0x40000>;
+ no-map;
+ };
+
+ shob@f540000 {
+ reg = <0x0f540000 0x2000>;
+ no-map;
+ };
+
+ smem_region: smem@fa00000 {
+ reg = <0x0fa00000 0x100000>;
+ no-map;
+ };
+
+ reserved@fb00000 {
+ reg = <0x0fb00000 0x400000>;
+ no-map;
+ };
+ };
+};
+
+&blsp1_i2c4 {
+ status = "okay";
+
+ regulator@3e {
+ compatible = "ti,tps65132";
+ reg = <0x3e>;
+
+ pinctrl-0 = <&reg_lcd_default>;
+ pinctrl-names = "default";
+
+ reg_lcd_pos: outp {
+ regulator-name = "outp";
+ regulator-min-microvolt = <5400000>;
+ regulator-max-microvolt = <5600000>;
+ regulator-active-discharge = <1>;
+ regulator-boot-on;
+ enable-gpios = <&tlmm 12 GPIO_ACTIVE_HIGH>;
+ };
+
+ reg_lcd_neg: outn {
+ regulator-name = "outn";
+ regulator-min-microvolt = <5400000>;
+ regulator-max-microvolt = <5600000>;
+ regulator-active-discharge = <1>;
+ regulator-boot-on;
+ enable-gpios = <&tlmm 13 GPIO_ACTIVE_HIGH>;
+ };
+ };
+};
+
+&pm8226_vib {
+ status = "okay";
+};
+
+&rpm_requests {
+ regulators {
+ compatible = "qcom,rpm-pm8226-regulators";
+
+ pm8226_s3: s3 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1300000>;
+ };
+
+ pm8226_s4: s4 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2200000>;
+ };
+
+ pm8226_s5: s5 {
+ regulator-min-microvolt = <1150000>;
+ regulator-max-microvolt = <1150000>;
+ };
+
+ pm8226_l1: l1 {
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ };
+
+ pm8226_l2: l2 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ pm8226_l3: l3 {
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <1337500>;
+ };
+
+ pm8226_l4: l4 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ pm8226_l5: l5 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ pm8226_l6: l6 {
+ /* Hall effect sensor */
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ pm8226_l7: l7 {
+ regulator-min-microvolt = <1850000>;
+ regulator-max-microvolt = <1850000>;
+ };
+
+ pm8226_l8: l8 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ pm8226_l9: l9 {
+ regulator-min-microvolt = <2050000>;
+ regulator-max-microvolt = <2050000>;
+ };
+
+ pm8226_l10: l10 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ pm8226_l12: l12 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ pm8226_l14: l14 {
+ regulator-min-microvolt = <2750000>;
+ regulator-max-microvolt = <2750000>;
+ };
+
+ pm8226_l15: l15 {
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ };
+
+ pm8226_l16: l16 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3350000>;
+ };
+
+ pm8226_l17: l17 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ };
+
+ pm8226_l18: l18 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ };
+
+ pm8226_l19: l19 {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ };
+
+ pm8226_l20: l20 {
+ regulator-min-microvolt = <3075000>;
+ regulator-max-microvolt = <3075000>;
+ };
+
+ pm8226_l21: l21 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ regulator-allow-set-load;
+ };
+
+ pm8226_l22: l22 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ };
+
+ pm8226_l23: l23 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ };
+
+ pm8226_l24: l24 {
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1350000>;
+ };
+
+ pm8226_l25: l25 {
+ regulator-min-microvolt = <1775000>;
+ regulator-max-microvolt = <2125000>;
+ };
+
+ pm8226_l26: l26 {
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ };
+
+ pm8226_l27: l27 {
+ regulator-min-microvolt = <2050000>;
+ regulator-max-microvolt = <2050000>;
+ };
+
+ pm8226_l28: l28 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3400000>;
+ regulator-boot-on;
+ };
+
+ pm8226_lvs1: lvs1 {
+ /* Pull-up for I2C lines */
+ regulator-always-on;
+ };
+ };
+};
+
+&sdhc_1 {
+ vmmc-supply = <&pm8226_l17>;
+ vqmmc-supply = <&pm8226_l6>;
+ bus-width = <8>;
+ non-removable;
+
+ status = "okay";
+};
+
+&smbb {
+ qcom,fast-charge-safe-current = <2000000>;
+ qcom,fast-charge-current-limit = <1900000>;
+ qcom,fast-charge-safe-voltage = <4400000>;
+ qcom,minimum-input-voltage = <4300000>;
+
+ status = "okay";
+};
+
+&usb {
+ extcon = <&smbb>;
+ dr_mode = "peripheral";
+
+ status = "okay";
+};
+
+&usb_hs_phy {
+ extcon = <&smbb>;
+ v1p8-supply = <&pm8226_l10>;
+ v3p3-supply = <&pm8226_l20>;
+};
+
+&tlmm {
+ reg_lcd_default: reg-lcd-default-state {
+ pins = "gpio12", "gpio13";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/qcom-apq8064-pins.dtsi b/arch/arm/boot/dts/qcom/qcom-apq8064-pins.dtsi
index e53de709e9d1..e95da761234b 100644
--- a/arch/arm/boot/dts/qcom/qcom-apq8064-pins.dtsi
+++ b/arch/arm/boot/dts/qcom/qcom-apq8064-pins.dtsi
@@ -87,7 +87,7 @@
function = "gsbi7";
};
- gsbi7_uart_4pins: gsbi7_uart_4pins-state {
+ gsbi7_uart_4pins: gsbi7-uart-4pins-state {
pins = "gpio82", "gpio83", "gpio84", "gpio85";
function = "gsbi7";
};
diff --git a/arch/arm/boot/dts/qcom/qcom-ipq8064.dtsi b/arch/arm/boot/dts/qcom/qcom-ipq8064.dtsi
index adedcc6da1da..1a278503d340 100644
--- a/arch/arm/boot/dts/qcom/qcom-ipq8064.dtsi
+++ b/arch/arm/boot/dts/qcom/qcom-ipq8064.dtsi
@@ -591,7 +591,7 @@
nss_common: syscon@3000000 {
compatible = "syscon";
- reg = <0x03000000 0x0000FFFF>;
+ reg = <0x03000000 0x0000ffff>;
};
usb3_0: usb@100f8800 {
@@ -1241,7 +1241,7 @@
qsgmii_csr: syscon@1bb00000 {
compatible = "syscon";
- reg = <0x1bb00000 0x000001FF>;
+ reg = <0x1bb00000 0x000001ff>;
};
lcc: clock-controller@28000000 {
diff --git a/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548.dtsi b/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548.dtsi
index 0dd52cac0e2e..7206a33da279 100644
--- a/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548.dtsi
+++ b/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548.dtsi
@@ -15,7 +15,7 @@
memory@48000000 {
device_type = "memory";
- reg = <0x48000000 0x7F00000>;
+ reg = <0x48000000 0x7f00000>;
};
};
diff --git a/arch/arm/boot/dts/qcom/qcom-msm8960-samsung-expressatt.dts b/arch/arm/boot/dts/qcom/qcom-msm8960-samsung-expressatt.dts
index 5a39abd6f3ce..5a3d88e31cf5 100644
--- a/arch/arm/boot/dts/qcom/qcom-msm8960-samsung-expressatt.dts
+++ b/arch/arm/boot/dts/qcom/qcom-msm8960-samsung-expressatt.dts
@@ -52,6 +52,40 @@
linux,code = <KEY_VOLUMEDOWN>;
};
};
+
+ touchkey_enable: touchkey-enable {
+ compatible = "regulator-fixed";
+ regulator-name = "touchkey_enable";
+ gpio = <&tlmm 51 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ regulator-boot-on;
+ };
+
+ i2c-gpio-touchkey {
+ compatible = "i2c-gpio";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ sda-gpios = <&tlmm 71 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ scl-gpios = <&tlmm 72 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ pinctrl-0 = <&touchkey_i2c_pins>;
+ pinctrl-names = "default";
+ i2c-gpio,delay-us = <2>;
+
+ touchkey@20 {
+ compatible = "coreriver,tc360-touchkey";
+ reg = <0x20>;
+
+ interrupts-extended = <&tlmm 52 IRQ_TYPE_EDGE_FALLING>;
+ pinctrl-0 = <&touchkey_irq_pin>;
+ pinctrl-names = "default";
+
+ vddio-supply = <&touchkey_enable>;
+ vdd-supply = <&pm8921_l29>;
+ vcc-supply = <&pm8921_l29>;
+
+ linux,keycodes = <KEY_MENU KEY_BACK>;
+ };
+ };
};
&gsbi2 {
@@ -198,6 +232,20 @@
bias-disable;
};
};
+
+ touchkey_i2c_pins: touchkey-i2c-state {
+ pins = "gpio71", "gpio72";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ touchkey_irq_pin: touchkey-irq-state {
+ pins = "gpio52";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
};
&pm8921 {
@@ -420,6 +468,12 @@
bias-pull-down;
};
+ pm8921_l29: l29 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ bias-pull-down;
+ };
+
/* Low Voltage Switch */
pm8921_lvs1: lvs1 {
bias-pull-down;
diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi
index 95be1d2e214f..06c0af0aa317 100644
--- a/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi
+++ b/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi
@@ -1866,7 +1866,7 @@
};
};
- spi8_default: spi8_default-state {
+ spi8_default: spi8-default-state {
mosi-pins {
pins = "gpio45";
function = "blsp_spi8";
diff --git a/arch/arm/boot/dts/qcom/qcom-sdx65-mtp.dts b/arch/arm/boot/dts/qcom/qcom-sdx65-mtp.dts
index 07c10c84eefa..2c0590617ac4 100644
--- a/arch/arm/boot/dts/qcom/qcom-sdx65-mtp.dts
+++ b/arch/arm/boot/dts/qcom/qcom-sdx65-mtp.dts
@@ -55,7 +55,7 @@
regulator-max-microvolt = <3700000>;
};
- vreg_bob_3p3: pmx65_bob {
+ vreg_bob_3p3: pmx65-bob-regulator {
compatible = "regulator-fixed";
regulator-name = "vreg_bob_3p3";
regulator-min-microvolt = <3300000>;
diff --git a/arch/arm/mach-ux500/cpu-db8500.c b/arch/arm/mach-ux500/cpu-db8500.c
index b1a70f203372..0d7530fb6ad0 100644
--- a/arch/arm/mach-ux500/cpu-db8500.c
+++ b/arch/arm/mach-ux500/cpu-db8500.c
@@ -12,7 +12,7 @@
#include <linux/irq.h>
#include <linux/irqchip.h>
#include <linux/irqchip/arm-gic.h>
-#include <linux/mfd/dbx500-prcmu.h>
+#include <linux/mfd/db8500-prcmu.h>
#include <linux/platform_data/arm-ux500-pm.h>
#include <linux/platform_device.h>
#include <linux/io.h>
@@ -81,7 +81,7 @@ static void __init ux500_init_irq(void)
struct resource r;
irqchip_init();
- prcmu_early_init();
+ db8500_prcmu_early_init();
np = of_find_compatible_node(NULL, NULL, "stericsson,db8500-prcmu");
of_address_to_resource(np, 0, &r);
of_node_put(np);
@@ -101,7 +101,7 @@ static void ux500_restart(enum reboot_mode mode, const char *cmd)
local_irq_disable();
local_fiq_disable();
- prcmu_system_reset(0);
+ db8500_prcmu_system_reset(0);
}
static const struct of_device_id u8500_local_bus_nodes[] = {
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index e136e5abdb33..11a9c534b7b4 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -78,6 +78,7 @@ config ARM64
select ARCH_SUPPORTS_CFI
select ARCH_SUPPORTS_ATOMIC_RMW
select ARCH_SUPPORTS_INT128 if CC_HAS_INT128
+ select ARCH_HAS_PTE_PROTNONE
select ARCH_SUPPORTS_NUMA_BALANCING
select ARCH_SUPPORTS_PAGE_TABLE_CHECK
select ARCH_SUPPORTS_PER_VMA_LOCK
diff --git a/arch/arm64/boot/dts/mediatek/mt6795.dtsi b/arch/arm64/boot/dts/mediatek/mt6795.dtsi
index 134cfa77e3b1..6dd706b27830 100644
--- a/arch/arm64/boot/dts/mediatek/mt6795.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt6795.dtsi
@@ -547,8 +547,7 @@
};
apdma: dma-controller@11000380 {
- compatible = "mediatek,mt6795-uart-dma",
- "mediatek,mt6577-uart-dma";
+ compatible = "mediatek,mt6795-uart-dma";
reg = <0 0x11000380 0 0x60>,
<0 0x11000400 0 0x60>,
<0 0x11000480 0 0x60>,
@@ -568,7 +567,6 @@
dma-requests = <8>;
clocks = <&pericfg CLK_PERI_AP_DMA>;
clock-names = "apdma";
- mediatek,dma-33bits;
#dma-cells = <1>;
};
diff --git a/arch/arm64/boot/dts/mediatek/mt8183.dtsi b/arch/arm64/boot/dts/mediatek/mt8183.dtsi
index 95cc06799533..8b0992548431 100644
--- a/arch/arm64/boot/dts/mediatek/mt8183.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8183.dtsi
@@ -1071,6 +1071,22 @@
clock-names = "gce";
};
+ apdma: dma-controller@11000780 {
+ compatible = "mediatek,mt8183-uart-dma", "mediatek,mt6577-uart-dma";
+ reg = <0 0x11000780 0 0x80>, <0 0x11000800 0 0x80>,
+ <0 0x11000880 0 0x80>, <0 0x11000900 0 0x80>,
+ <0 0x11000980 0 0x80>, <0 0x11000a00 0 0x80>;
+ interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 109 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 110 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 111 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 112 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 113 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&infracfg CLK_INFRA_AP_DMA>;
+ #dma-cells = <1>;
+ dma-requests = <6>;
+ };
+
auxadc: auxadc@11001000 {
compatible = "mediatek,mt8183-auxadc",
"mediatek,mt8173-auxadc";
@@ -1088,6 +1104,8 @@
interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_LOW>;
clocks = <&clk26m>, <&infracfg CLK_INFRA_UART0>;
clock-names = "baud", "bus";
+ dmas = <&apdma 0>, <&apdma 1>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -1098,6 +1116,8 @@
interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_LOW>;
clocks = <&clk26m>, <&infracfg CLK_INFRA_UART1>;
clock-names = "baud", "bus";
+ dmas = <&apdma 2>, <&apdma 3>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -1108,6 +1128,8 @@
interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_LOW>;
clocks = <&clk26m>, <&infracfg CLK_INFRA_UART2>;
clock-names = "baud", "bus";
+ dmas = <&apdma 4>, <&apdma 5>;
+ dma-names = "tx", "rx";
status = "disabled";
};
diff --git a/arch/arm64/boot/dts/mediatek/mt8186.dtsi b/arch/arm64/boot/dts/mediatek/mt8186.dtsi
index fded6345d422..621408439ffa 100644
--- a/arch/arm64/boot/dts/mediatek/mt8186.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8186.dtsi
@@ -1142,6 +1142,22 @@
clocks = <&clk13m>;
};
+ apdma: dma-controller@10200d80 {
+ compatible = "mediatek,mt8186-uart-dma", "mediatek,mt6835-uart-dma";
+ reg = <0 0x10200d80 0 0x80>, <0 0x10200e00 0 0x80>,
+ <0 0x10200e80 0 0x80>, <0 0x10200f00 0 0x80>,
+ <0 0x10200f80 0 0x80>, <0 0x10201000 0 0x80>;
+ interrupts = <GIC_SPI 376 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 377 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 378 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 379 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 380 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 381 IRQ_TYPE_LEVEL_HIGH 0>;
+ clocks = <&infracfg_ao CLK_INFRA_AO_AP_DMA>;
+ #dma-cells = <1>;
+ dma-requests = <6>;
+ };
+
gce: mailbox@1022c000 {
compatible = "mediatek,mt8186-gce";
reg = <0 0X1022c000 0 0x4000>;
@@ -1218,6 +1234,8 @@
interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&clk26m>, <&infracfg_ao CLK_INFRA_AO_UART0>;
clock-names = "baud", "bus";
+ dmas = <&apdma 0>, <&apdma 1>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -1228,6 +1246,8 @@
interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&clk26m>, <&infracfg_ao CLK_INFRA_AO_UART1>;
clock-names = "baud", "bus";
+ dmas = <&apdma 2>, <&apdma 3>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -1482,6 +1502,8 @@
interrupts = <GIC_SPI 246 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&clk26m>, <&infracfg_ao CLK_INFRA_AO_UART2>;
clock-names = "baud", "bus";
+ dmas = <&apdma 4>, <&apdma 5>;
+ dma-names = "tx", "rx";
status = "disabled";
};
diff --git a/arch/arm64/boot/dts/mediatek/mt8188.dtsi b/arch/arm64/boot/dts/mediatek/mt8188.dtsi
index 75133794cec3..14a320f0c70c 100644
--- a/arch/arm64/boot/dts/mediatek/mt8188.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8188.dtsi
@@ -1360,6 +1360,31 @@
clock-names = "pmif_sys_ck", "pmif_tmr_ck", "spmimst_clk_mux";
};
+ apdma: dma-controller@10220880 {
+ compatible = "mediatek,mt8188-uart-dma", "mediatek,mt6835-uart-dma";
+ reg = <0 0x10220880 0 0x80>, <0 0x10220900 0 0x80>,
+ <0 0x10220980 0 0x80>, <0 0x10220a00 0 0x80>,
+ <0 0x10220a80 0 0x80>, <0 0x10220b00 0 0x80>,
+ <0 0x10220b80 0 0x80>, <0 0x10220c00 0 0x80>,
+ <0 0x10220c80 0 0x80>, <0 0x10220d00 0 0x80>,
+ <0 0x10220d80 0 0x80>, <0 0x10220e00 0 0x80>;
+ interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 175 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 177 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 178 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 179 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 180 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 181 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 182 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 183 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 185 IRQ_TYPE_LEVEL_HIGH 0>;
+ clocks = <&infracfg_ao CLK_INFRA_AO_APDMA_BCLK>;
+ #dma-cells = <1>;
+ dma-requests = <12>;
+ };
+
infra_iommu: iommu@10315000 {
compatible = "mediatek,mt8188-iommu-infra";
reg = <0 0x10315000 0 0x1000>;
@@ -1512,6 +1537,8 @@
interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&clk26m>, <&infracfg_ao CLK_INFRA_AO_UART0>;
clock-names = "baud", "bus";
+ dmas = <&apdma 0>, <&apdma 1>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -1521,6 +1548,8 @@
interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&clk26m>, <&infracfg_ao CLK_INFRA_AO_UART1>;
clock-names = "baud", "bus";
+ dmas = <&apdma 2>, <&apdma 3>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -1530,6 +1559,8 @@
interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&clk26m>, <&infracfg_ao CLK_INFRA_AO_UART2>;
clock-names = "baud", "bus";
+ dmas = <&apdma 4>, <&apdma 5>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -1539,6 +1570,8 @@
interrupts = <GIC_SPI 723 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&clk26m>, <&infracfg_ao CLK_INFRA_AO_UART3>;
clock-names = "baud", "bus";
+ dmas = <&apdma 6>, <&apdma 7>;
+ dma-names = "tx", "rx";
status = "disabled";
};
diff --git a/arch/arm64/boot/dts/mediatek/mt8192.dtsi b/arch/arm64/boot/dts/mediatek/mt8192.dtsi
index 9f8f115edd4c..898953acdb61 100644
--- a/arch/arm64/boot/dts/mediatek/mt8192.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8192.dtsi
@@ -741,6 +741,19 @@
assigned-clock-parents = <&topckgen CLK_TOP_OSC_D10>;
};
+ apdma: dma-controller@10217a80 {
+ compatible = "mediatek,mt8192-uart-dma", "mediatek,mt6835-uart-dma";
+ reg = <0 0x10217a80 0 0x80>, <0 0x10217b00 0 0x80>,
+ <0 0x10217b80 0 0x80>, <0 0x10217c00 0 0x80>;
+ interrupts = <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH 0>;
+ clocks = <&infracfg CLK_INFRA_AP_DMA>;
+ #dma-cells = <1>;
+ dma-requests = <4>;
+ };
+
gce: mailbox@10228000 {
compatible = "mediatek,mt8192-gce";
reg = <0 0x10228000 0 0x4000>;
@@ -765,6 +778,8 @@
interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&clk26m>, <&infracfg CLK_INFRA_UART0>;
clock-names = "baud", "bus";
+ dmas = <&apdma 0>, <&apdma 1>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -775,6 +790,8 @@
interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&clk26m>, <&infracfg CLK_INFRA_UART1>;
clock-names = "baud", "bus";
+ dmas = <&apdma 2>, <&apdma 3>;
+ dma-names = "tx", "rx";
status = "disabled";
};
diff --git a/arch/arm64/boot/dts/mediatek/mt8195.dtsi b/arch/arm64/boot/dts/mediatek/mt8195.dtsi
index c72e34c57629..9aaf8b6edcb5 100644
--- a/arch/arm64/boot/dts/mediatek/mt8195.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8195.dtsi
@@ -904,6 +904,31 @@
assigned-clock-parents = <&topckgen CLK_TOP_ULPOSC1_D10>;
};
+ apdma: dma-controller@10220880 {
+ compatible = "mediatek,mt8195-uart-dma", "mediatek,mt6835-uart-dma";
+ reg = <0 0x10220880 0 0x80>, <0 0x10220900 0 0x80>,
+ <0 0x10220980 0 0x80>, <0 0x10220a00 0 0x80>,
+ <0 0x10220a80 0 0x80>, <0 0x10220b00 0 0x80>,
+ <0 0x10220b80 0 0x80>, <0 0x10220c00 0 0x80>,
+ <0 0x10220c80 0 0x80>, <0 0x10220d00 0 0x80>,
+ <0 0x10220d80 0 0x80>, <0 0x10220e00 0 0x80>;
+ interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 175 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 177 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 178 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 179 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 180 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 181 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 182 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 183 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 185 IRQ_TYPE_LEVEL_HIGH 0>;
+ clocks = <&infracfg_ao CLK_INFRA_AO_APDMA_B>;
+ #dma-cells = <1>;
+ dma-requests = <12>;
+ };
+
iommu_infra: infra-iommu@10315000 {
compatible = "mediatek,mt8195-iommu-infra";
reg = <0 0x10315000 0 0x5000>;
@@ -1040,6 +1065,8 @@
interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&clk26m>, <&infracfg_ao CLK_INFRA_AO_UART0>;
clock-names = "baud", "bus";
+ dmas = <&apdma 0>, <&apdma 1>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -1050,6 +1077,8 @@
interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&clk26m>, <&infracfg_ao CLK_INFRA_AO_UART1>;
clock-names = "baud", "bus";
+ dmas = <&apdma 2>, <&apdma 3>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -1060,6 +1089,8 @@
interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&clk26m>, <&infracfg_ao CLK_INFRA_AO_UART2>;
clock-names = "baud", "bus";
+ dmas = <&apdma 4>, <&apdma 5>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -1070,6 +1101,8 @@
interrupts = <GIC_SPI 723 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&clk26m>, <&infracfg_ao CLK_INFRA_AO_UART3>;
clock-names = "baud", "bus";
+ dmas = <&apdma 6>, <&apdma 7>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -1080,6 +1113,8 @@
interrupts = <GIC_SPI 724 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&clk26m>, <&infracfg_ao CLK_INFRA_AO_UART4>;
clock-names = "baud", "bus";
+ dmas = <&apdma 8>, <&apdma 9>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -1090,6 +1125,8 @@
interrupts = <GIC_SPI 725 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&clk26m>, <&infracfg_ao CLK_INFRA_AO_UART5>;
clock-names = "baud", "bus";
+ dmas = <&apdma 10>, <&apdma 11>;
+ dma-names = "tx", "rx";
status = "disabled";
};
diff --git a/arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtsi b/arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtsi
index 9f5a0ec563e8..8256279c5629 100644
--- a/arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8390-tungsten-smarc.dtsi
@@ -265,8 +265,6 @@
};
&disp_dsi0 {
- #address-cells = <1>;
- #size-cells = <0>;
status = "okay";
ports {
@@ -1049,8 +1047,6 @@
ethernet@1 {
compatible = "usb424,7850";
reg = <1>;
- #address-cells = <1>;
- #size-cells = <0>;
mdio {
#address-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index 5a1c56cf98f6..33e9199511aa 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -14,6 +14,7 @@ dtb-$(CONFIG_ARCH_QCOM) += apq8094-sony-xperia-kitakami-karin_windy.dtb
dtb-$(CONFIG_ARCH_QCOM) += apq8096-db820c.dtb
dtb-$(CONFIG_ARCH_QCOM) += apq8096sg-db820c.dtb
dtb-$(CONFIG_ARCH_QCOM) += apq8096-ifc6640.dtb
+dtb-$(CONFIG_ARCH_QCOM) += eliza-cqs-evk.dtb
dtb-$(CONFIG_ARCH_QCOM) += eliza-mtp.dtb
dtb-$(CONFIG_ARCH_QCOM) += glymur-crd.dtb
dtb-$(CONFIG_ARCH_QCOM) += hamoa-iot-evk.dtb
@@ -333,6 +334,9 @@ dtb-$(CONFIG_ARCH_QCOM) += sdm850-huawei-matebook-e-2019.dtb
dtb-$(CONFIG_ARCH_QCOM) += sdm850-lenovo-yoga-c630.dtb
dtb-$(CONFIG_ARCH_QCOM) += sdm850-samsung-w737.dtb
dtb-$(CONFIG_ARCH_QCOM) += sdx75-idp.dtb
+dtb-$(CONFIG_ARCH_QCOM) += shikra-cqm-evk.dtb
+dtb-$(CONFIG_ARCH_QCOM) += shikra-cqs-evk.dtb
+dtb-$(CONFIG_ARCH_QCOM) += shikra-iqs-evk.dtb
dtb-$(CONFIG_ARCH_QCOM) += sm4250-oneplus-billie2.dtb
dtb-$(CONFIG_ARCH_QCOM) += sm4450-qrd.dtb
dtb-$(CONFIG_ARCH_QCOM) += sm6115-fxtec-pro1x.dtb
@@ -350,6 +354,7 @@ dtb-$(CONFIG_ARCH_QCOM) += sm7325-motorola-dubai.dtb
dtb-$(CONFIG_ARCH_QCOM) += sm7325-motorola-dubai-csot.dtb
dtb-$(CONFIG_ARCH_QCOM) += sm7325-motorola-dubai-tianma.dtb
dtb-$(CONFIG_ARCH_QCOM) += sm7325-nothing-spacewar.dtb
+dtb-$(CONFIG_ARCH_QCOM) += sm7325-xiaomi-taoyao.dtb
dtb-$(CONFIG_ARCH_QCOM) += sm8150-hdk.dtb
dtb-$(CONFIG_ARCH_QCOM) += sm8150-microsoft-surface-duo.dtb
dtb-$(CONFIG_ARCH_QCOM) += sm8150-mtp.dtb
@@ -436,6 +441,8 @@ x1e80100-hp-elitebook-ultra-g1q-el2-dtbs := x1e80100-hp-elitebook-ultra-g1q.dtb
dtb-$(CONFIG_ARCH_QCOM) += x1e80100-hp-elitebook-ultra-g1q.dtb x1e80100-hp-elitebook-ultra-g1q-el2.dtb
x1e80100-hp-omnibook-x14-el2-dtbs := x1e80100-hp-omnibook-x14.dtb x1-el2.dtbo
dtb-$(CONFIG_ARCH_QCOM) += x1e80100-hp-omnibook-x14.dtb x1e80100-hp-omnibook-x14-el2.dtb
+x1e80100-honor-magicbook-art-14-el2-dtbs := x1e80100-honor-magicbook-art-14.dtb x1-el2.dtbo
+dtb-$(CONFIG_ARCH_QCOM) += x1e80100-honor-magicbook-art-14.dtb x1e80100-honor-magicbook-art-14-el2.dtb
x1e80100-lenovo-yoga-slim7x-el2-dtbs := x1e80100-lenovo-yoga-slim7x.dtb x1-el2.dtbo
dtb-$(CONFIG_ARCH_QCOM) += x1e80100-lenovo-yoga-slim7x.dtb x1e80100-lenovo-yoga-slim7x-el2.dtb
x1e80100-medion-sprchrgd-14-s1-el2-dtbs := x1e80100-medion-sprchrgd-14-s1.dtb x1-el2.dtbo
@@ -462,3 +469,5 @@ x1p42100-lenovo-thinkbook-16-el2-dtbs := x1p42100-lenovo-thinkbook-16.dtb x1-el2
dtb-$(CONFIG_ARCH_QCOM) += x1p42100-lenovo-thinkbook-16.dtb x1p42100-lenovo-thinkbook-16-el2.dtb
x1p64100-microsoft-denali-el2-dtbs := x1p64100-microsoft-denali.dtb x1-el2.dtbo
dtb-$(CONFIG_ARCH_QCOM) += x1p64100-microsoft-denali.dtb x1p64100-microsoft-denali-el2.dtb
+x1p42100-microsoft-sp12in-el2-dtbs := x1p42100-microsoft-sp12in.dtb x1-el2.dtbo
+dtb-$(CONFIG_ARCH_QCOM) += x1p42100-microsoft-sp12in.dtb x1p42100-microsoft-sp12in-el2.dtb
diff --git a/arch/arm64/boot/dts/qcom/apq8016-sbc-usb-host.dtso b/arch/arm64/boot/dts/qcom/apq8016-sbc-usb-host.dtso
index a82c26b7eae8..9872d5cb83bd 100644
--- a/arch/arm64/boot/dts/qcom/apq8016-sbc-usb-host.dtso
+++ b/arch/arm64/boot/dts/qcom/apq8016-sbc-usb-host.dtso
@@ -4,5 +4,5 @@
/plugin/;
&usb {
- dr_mode = "host";
+ dr_mode = "host";
};
diff --git a/arch/arm64/boot/dts/qcom/eliza-cqs-evk.dts b/arch/arm64/boot/dts/qcom/eliza-cqs-evk.dts
new file mode 100644
index 000000000000..43d428a4ed2d
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/eliza-cqs-evk.dts
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+/dts-v1/;
+
+#include "eliza-cqs-som.dtsi"
+#include "eliza-evk.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. Eliza CQS EVK";
+ compatible = "qcom,eliza-cqs-evk", "qcom,eliza-cqs-som", "qcom,eliza";
+};
diff --git a/arch/arm64/boot/dts/qcom/eliza-cqs-som.dtsi b/arch/arm64/boot/dts/qcom/eliza-cqs-som.dtsi
new file mode 100644
index 000000000000..318ae3c22351
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/eliza-cqs-som.dtsi
@@ -0,0 +1,399 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
+#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+
+#include "eliza.dtsi"
+#include "pm7550ba-eliza.dtsi"
+#include "pm7550-eliza.dtsi"
+#include "pm8550vs-d-eliza.dtsi"
+#include "pm8550vs-g-eliza.dtsi"
+#include "pmr735d-eliza.dtsi"
+#include "pmk8550-eliza.dtsi"
+
+/ {
+ clocks {
+ xo_board: xo-board {
+ compatible = "fixed-clock";
+ clock-frequency = <76800000>;
+ #clock-cells = <0>;
+ };
+
+ sleep_clk: sleep-clk {
+ compatible = "fixed-clock";
+ clock-frequency = <32764>;
+ #clock-cells = <0>;
+ };
+
+ bi_tcxo_div2: bi-tcxo-div2-clk {
+ compatible = "fixed-factor-clock";
+ #clock-cells = <0>;
+
+ clocks = <&rpmhcc RPMH_CXO_CLK>;
+ clock-mult = <1>;
+ clock-div = <2>;
+ };
+
+ bi_tcxo_ao_div2: bi-tcxo-ao-div2-clk {
+ compatible = "fixed-factor-clock";
+ #clock-cells = <0>;
+
+ clocks = <&rpmhcc RPMH_CXO_CLK_A>;
+ clock-mult = <1>;
+ clock-div = <2>;
+ };
+ };
+
+ vph_pwr: regulator-vph-pwr {
+ compatible = "regulator-fixed";
+
+ regulator-name = "vph_pwr";
+ regulator-min-microvolt = <3700000>;
+ regulator-max-microvolt = <3700000>;
+
+ regulator-always-on;
+ regulator-boot-on;
+ };
+};
+
+&apps_rsc {
+ regulators-0 {
+ compatible = "qcom,pm7550-rpmh-regulators";
+
+ vdd-l1-supply = <&vreg_s3b>;
+ vdd-l2-l3-supply = <&vreg_s3b>;
+ vdd-l4-l5-supply = <&vreg_s2b>;
+ vdd-l6-supply = <&vreg_s2b>;
+ vdd-l7-supply = <&vreg_s1b>;
+ vdd-l8-supply = <&vreg_s1b>;
+ vdd-l9-l10-supply = <&vreg_s1b>;
+ vdd-l11-supply = <&vreg_s1b>;
+ vdd-l12-l14-supply = <&vreg_bob>;
+ vdd-l13-l16-supply = <&vreg_bob>;
+ vdd-l15-l17-l18-l19-l20-l21-l22-l23-supply = <&vreg_bob>;
+ vdd-s1-supply = <&vph_pwr>;
+ vdd-s2-supply = <&vph_pwr>;
+ vdd-s3-supply = <&vph_pwr>;
+ vdd-s4-supply = <&vph_pwr>;
+ vdd-s5-supply = <&vph_pwr>;
+ vdd-s6-supply = <&vph_pwr>;
+
+ vdd-bob-supply = <&vph_pwr>;
+
+ qcom,pmic-id = "b";
+
+ vreg_s1b: smps1 {
+ regulator-name = "vreg_s1b";
+ regulator-min-microvolt = <1850000>;
+ regulator-max-microvolt = <2040000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_s2b: smps2 {
+ regulator-name = "vreg_s2b";
+ regulator-min-microvolt = <375000>;
+ regulator-max-microvolt = <2744000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_s3b: smps3 {
+ regulator-name = "vreg_s3b";
+ regulator-min-microvolt = <375000>;
+ regulator-max-microvolt = <2744000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_s4b: smps4 {
+ regulator-name = "vreg_s4b";
+ regulator-min-microvolt = <2156000>;
+ regulator-max-microvolt = <2400000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l2b: ldo2 {
+ regulator-name = "vreg_l2b";
+ regulator-min-microvolt = <720000>;
+ regulator-max-microvolt = <950000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l3b: ldo3 {
+ regulator-name = "vreg_l3b";
+ regulator-min-microvolt = <880000>;
+ regulator-max-microvolt = <912000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l4b: ldo4 {
+ regulator-name = "vreg_l4b";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l6b: ldo6 {
+ regulator-name = "vreg_l6b";
+ regulator-min-microvolt = <866000>;
+ regulator-max-microvolt = <958000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l7b: ldo7 {
+ regulator-name = "vreg_l7b";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l8b: ldo8 {
+ regulator-name = "vreg_l8b";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l9b: ldo9 {
+ regulator-name = "vreg_l9b";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l10b: ldo10 {
+ regulator-name = "vreg_l10b";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l11b: ldo11 {
+ regulator-name = "vreg_l11b";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l12b: ldo12 {
+ regulator-name = "vreg_l12b";
+ regulator-min-microvolt = <2400000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l13b: ldo13 {
+ regulator-name = "vreg_l13b";
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l14b: ldo14 {
+ regulator-name = "vreg_l14b";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3304000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l15b: ldo15 {
+ regulator-name = "vreg_l15b";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3304000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l16b: ldo16 {
+ regulator-name = "vreg_l16b";
+ regulator-min-microvolt = <3008000>;
+ regulator-max-microvolt = <3008000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l17b: ldo17 {
+ regulator-name = "vreg_l17b";
+ regulator-min-microvolt = <3104000>;
+ regulator-max-microvolt = <3104000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l18b: ldo18 {
+ regulator-name = "vreg_l18b";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l19b: ldo19 {
+ regulator-name = "vreg_l19b";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l20b: ldo20 {
+ regulator-name = "vreg_l20b";
+ regulator-min-microvolt = <1620000>;
+ regulator-max-microvolt = <3544000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l21b: ldo21 {
+ regulator-name = "vreg_l21b";
+ regulator-min-microvolt = <1620000>;
+ regulator-max-microvolt = <3544000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l22b: ldo22 {
+ regulator-name = "vreg_l22b";
+ regulator-min-microvolt = <3200000>;
+ regulator-max-microvolt = <3200000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l23b: ldo23 {
+ regulator-name = "vreg_l23b";
+ regulator-min-microvolt = <1650000>;
+ regulator-max-microvolt = <3544000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_bob: bob {
+ regulator-name = "vreg_bob";
+ regulator-min-microvolt = <3008000>;
+ regulator-max-microvolt = <3960000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+ };
+
+ regulators-1 {
+ compatible = "qcom,pm8550vs-rpmh-regulators";
+
+ vdd-l1-supply = <&vreg_s1b>;
+
+ qcom,pmic-id = "d";
+
+ vreg_l1d: ldo1 {
+ regulator-name = "vreg_l1d";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+ };
+
+ regulators-2 {
+ compatible = "qcom,pm8550vs-rpmh-regulators";
+
+ vdd-l1-supply = <&vreg_s2b>;
+ vdd-l3-supply = <&vreg_s2b>;
+
+ qcom,pmic-id = "g";
+
+ vreg_l1g: ldo1 {
+ regulator-name = "vreg_l1g";
+ regulator-min-microvolt = <1150000>;
+ regulator-max-microvolt = <1260000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l3g: ldo3 {
+ regulator-name = "vreg_l3g";
+ regulator-min-microvolt = <1150000>;
+ regulator-max-microvolt = <1260000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ };
+
+ regulators-3 {
+ compatible = "qcom,pmr735d-rpmh-regulators";
+
+ vdd-l1-l2-l5-supply = <&vreg_s3b>;
+ vdd-l3-l4-supply = <&vreg_s2b>;
+ vdd-l6-supply = <&vreg_s1b>;
+ vdd-l7-supply = <&vreg_s3b>;
+
+ qcom,pmic-id = "k";
+
+ vreg_l1k: ldo1 {
+ regulator-name = "vreg_l1k";
+ regulator-min-microvolt = <488000>;
+ regulator-max-microvolt = <912000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l2k: ldo2 {
+ regulator-name = "vreg_l2k";
+ regulator-min-microvolt = <920000>;
+ regulator-max-microvolt = <969000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l3k: ldo3 {
+ regulator-name = "vreg_l3k";
+ regulator-min-microvolt = <1080000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l4k: ldo4 {
+ regulator-name = "vreg_l4k";
+ regulator-min-microvolt = <960000>;
+ regulator-max-microvolt = <1980000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l5k: ldo5 {
+ regulator-name = "vreg_l5k";
+ regulator-min-microvolt = <866000>;
+ regulator-max-microvolt = <931000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l6k: ldo6 {
+ regulator-name = "vreg_l6k";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <2000000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l7k: ldo7 {
+ regulator-name = "vreg_l7k";
+ regulator-min-microvolt = <720000>;
+ regulator-max-microvolt = <958000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+ };
+};
+
+&remoteproc_adsp {
+ firmware-name = "qcom/eliza/adsp.mbn",
+ "qcom/eliza/adsp_dtb.mbn";
+
+ status = "okay";
+};
+
+&sdhc_1 {
+ vmmc-supply = <&vreg_l12b>;
+ vqmmc-supply = <&vreg_l1d>;
+ pinctrl-0 = <&sdc1_default>;
+ pinctrl-1 = <&sdc1_sleep>;
+ pinctrl-names = "default", "sleep";
+ mmc-hs400-1_8v;
+ mmc-hs200-1_8v;
+ non-removable;
+ supports-cqe;
+ no-sdio;
+ no-sd;
+
+ status = "okay";
+};
+
+&tlmm {
+ gpio-reserved-ranges = <20 4>, /* NFC SPI */
+ <111 2>, /* WCN UART1 */
+ <118 1>; /* NFC Secure I/O */
+};
diff --git a/arch/arm64/boot/dts/qcom/eliza-evk.dtsi b/arch/arm64/boot/dts/qcom/eliza-evk.dtsi
new file mode 100644
index 000000000000..e47b24f8b827
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/eliza-evk.dtsi
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+/ {
+ aliases {
+ serial0 = &uart13;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&uart13 {
+ compatible = "qcom,geni-debug-uart";
+
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/eliza-mtp.dts b/arch/arm64/boot/dts/qcom/eliza-mtp.dts
index 1374afd9d14e..a7d6f9d52ef3 100644
--- a/arch/arm64/boot/dts/qcom/eliza-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/eliza-mtp.dts
@@ -11,6 +11,11 @@
#include "eliza.dtsi"
#include "pm7550ba-eliza.dtsi"
+#include "pm7550-eliza.dtsi"
+#include "pm8550vs-d-eliza.dtsi"
+#include "pm8550vs-g-eliza.dtsi"
+#include "pmr735d-eliza.dtsi"
+#include "pmk8550-eliza.dtsi"
/ {
model = "Qualcomm Technologies, Inc. Eliza MTP";
diff --git a/arch/arm64/boot/dts/qcom/eliza.dtsi b/arch/arm64/boot/dts/qcom/eliza.dtsi
index 977de44b816e..357e8066c176 100644
--- a/arch/arm64/boot/dts/qcom/eliza.dtsi
+++ b/arch/arm64/boot/dts/qcom/eliza.dtsi
@@ -1232,8 +1232,6 @@
#size-cells = <2>;
ranges;
- status = "disabled";
-
i2c0: i2c@a80000 {
compatible = "qcom,geni-i2c";
reg = <0x0 0x00a80000 0x0 0x4000>;
@@ -2696,7 +2694,7 @@
pdc: interrupt-controller@b220000 {
compatible = "qcom,eliza-pdc", "qcom,pdc";
- reg = <0x0 0x0b220000 0x0 0x40000>,
+ reg = <0x0 0x0b220000 0x0 0x10000>,
<0x0 0x174000f0 0x0 0x64>;
qcom,pdc-ranges = <0 480 8>, <8 719 1>, <9 718 1>,
@@ -3616,6 +3614,102 @@
#clock-cells = <1>;
};
+ pmu@24091000 {
+ compatible = "qcom,eliza-llcc-bwmon", "qcom,sc7280-llcc-bwmon";
+ reg = <0x0 0x24091000 0x0 0x1000>;
+
+ interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
+
+ interconnects = <&mc_virt MASTER_LLCC QCOM_ICC_TAG_ACTIVE_ONLY
+ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ACTIVE_ONLY>;
+
+ operating-points-v2 = <&llcc_bwmon_opp_table>;
+
+ llcc_bwmon_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ opp-0 {
+ opp-peak-kBps = <2188800>;
+ };
+
+ opp-1 {
+ opp-peak-kBps = <5414400>;
+ };
+
+ opp-2 {
+ opp-peak-kBps = <6220800>;
+ };
+
+ opp-3 {
+ opp-peak-kBps = <6835200>;
+ };
+
+ opp-4 {
+ opp-peak-kBps = <8371200>;
+ };
+
+ opp-5 {
+ opp-peak-kBps = <10944000>;
+ };
+
+ opp-6 {
+ opp-peak-kBps = <12748800>;
+ };
+
+ opp-7 {
+ opp-peak-kBps = <14745600>;
+ };
+
+ opp-8 {
+ opp-peak-kBps = <16896000>;
+ };
+ };
+ };
+
+ pmu@240b7400 {
+ compatible = "qcom,eliza-cpu-bwmon", "qcom,sdm845-bwmon";
+ reg = <0x0 0x240b7400 0x0 0x600>;
+
+ interrupts = <GIC_SPI 581 IRQ_TYPE_LEVEL_HIGH>;
+
+ interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY
+ &gem_noc SLAVE_LLCC QCOM_ICC_TAG_ACTIVE_ONLY>;
+
+ operating-points-v2 = <&cpu_bwmon_opp_table>;
+
+ cpu_bwmon_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ opp-0 {
+ opp-peak-kBps = <307200>;
+ };
+
+ opp-1 {
+ opp-peak-kBps = <5600000>;
+ };
+
+ opp-2 {
+ opp-peak-kBps = <8528000>;
+ };
+
+ opp-3 {
+ opp-peak-kBps = <11120000>;
+ };
+
+ opp-4 {
+ opp-peak-kBps = <14000000>;
+ };
+
+ opp-5 {
+ opp-peak-kBps = <14928000>;
+ };
+
+ opp-6 {
+ opp-peak-kBps = <17056000>;
+ };
+ };
+ };
+
gem_noc: interconnect@24100000 {
compatible = "qcom,eliza-gem-noc";
reg = <0x0 0x24100000 0x0 0x163080>;
diff --git a/arch/arm64/boot/dts/qcom/glymur.dtsi b/arch/arm64/boot/dts/qcom/glymur.dtsi
index 75ebdb38cd0e..dd80da14ab10 100644
--- a/arch/arm64/boot/dts/qcom/glymur.dtsi
+++ b/arch/arm64/boot/dts/qcom/glymur.dtsi
@@ -6303,6 +6303,7 @@
clocks = <&aoss_qmp>;
clock-names = "apb_pclk";
+ label = "tpdm_spdm";
qcom,cmb-element-bits = <32>;
qcom,cmb-msrs-num = <32>;
@@ -6367,6 +6368,7 @@
clocks = <&aoss_qmp>;
clock-names = "apb_pclk";
+ label = "tpdm_gcc";
qcom,dsb-msrs-num = <32>;
@@ -6385,6 +6387,7 @@
clocks = <&aoss_qmp>;
clock-names = "apb_pclk";
+ label = "tpdm_cdsp";
qcom,dsb-element-bits = <32>;
qcom,dsb-msrs-num = <32>;
@@ -6404,6 +6407,7 @@
clocks = <&aoss_qmp>;
clock-names = "apb_pclk";
+ label = "tpdm_cdsp_dpm_1";
qcom,cmb-element-bits = <64>;
qcom,cmb-msrs-num = <32>;
@@ -6423,6 +6427,7 @@
clocks = <&aoss_qmp>;
clock-names = "apb_pclk";
+ label = "tpdm_cdsp_dpm_2";
qcom,cmb-element-bits = <64>;
qcom,cmb-msrs-num = <32>;
@@ -6543,6 +6548,7 @@
clocks = <&aoss_qmp>;
clock-names = "apb_pclk";
+ label = "cti_cdsp";
};
cti_wpss: cti@111ab000 {
@@ -6551,6 +6557,7 @@
clocks = <&aoss_qmp>;
clock-names = "apb_pclk";
+ label = "cti_wpss";
};
tpdm@111d0000 {
@@ -6559,6 +6566,7 @@
clocks = <&aoss_qmp>;
clock-names = "apb_pclk";
+ label = "tpdm_qm";
qcom,dsb-msrs-num = <32>;
@@ -6734,6 +6742,7 @@
clocks = <&aoss_qmp>;
clock-names = "apb_pclk";
+ label = "tpdm_mm_dsb";
qcom,dsb-msrs-num = <32>;
@@ -6752,6 +6761,7 @@
clocks = <&aoss_qmp>;
clock-names = "apb_pclk";
+ label = "tpdm_east_dsb";
qcom,dsb-msrs-num = <32>;
@@ -6770,6 +6780,7 @@
clocks = <&aoss_qmp>;
clock-names = "apb_pclk";
+ label = "tpdm_west_dsb";
qcom,dsb-msrs-num = <32>;
@@ -6788,6 +6799,7 @@
clocks = <&aoss_qmp>;
clock-names = "apb_pclk";
+ label = "tpdm_center_dsb";
qcom,dsb-msrs-num = <32>;
@@ -6806,6 +6818,7 @@
clocks = <&aoss_qmp>;
clock-names = "apb_pclk";
+ label = "tpdm_ipcc";
qcom,cmb-msrs-num = <32>;
@@ -6824,6 +6837,7 @@
clocks = <&aoss_qmp>;
clock-names = "apb_pclk";
+ label = "tpdm_qrng";
qcom,cmb-msrs-num = <32>;
@@ -6842,6 +6856,7 @@
clocks = <&aoss_qmp>;
clock-names = "apb_pclk";
+ label = "tpdm_pmu";
qcom,dsb-msrs-num = <32>;
@@ -6860,6 +6875,7 @@
clocks = <&aoss_qmp>;
clock-names = "apb_pclk";
+ label = "tpdm_rdpm_cx";
qcom,cmb-msrs-num = <32>;
@@ -6878,6 +6894,7 @@
clocks = <&aoss_qmp>;
clock-names = "apb_pclk";
+ label = "tpdm_rdpm_mxc";
qcom,cmb-msrs-num = <32>;
@@ -6896,6 +6913,7 @@
clocks = <&aoss_qmp>;
clock-names = "apb_pclk";
+ label = "tpdm_rdpm_mxa";
qcom,cmb-msrs-num = <32>;
@@ -6914,6 +6932,7 @@
clocks = <&aoss_qmp>;
clock-names = "apb_pclk";
+ label = "tpdm_center_dsb_1";
qcom,dsb-msrs-num = <32>;
@@ -6932,6 +6951,7 @@
clocks = <&aoss_qmp>;
clock-names = "apb_pclk";
+ label = "tpdm_south2_dsb";
qcom,dsb-msrs-num = <32>;
@@ -6950,6 +6970,7 @@
clocks = <&aoss_qmp>;
clock-names = "apb_pclk";
+ label = "tpdm_south_dsb";
qcom,dsb-msrs-num = <32>;
@@ -6968,6 +6989,7 @@
clocks = <&aoss_qmp>;
clock-names = "apb_pclk";
+ label = "tpdm_pcie_rscc";
qcom,cmb-element-bits = <32>;
qcom,cmb-msrs-num = <32>;
@@ -7011,6 +7033,7 @@
clocks = <&aoss_qmp>;
clock-names = "apb_pclk";
+ label = "tpdm_swao_prio_4";
qcom,cmb-element-bits = <64>;
qcom,cmb-msrs-num = <32>;
@@ -7189,6 +7212,7 @@
clocks = <&aoss_qmp>;
clock-names = "apb_pclk";
+ label = "tpdm_swao_prio_0";
qcom,cmb-element-bits = <64>;
qcom,cmb-msrs-num = <32>;
@@ -7208,6 +7232,7 @@
clocks = <&aoss_qmp>;
clock-names = "apb_pclk";
+ label = "tpdm_swao_prio_1";
qcom,cmb-element-bits = <64>;
qcom,cmb-msrs-num = <32>;
@@ -7227,6 +7252,7 @@
clocks = <&aoss_qmp>;
clock-names = "apb_pclk";
+ label = "tpdm_swao_prio_2";
qcom,cmb-element-bits = <64>;
qcom,cmb-msrs-num = <32>;
@@ -7246,6 +7272,7 @@
clocks = <&aoss_qmp>;
clock-names = "apb_pclk";
+ label = "tpdm_swao_prio_3";
qcom,cmb-element-bits = <64>;
qcom,cmb-msrs-num = <32>;
@@ -7265,6 +7292,7 @@
clocks = <&aoss_qmp>;
clock-names = "apb_pclk";
+ label = "tpdm_swao";
qcom,dsb-element-bits = <32>;
qcom,dsb-msrs-num = <32>;
diff --git a/arch/arm64/boot/dts/qcom/hamoa.dtsi b/arch/arm64/boot/dts/qcom/hamoa.dtsi
index 60f485a4892e..b672a763047a 100644
--- a/arch/arm64/boot/dts/qcom/hamoa.dtsi
+++ b/arch/arm64/boot/dts/qcom/hamoa.dtsi
@@ -6,6 +6,7 @@
#include <dt-bindings/clock/qcom,rpmh.h>
#include <dt-bindings/clock/qcom,sc8280xp-lpasscc.h>
#include <dt-bindings/clock/qcom,sm8450-videocc.h>
+#include <dt-bindings/clock/qcom,x1e80100-camcc.h>
#include <dt-bindings/clock/qcom,x1e80100-dispcc.h>
#include <dt-bindings/clock/qcom,x1e80100-gcc.h>
#include <dt-bindings/clock/qcom,x1e80100-gpucc.h>
@@ -5501,6 +5502,22 @@
#power-domain-cells = <1>;
};
+ camcc: clock-controller@ade0000 {
+ compatible = "qcom,x1e80100-camcc";
+ reg = <0x0 0x0ade0000 0x0 0x20000>;
+ clocks = <&gcc GCC_CAMERA_AHB_CLK>,
+ <&bi_tcxo_div2>,
+ <&bi_tcxo_ao_div2>,
+ <&sleep_clk>;
+ power-domains = <&rpmhpd RPMHPD_MXC>,
+ <&rpmhpd RPMHPD_MMCX>;
+ required-opps = <&rpmhpd_opp_low_svs>,
+ <&rpmhpd_opp_low_svs>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ #power-domain-cells = <1>;
+ };
+
mdss: display-subsystem@ae00000 {
compatible = "qcom,x1e80100-mdss";
reg = <0 0x0ae00000 0 0x1000>;
@@ -5998,7 +6015,7 @@
pdc: interrupt-controller@b220000 {
compatible = "qcom,x1e80100-pdc", "qcom,pdc";
- reg = <0 0x0b220000 0 0x30000>, <0 0x174000f0 0 0x64>;
+ reg = <0 0x0b220000 0 0x10000>, <0 0x174000f0 0 0x64>;
qcom,pdc-ranges = <0 480 42>, <42 251 5>,
<47 522 52>, <99 609 32>,
diff --git a/arch/arm64/boot/dts/qcom/ipq5332-rdp441.dts b/arch/arm64/boot/dts/qcom/ipq5332-rdp441.dts
index 79ec77cfe552..7fcf632e289f 100644
--- a/arch/arm64/boot/dts/qcom/ipq5332-rdp441.dts
+++ b/arch/arm64/boot/dts/qcom/ipq5332-rdp441.dts
@@ -36,9 +36,6 @@
pinctrl-0 = <&pcie0_default>;
pinctrl-names = "default";
- perst-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>;
- wake-gpios = <&tlmm 39 GPIO_ACTIVE_LOW>;
-
status = "okay";
};
@@ -46,13 +43,15 @@
status = "okay";
};
+&pcie0_port0 {
+ reset-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 39 GPIO_ACTIVE_LOW>;
+};
+
&pcie1 {
pinctrl-0 = <&pcie1_default>;
pinctrl-names = "default";
- perst-gpios = <&tlmm 47 GPIO_ACTIVE_LOW>;
- wake-gpios = <&tlmm 48 GPIO_ACTIVE_LOW>;
-
status = "okay";
};
@@ -60,6 +59,11 @@
status = "okay";
};
+&pcie1_port0 {
+ reset-gpios = <&tlmm 47 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 48 GPIO_ACTIVE_LOW>;
+};
+
&tlmm {
i2c_1_pins: i2c-1-state {
pins = "gpio29", "gpio30";
diff --git a/arch/arm64/boot/dts/qcom/ipq5332.dtsi b/arch/arm64/boot/dts/qcom/ipq5332.dtsi
index fbc6c4d37fa3..74d9de8d7641 100644
--- a/arch/arm64/boot/dts/qcom/ipq5332.dtsi
+++ b/arch/arm64/boot/dts/qcom/ipq5332.dtsi
@@ -741,19 +741,18 @@
"aux",
"ahb";
- phys = <&pcie1_phy>;
- phy-names = "pciephy";
-
interconnects = <&gcc MASTER_SNOC_PCIE3_2_M &gcc SLAVE_SNOC_PCIE3_2_M>,
<&gcc MASTER_ANOC_PCIE3_2_S &gcc SLAVE_ANOC_PCIE3_2_S>;
interconnect-names = "pcie-mem", "cpu-pcie";
status = "disabled";
- pcie@0 {
+ pcie1_port0: pcie@0 {
device_type = "pci";
reg = <0x0 0x0 0x0 0x0 0x0>;
+ phys = <&pcie1_phy>;
+
#address-cells = <3>;
#size-cells = <2>;
ranges;
@@ -845,19 +844,18 @@
"aux",
"ahb";
- phys = <&pcie0_phy>;
- phy-names = "pciephy";
-
interconnects = <&gcc MASTER_SNOC_PCIE3_1_M &gcc SLAVE_SNOC_PCIE3_1_M>,
<&gcc MASTER_ANOC_PCIE3_1_S &gcc SLAVE_ANOC_PCIE3_1_S>;
interconnect-names = "pcie-mem", "cpu-pcie";
status = "disabled";
- pcie@0 {
+ pcie0_port0: pcie@0 {
device_type = "pci";
reg = <0x0 0x0 0x0 0x0 0x0>;
+ phys = <&pcie0_phy>;
+
#address-cells = <3>;
#size-cells = <2>;
ranges;
diff --git a/arch/arm64/boot/dts/qcom/ipq5424-rdp466.dts b/arch/arm64/boot/dts/qcom/ipq5424-rdp466.dts
index de71b72ae6dc..be8657239c46 100644
--- a/arch/arm64/boot/dts/qcom/ipq5424-rdp466.dts
+++ b/arch/arm64/boot/dts/qcom/ipq5424-rdp466.dts
@@ -86,8 +86,6 @@
pinctrl-0 = <&pcie2_default_state>;
pinctrl-names = "default";
- perst-gpios = <&tlmm 31 GPIO_ACTIVE_LOW>;
-
status = "okay";
};
@@ -95,12 +93,14 @@
status = "okay";
};
+&pcie2_port0 {
+ reset-gpios = <&tlmm 31 GPIO_ACTIVE_LOW>;
+};
+
&pcie3 {
pinctrl-0 = <&pcie3_default_state>;
pinctrl-names = "default";
- perst-gpios = <&tlmm 34 GPIO_ACTIVE_LOW>;
-
status = "okay";
};
@@ -108,6 +108,10 @@
status = "okay";
};
+&pcie3_port0 {
+ reset-gpios = <&tlmm 34 GPIO_ACTIVE_LOW>;
+};
+
&qusb_phy_0 {
vdd-supply = <&vreg_misc_0p925>;
vdda-pll-supply = <&vreg_misc_1p8>;
diff --git a/arch/arm64/boot/dts/qcom/ipq5424.dtsi b/arch/arm64/boot/dts/qcom/ipq5424.dtsi
index 876bf6a8b8ff..702061e16a58 100644
--- a/arch/arm64/boot/dts/qcom/ipq5424.dtsi
+++ b/arch/arm64/boot/dts/qcom/ipq5424.dtsi
@@ -968,19 +968,19 @@
"aux",
"ahb";
- phys = <&pcie3_phy>;
- phy-names = "pciephy";
interconnects = <&gcc MASTER_ANOC_PCIE3 &gcc SLAVE_ANOC_PCIE3>,
<&gcc MASTER_CNOC_PCIE3 &gcc SLAVE_CNOC_PCIE3>;
interconnect-names = "pcie-mem", "cpu-pcie";
status = "disabled";
- pcie@0 {
+ pcie3_port0: pcie@0 {
device_type = "pci";
reg = <0x0 0x0 0x0 0x0 0x0>;
bus-range = <0x01 0xff>;
+ phys = <&pcie3_phy>;
+
#address-cells = <3>;
#size-cells = <2>;
ranges;
@@ -1071,19 +1071,19 @@
"aux",
"ahb";
- phys = <&pcie2_phy>;
- phy-names = "pciephy";
interconnects = <&gcc MASTER_ANOC_PCIE2 &gcc SLAVE_ANOC_PCIE2>,
<&gcc MASTER_CNOC_PCIE2 &gcc SLAVE_CNOC_PCIE2>;
interconnect-names = "pcie-mem", "cpu-pcie";
status = "disabled";
- pcie@0 {
+ pcie2_port0: pcie@0 {
device_type = "pci";
reg = <0x0 0x0 0x0 0x0 0x0>;
bus-range = <0x01 0xff>;
+ phys = <&pcie2_phy>;
+
#address-cells = <3>;
#size-cells = <2>;
ranges;
@@ -1174,19 +1174,19 @@
"aux",
"ahb";
- phys = <&pcie1_phy>;
- phy-names = "pciephy";
interconnects = <&gcc MASTER_ANOC_PCIE1 &gcc SLAVE_ANOC_PCIE1>,
<&gcc MASTER_CNOC_PCIE1 &gcc SLAVE_CNOC_PCIE1>;
interconnect-names = "pcie-mem", "cpu-pcie";
status = "disabled";
- pcie@0 {
+ pcie1_port0: pcie@0 {
device_type = "pci";
reg = <0x0 0x0 0x0 0x0 0x0>;
bus-range = <0x01 0xff>;
+ phys = <&pcie1_phy>;
+
#address-cells = <3>;
#size-cells = <2>;
ranges;
@@ -1277,19 +1277,19 @@
"aux",
"ahb";
- phys = <&pcie0_phy>;
- phy-names = "pciephy";
interconnects = <&gcc MASTER_ANOC_PCIE0 &gcc SLAVE_ANOC_PCIE0>,
<&gcc MASTER_CNOC_PCIE0 &gcc SLAVE_CNOC_PCIE0>;
interconnect-names = "pcie-mem", "cpu-pcie";
status = "disabled";
- pcie@0 {
+ pcie0_port0: pcie@0 {
device_type = "pci";
reg = <0x0 0x0 0x0 0x0 0x0>;
bus-range = <0x01 0xff>;
+ phys = <&pcie0_phy>;
+
#address-cells = <3>;
#size-cells = <2>;
ranges;
diff --git a/arch/arm64/boot/dts/qcom/ipq9574.dtsi b/arch/arm64/boot/dts/qcom/ipq9574.dtsi
index 3f15c40f7841..451c2076f6a7 100644
--- a/arch/arm64/boot/dts/qcom/ipq9574.dtsi
+++ b/arch/arm64/boot/dts/qcom/ipq9574.dtsi
@@ -955,7 +955,8 @@
<GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
+ <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "msi0",
"msi1",
"msi2",
@@ -963,7 +964,8 @@
"msi4",
"msi5",
"msi6",
- "msi7";
+ "msi7",
+ "global";
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0x7>;
@@ -1041,7 +1043,8 @@
<GIC_SPI 326 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 415 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 494 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 495 IRQ_TYPE_LEVEL_HIGH>;
+ <GIC_SPI 495 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "msi0",
"msi1",
"msi2",
@@ -1049,7 +1052,8 @@
"msi4",
"msi5",
"msi6",
- "msi7";
+ "msi7",
+ "global";
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0x7>;
@@ -1127,7 +1131,8 @@
<GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
+ <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "msi0",
"msi1",
"msi2",
@@ -1135,7 +1140,8 @@
"msi4",
"msi5",
"msi6",
- "msi7";
+ "msi7",
+ "global";
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0x7>;
@@ -1212,7 +1218,8 @@
<GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
+ <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "msi0",
"msi1",
"msi2",
@@ -1220,7 +1227,8 @@
"msi4",
"msi5",
"msi6",
- "msi7";
+ "msi7",
+ "global";
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0x7>;
diff --git a/arch/arm64/boot/dts/qcom/kaanapali.dtsi b/arch/arm64/boot/dts/qcom/kaanapali.dtsi
index 0518488f358b..ace19b8b12d7 100644
--- a/arch/arm64/boot/dts/qcom/kaanapali.dtsi
+++ b/arch/arm64/boot/dts/qcom/kaanapali.dtsi
@@ -3251,6 +3251,297 @@
};
};
+ camss: isp@9253000 {
+ compatible = "qcom,kaanapali-camss";
+
+ reg = <0x0 0x09253000 0x0 0x5e80>,
+ <0x0 0x09263000 0x0 0x5e80>,
+ <0x0 0x09273000 0x0 0x5e80>,
+ <0x0 0x092d3000 0x0 0x3880>,
+ <0x0 0x092e7000 0x0 0x3880>,
+ <0x0 0x09523000 0x0 0x2000>,
+ <0x0 0x09525000 0x0 0x2000>,
+ <0x0 0x09527000 0x0 0x2000>,
+ <0x0 0x09529000 0x0 0x2000>,
+ <0x0 0x0952b000 0x0 0x2000>,
+ <0x0 0x0952d000 0x0 0x2000>,
+ <0x0 0x093fd000 0x0 0x400>,
+ <0x0 0x093fe000 0x0 0x400>,
+ <0x0 0x093ff000 0x0 0x400>,
+ <0x0 0x09151000 0x0 0x20000>,
+ <0x0 0x09171000 0x0 0x20000>,
+ <0x0 0x09191000 0x0 0x20000>,
+ <0x0 0x092dc000 0x0 0x1300>,
+ <0x0 0x092f0000 0x0 0x1300>;
+ reg-names = "csid0",
+ "csid1",
+ "csid2",
+ "csid_lite0",
+ "csid_lite1",
+ "csiphy0",
+ "csiphy1",
+ "csiphy2",
+ "csiphy3",
+ "csiphy4",
+ "csiphy5",
+ "csitpg0",
+ "csitpg1",
+ "csitpg2",
+ "vfe0",
+ "vfe1",
+ "vfe2",
+ "vfe_lite0",
+ "vfe_lite1";
+
+ clocks = <&camcc CAM_CC_CAMNOC_NRT_AXI_CLK>,
+ <&camcc CAM_CC_CAMNOC_RT_AXI_CLK>,
+ <&camcc CAM_CC_CAM_TOP_AHB_CLK>,
+ <&camcc CAM_CC_CAM_TOP_FAST_AHB_CLK>,
+ <&camcc CAM_CC_CAMNOC_RT_TFE_0_MAIN_CLK>,
+ <&camcc CAM_CC_CAMNOC_RT_TFE_1_MAIN_CLK>,
+ <&camcc CAM_CC_CAMNOC_RT_TFE_2_MAIN_CLK>,
+ <&camcc CAM_CC_CAMNOC_RT_IFE_LITE_CLK>,
+ <&camcc CAM_CC_CSID_CLK>,
+ <&camcc CAM_CC_CSID_CSIPHY_RX_CLK>,
+ <&camcc CAM_CC_CSIPHY0_CLK>,
+ <&camcc CAM_CC_CSI0PHYTIMER_CLK>,
+ <&camcc CAM_CC_CSIPHY1_CLK>,
+ <&camcc CAM_CC_CSI1PHYTIMER_CLK>,
+ <&camcc CAM_CC_CSIPHY2_CLK>,
+ <&camcc CAM_CC_CSI2PHYTIMER_CLK>,
+ <&camcc CAM_CC_CSIPHY3_CLK>,
+ <&camcc CAM_CC_CSI3PHYTIMER_CLK>,
+ <&camcc CAM_CC_CSIPHY4_CLK>,
+ <&camcc CAM_CC_CSI4PHYTIMER_CLK>,
+ <&camcc CAM_CC_CSIPHY5_CLK>,
+ <&camcc CAM_CC_CSI5PHYTIMER_CLK>,
+ <&gcc GCC_CAMERA_HF_AXI_CLK>,
+ <&gcc GCC_CAMERA_SF_AXI_CLK>,
+ <&camcc CAM_CC_TFE_0_MAIN_CLK>,
+ <&camcc CAM_CC_TFE_0_MAIN_FAST_AHB_CLK>,
+ <&camcc CAM_CC_TFE_1_MAIN_CLK>,
+ <&camcc CAM_CC_TFE_1_MAIN_FAST_AHB_CLK>,
+ <&camcc CAM_CC_TFE_2_MAIN_CLK>,
+ <&camcc CAM_CC_TFE_2_MAIN_FAST_AHB_CLK>,
+ <&camcc CAM_CC_IFE_LITE_CLK>,
+ <&camcc CAM_CC_IFE_LITE_AHB_CLK>,
+ <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>,
+ <&camcc CAM_CC_IFE_LITE_CSID_CLK>,
+ <&camcc CAM_CC_QDSS_DEBUG_XO_CLK>;
+ clock-names = "camnoc_nrt_axi",
+ "camnoc_rt_axi",
+ "cpas_ahb",
+ "cpas_fast_ahb",
+ "cpas_vfe0",
+ "cpas_vfe1",
+ "cpas_vfe2",
+ "cpas_vfe_lite",
+ "csid",
+ "csid_csiphy_rx",
+ "csiphy0",
+ "csiphy0_timer",
+ "csiphy1",
+ "csiphy1_timer",
+ "csiphy2",
+ "csiphy2_timer",
+ "csiphy3",
+ "csiphy3_timer",
+ "csiphy4",
+ "csiphy4_timer",
+ "csiphy5",
+ "csiphy5_timer",
+ "gcc_axi_hf",
+ "gcc_axi_sf",
+ "vfe0",
+ "vfe0_fast_ahb",
+ "vfe1",
+ "vfe1_fast_ahb",
+ "vfe2",
+ "vfe2_fast_ahb",
+ "vfe_lite",
+ "vfe_lite_ahb",
+ "vfe_lite_cphy_rx",
+ "vfe_lite_csid",
+ "qdss_debug_xo";
+
+ interrupts = <GIC_SPI 601 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 603 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 431 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 605 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 376 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 477 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 478 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 479 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 448 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 122 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 89 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 433 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 436 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 457 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 606 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 377 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "csid0",
+ "csid1",
+ "csid2",
+ "csid_lite0",
+ "csid_lite1",
+ "csiphy0",
+ "csiphy1",
+ "csiphy2",
+ "csiphy3",
+ "csiphy4",
+ "csiphy5",
+ "vfe0",
+ "vfe1",
+ "vfe2",
+ "vfe_lite0",
+ "vfe_lite1";
+
+ interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY
+ &config_noc SLAVE_CAMERA_CFG QCOM_ICC_TAG_ACTIVE_ONLY>,
+ <&mmss_noc MASTER_CAMNOC_HF QCOM_ICC_TAG_ALWAYS
+ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>,
+ <&mmss_noc MASTER_CAMNOC_SF QCOM_ICC_TAG_ALWAYS
+ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>,
+ <&mmss_noc MASTER_CAMNOC_NRT_ICP_SF QCOM_ICC_TAG_ALWAYS
+ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>;
+ interconnect-names = "ahb",
+ "hf_mnoc",
+ "sf_mnoc",
+ "sf_icp_mnoc";
+
+ iommus = <&apps_smmu 0x1c00 0x00>;
+
+ power-domains = <&camcc CAM_CC_TFE_0_GDSC>,
+ <&camcc CAM_CC_TFE_1_GDSC>,
+ <&camcc CAM_CC_TFE_2_GDSC>,
+ <&camcc CAM_CC_TITAN_TOP_GDSC>;
+ power-domain-names = "ife0",
+ "ife1",
+ "ife2",
+ "top";
+ status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ };
+
+ port@1 {
+ reg = <1>;
+ };
+
+ port@2 {
+ reg = <2>;
+ };
+
+ port@3 {
+ reg = <3>;
+ };
+
+ port@4 {
+ reg = <4>;
+ };
+
+ port@5 {
+ reg = <5>;
+ };
+ };
+ };
+
+ cci0: cci@941b000 {
+ compatible = "qcom,kaanapali-cci", "qcom,msm8996-cci";
+ reg = <0x0 0x0941b000 0x0 0x1000>;
+ interrupts = <GIC_SPI 426 IRQ_TYPE_EDGE_RISING>;
+ power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>;
+ clocks = <&camcc CAM_CC_CAM_TOP_AHB_CLK>,
+ <&camcc CAM_CC_CCI_0_CLK>;
+ clock-names = "ahb", "cci";
+ pinctrl-0 = <&cci0_0_default &cci0_1_default>;
+ pinctrl-1 = <&cci0_0_sleep &cci0_1_sleep>;
+ pinctrl-names = "default", "sleep";
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cci0_i2c0: i2c-bus@0 {
+ reg = <0>;
+ clock-frequency = <1000000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ cci0_i2c1: i2c-bus@1 {
+ reg = <1>;
+ clock-frequency = <1000000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+
+ cci1: cci@941c000 {
+ compatible = "qcom,kaanapali-cci", "qcom,msm8996-cci";
+ reg = <0x0 0x0941c000 0x0 0x1000>;
+ interrupts = <GIC_SPI 427 IRQ_TYPE_EDGE_RISING>;
+ power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>;
+ clocks = <&camcc CAM_CC_CAM_TOP_AHB_CLK>,
+ <&camcc CAM_CC_CCI_1_CLK>;
+ clock-names = "ahb", "cci";
+ pinctrl-0 = <&cci1_0_default &cci1_1_default>;
+ pinctrl-1 = <&cci1_0_sleep &cci1_1_sleep>;
+ pinctrl-names = "default", "sleep";
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cci1_i2c0: i2c-bus@0 {
+ reg = <0>;
+ clock-frequency = <1000000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ cci1_i2c1: i2c-bus@1 {
+ reg = <1>;
+ clock-frequency = <1000000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+
+ cci2: cci@941d000 {
+ compatible = "qcom,kaanapali-cci", "qcom,msm8996-cci";
+ reg = <0x0 0x0941d000 0x0 0x1000>;
+ interrupts = <GIC_SPI 428 IRQ_TYPE_EDGE_RISING>;
+ power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>;
+ clocks = <&camcc CAM_CC_CAM_TOP_AHB_CLK>,
+ <&camcc CAM_CC_CCI_2_CLK>;
+ clock-names = "ahb", "cci";
+ pinctrl-0 = <&cci2_0_default &cci2_1_default>;
+ pinctrl-1 = <&cci2_0_sleep &cci2_1_sleep>;
+ pinctrl-names = "default", "sleep";
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cci2_i2c0: i2c-bus@0 {
+ reg = <0>;
+ clock-frequency = <1000000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ cci2_i2c1: i2c-bus@1 {
+ reg = <1>;
+ clock-frequency = <1000000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+
camcc: clock-controller@956d000 {
compatible = "qcom,kaanapali-camcc";
reg = <0x0 0x0956d000 0x0 0x80000>;
@@ -3811,6 +4102,254 @@
#interrupt-cells = <2>;
wakeup-parent = <&pdc>;
+ cam0_default: cam0-default-state {
+ pins = "gpio89";
+ function = "cam_mclk";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ cam1_default: cam1-default-state {
+ pins = "gpio90";
+ function = "cam_mclk";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ cam2_default: cam2-default-state {
+ pins = "gpio91";
+ function = "cam_asc_mclk2";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ cam3_default: cam3-default-state {
+ pins = "gpio92";
+ function = "cam_mclk";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ cam4_default: cam4-default-state {
+ pins = "gpio93";
+ function = "cam_asc_mclk4";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ cam5_default: cam5-default-state {
+ pins = "gpio94";
+ function = "cam_mclk";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ cam6_default: cam6-default-state {
+ pins = "gpio95";
+ function = "cam_mclk";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ cam7_default: cam7-default-state {
+ pins = "gpio96";
+ function = "cam_mclk";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ cci0_0_default: cci0-0-default-state {
+ sda-pins {
+ pins = "gpio109";
+ function = "cci_i2c_sda";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ scl-pins {
+ pins = "gpio110";
+ function = "cci_i2c_scl";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ cci0_0_sleep: cci0-0-sleep-state {
+ sda-pins {
+ pins = "gpio109";
+ function = "cci_i2c_sda";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ scl-pins {
+ pins = "gpio110";
+ function = "cci_i2c_scl";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+ };
+
+ cci0_1_default: cci0-1-default-state {
+ sda-pins {
+ pins = "gpio111";
+ function = "cci_i2c_sda";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ scl-pins {
+ pins = "gpio112";
+ function = "cci_i2c_scl";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ cci0_1_sleep: cci0-1-sleep-state {
+ sda-pins {
+ pins = "gpio111";
+ function = "cci_i2c_sda";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ scl-pins {
+ pins = "gpio112";
+ function = "cci_i2c_scl";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+ };
+
+ cci1_0_default: cci1-0-default-state {
+ sda-pins {
+ pins = "gpio113";
+ function = "cci_i2c_sda";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ scl-pins {
+ pins = "gpio114";
+ function = "cci_i2c_scl";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ cci1_0_sleep: cci1-0-sleep-state {
+ sda-pins {
+ pins = "gpio113";
+ function = "cci_i2c_sda";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ scl-pins {
+ pins = "gpio114";
+ function = "cci_i2c_scl";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+ };
+
+ cci1_1_default: cci1-1-default-state {
+ sda-pins {
+ pins = "gpio107";
+ function = "cci_i2c_sda";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ scl-pins {
+ pins = "gpio160";
+ function = "cci_i2c_scl";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ cci1_1_sleep: cci1-1-sleep-state {
+ sda-pins {
+ pins = "gpio107";
+ function = "cci_i2c_sda";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ scl-pins {
+ pins = "gpio160";
+ function = "cci_i2c_scl";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+ };
+
+ cci2_0_default: cci2-0-default-state {
+ sda-pins {
+ pins = "gpio108";
+ function = "cci_i2c_sda";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ scl-pins {
+ pins = "gpio149";
+ function = "cci_i2c_scl";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ cci2_0_sleep: cci2-0-sleep-state {
+ sda-pins {
+ pins = "gpio108";
+ function = "cci_i2c_sda";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ scl-pins {
+ pins = "gpio149";
+ function = "cci_i2c_scl";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+ };
+
+ cci2_1_default: cci2-1-default-state {
+ sda-pins {
+ pins = "gpio115";
+ function = "cci_i2c_sda";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ scl-pins {
+ pins = "gpio116";
+ function = "cci_i2c_scl";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ cci2_1_sleep: cci2-1-sleep-state {
+ sda-pins {
+ pins = "gpio115";
+ function = "cci_i2c_sda";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ scl-pins {
+ pins = "gpio116";
+ function = "cci_i2c_scl";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+ };
+
hub_i2c0_data_clk: hub-i2c0-data-clk-state {
/* SDA, SCL */
pins = "gpio66", "gpio67";
diff --git a/arch/arm64/boot/dts/qcom/kodiak.dtsi b/arch/arm64/boot/dts/qcom/kodiak.dtsi
index 90e50c245c0c..7e73348fe0d0 100644
--- a/arch/arm64/boot/dts/qcom/kodiak.dtsi
+++ b/arch/arm64/boot/dts/qcom/kodiak.dtsi
@@ -191,9 +191,12 @@
qcom,vmid = <QCOM_SCM_VMID_MSS_MSA>;
};
- adsp_rpc_remote_heap_mem: adsp-rpc-remote-heap@9cb80000 {
- reg = <0x0 0x9cb80000 0x0 0x800000>;
- no-map;
+ adsp_rpc_remote_heap_mem: adsp-rpc-remote-heap {
+ compatible = "shared-dma-pool";
+ alloc-ranges = <0x0 0x80000000 0x0 0x80000000>;
+ reusable;
+ alignment = <0x0 0x400000>;
+ size = <0x0 0x800000>;
};
};
@@ -2286,9 +2289,6 @@
power-domains = <&gcc GCC_PCIE_0_GDSC>;
- phys = <&pcie0_phy>;
- phy-names = "pciephy";
-
pinctrl-names = "default";
pinctrl-0 = <&pcie0_clkreq_n>;
dma-coherent;
@@ -2300,6 +2300,8 @@
reg = <0x0 0x0 0x0 0x0 0x0>;
bus-range = <0x01 0xff>;
+ phys = <&pcie0_phy>;
+
#address-cells = <3>;
#size-cells = <2>;
ranges;
@@ -2416,9 +2418,6 @@
power-domains = <&gcc GCC_PCIE_1_GDSC>;
- phys = <&pcie1_phy>;
- phy-names = "pciephy";
-
pinctrl-names = "default";
pinctrl-0 = <&pcie1_clkreq_n>;
@@ -2434,6 +2433,8 @@
reg = <0x0 0x0 0x0 0x0 0x0>;
bus-range = <0x01 0xff>;
+ phys = <&pcie1_phy>;
+
#address-cells = <3>;
#size-cells = <2>;
ranges;
@@ -5758,7 +5759,7 @@
pdc: interrupt-controller@b220000 {
compatible = "qcom,sc7280-pdc", "qcom,pdc";
- reg = <0 0x0b220000 0 0x30000>;
+ reg = <0 0x0b220000 0 0x10000>;
qcom,pdc-ranges = <0 480 40>, <40 140 14>, <54 263 1>,
<55 306 4>, <59 312 3>, <62 374 2>,
<64 434 2>, <66 438 3>, <69 86 1>,
diff --git a/arch/arm64/boot/dts/qcom/lemans-evk-camera.dtso b/arch/arm64/boot/dts/qcom/lemans-evk-camera.dtso
index 4600d5441cce..a4c6d39cf777 100644
--- a/arch/arm64/boot/dts/qcom/lemans-evk-camera.dtso
+++ b/arch/arm64/boot/dts/qcom/lemans-evk-camera.dtso
@@ -14,7 +14,7 @@
#include <dt-bindings/gpio/gpio.h>
&{/} {
- vreg_cam1_1p8: vreg_cam1_1p8 {
+ vreg_cam1_1p8: cam1-1p8-regulator {
compatible = "regulator-fixed";
regulator-name = "vreg_cam1_1p8";
startup-delay-us = <10000>;
diff --git a/arch/arm64/boot/dts/qcom/lemans-evk.dts b/arch/arm64/boot/dts/qcom/lemans-evk.dts
index 0b01be78a737..0c53640c42a6 100644
--- a/arch/arm64/boot/dts/qcom/lemans-evk.dts
+++ b/arch/arm64/boot/dts/qcom/lemans-evk.dts
@@ -21,6 +21,7 @@
ethernet0 = &ethernet0;
mmc1 = &sdhc;
serial0 = &uart10;
+ serial1 = &uart17;
serial2 = &uart0;
};
@@ -119,6 +120,38 @@
};
};
+ connector-3 {
+ compatible = "pcie-m2-e-connector";
+ vpcie3v3-supply = <&vreg_wcn_3p3>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ m2_e_pcie_ep: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&pcieport0_ep>;
+ };
+ };
+
+ port@3 {
+ reg = <3>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ m2_e_uart_ep: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&uart17_ep>;
+ };
+ };
+ };
+ };
+
edp0-connector {
compatible = "dp-connector";
label = "EDP0";
@@ -218,6 +251,17 @@
regulator-max-microvolt = <2950000>;
};
+ vreg_dcin_12v: regulator-dcin-12v {
+ compatible = "regulator-fixed";
+
+ regulator-name = "VREG_DCIN_12V";
+ regulator-min-microvolt = <12000000>;
+ regulator-max-microvolt = <12000000>;
+
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
vreg_sdc: regulator-vreg-sdc {
compatible = "regulator-gpio";
@@ -231,6 +275,19 @@
startup-delay-us = <100>;
};
+
+ vreg_wcn_3p3: regulator-wcn-3p3 {
+ compatible = "regulator-fixed";
+
+ regulator-name = "VREG_WCN_3P3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+
+ vin-supply = <&vreg_dcin_12v>;
+
+ regulator-always-on;
+ regulator-boot-on;
+ };
};
&apps_rsc {
@@ -815,6 +872,14 @@
status = "okay";
};
+&pcieport0 {
+ port {
+ pcieport0_ep: endpoint {
+ remote-endpoint = <&m2_e_pcie_ep>;
+ };
+ };
+};
+
&pmm8654au_0_pon_resin {
linux,code = <KEY_VOLUMEDOWN>;
status = "okay";
@@ -1057,6 +1122,16 @@
status = "okay";
};
+&uart17 {
+ status = "okay";
+
+ port {
+ uart17_ep: endpoint {
+ remote-endpoint = <&m2_e_uart_ep>;
+ };
+ };
+};
+
&ufs_mem_hc {
reset-gpios = <&tlmm 149 GPIO_ACTIVE_LOW>;
vcc-supply = <&vreg_l8a>;
diff --git a/arch/arm64/boot/dts/qcom/lemans-ride-common.dtsi b/arch/arm64/boot/dts/qcom/lemans-ride-common.dtsi
index 40f88498999b..cefb8ff00806 100644
--- a/arch/arm64/boot/dts/qcom/lemans-ride-common.dtsi
+++ b/arch/arm64/boot/dts/qcom/lemans-ride-common.dtsi
@@ -63,7 +63,7 @@
regulator-max-microvolt = <3300000>;
};
- vreg_conn_1p8: vreg_conn_1p8 {
+ vreg_conn_1p8: vreg-conn-1p8-regulator {
compatible = "regulator-fixed";
regulator-name = "vreg_conn_1p8";
startup-delay-us = <4000>;
@@ -71,7 +71,7 @@
gpio = <&pmm8654au_1_gpios 4 GPIO_ACTIVE_HIGH>;
};
- vreg_conn_pa: vreg_conn_pa {
+ vreg_conn_pa: vreg-conn-pa-regulator {
compatible = "regulator-fixed";
regulator-name = "vreg_conn_pa";
startup-delay-us = <4000>;
diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi
index a10322c5bc35..3b0539e27b51 100644
--- a/arch/arm64/boot/dts/qcom/lemans.dtsi
+++ b/arch/arm64/boot/dts/qcom/lemans.dtsi
@@ -297,17 +297,7 @@
idle-states {
entry-method = "psci";
- gold_cpu_sleep_0: cpu-sleep-0 {
- compatible = "arm,idle-state";
- idle-state-name = "gold-power-collapse";
- arm,psci-suspend-param = <0x40000003>;
- entry-latency-us = <549>;
- exit-latency-us = <901>;
- min-residency-us = <1774>;
- local-timer-stop;
- };
-
- gold_rail_cpu_sleep_0: cpu-sleep-1 {
+ gold_rail_cpu_sleep_0: cpu-sleep-0 {
compatible = "arm,idle-state";
idle-state-name = "gold-rail-power-collapse";
arm,psci-suspend-param = <0x40000004>;
@@ -566,57 +556,49 @@
cpu_pd0: power-domain-cpu0 {
#power-domain-cells = <0>;
power-domains = <&cluster_0_pd>;
- domain-idle-states = <&gold_cpu_sleep_0>,
- <&gold_rail_cpu_sleep_0>;
+ domain-idle-states = <&gold_rail_cpu_sleep_0>;
};
cpu_pd1: power-domain-cpu1 {
#power-domain-cells = <0>;
power-domains = <&cluster_0_pd>;
- domain-idle-states = <&gold_cpu_sleep_0>,
- <&gold_rail_cpu_sleep_0>;
+ domain-idle-states = <&gold_rail_cpu_sleep_0>;
};
cpu_pd2: power-domain-cpu2 {
#power-domain-cells = <0>;
power-domains = <&cluster_0_pd>;
- domain-idle-states = <&gold_cpu_sleep_0>,
- <&gold_rail_cpu_sleep_0>;
+ domain-idle-states = <&gold_rail_cpu_sleep_0>;
};
cpu_pd3: power-domain-cpu3 {
#power-domain-cells = <0>;
power-domains = <&cluster_0_pd>;
- domain-idle-states = <&gold_cpu_sleep_0>,
- <&gold_rail_cpu_sleep_0>;
+ domain-idle-states = <&gold_rail_cpu_sleep_0>;
};
cpu_pd4: power-domain-cpu4 {
#power-domain-cells = <0>;
power-domains = <&cluster_1_pd>;
- domain-idle-states = <&gold_cpu_sleep_0>,
- <&gold_rail_cpu_sleep_0>;
+ domain-idle-states = <&gold_rail_cpu_sleep_0>;
};
cpu_pd5: power-domain-cpu5 {
#power-domain-cells = <0>;
power-domains = <&cluster_1_pd>;
- domain-idle-states = <&gold_cpu_sleep_0>,
- <&gold_rail_cpu_sleep_0>;
+ domain-idle-states = <&gold_rail_cpu_sleep_0>;
};
cpu_pd6: power-domain-cpu6 {
#power-domain-cells = <0>;
power-domains = <&cluster_1_pd>;
- domain-idle-states = <&gold_cpu_sleep_0>,
- <&gold_rail_cpu_sleep_0>;
+ domain-idle-states = <&gold_rail_cpu_sleep_0>;
};
cpu_pd7: power-domain-cpu7 {
#power-domain-cells = <0>;
power-domains = <&cluster_1_pd>;
- domain-idle-states = <&gold_cpu_sleep_0>,
- <&gold_rail_cpu_sleep_0>;
+ domain-idle-states = <&gold_rail_cpu_sleep_0>;
};
cluster_0_pd: power-domain-cluster0 {
@@ -1041,7 +1023,7 @@
#address-cells = <1>;
#size-cells = <1>;
- gpu_speed_bin: gpu_speed_bin@240c {
+ gpu_speed_bin: gpu-speed-bin@240c {
reg = <0x240c 0x1>;
bits = <0 8>;
};
@@ -2779,6 +2761,7 @@
status = "disabled";
pcieport0: pcie@0 {
+ compatible = "pciclass,0604";
device_type = "pci";
reg = <0x0 0x0 0x0 0x0 0x0>;
bus-range = <0x01 0xff>;
@@ -5886,7 +5869,7 @@
pdc: interrupt-controller@b220000 {
compatible = "qcom,sa8775p-pdc", "qcom,pdc";
- reg = <0x0 0x0b220000 0x0 0x30000>,
+ reg = <0x0 0x0b220000 0x0 0x10000>,
<0x0 0x17c000f0 0x0 0x64>;
qcom,pdc-ranges = <0 480 40>,
<40 140 14>,
diff --git a/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts b/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts
index 2fc93e64b520..bb3b67e2fd01 100644
--- a/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts
+++ b/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts
@@ -449,16 +449,16 @@
regulators-2 {
compatible = "qcom,pmr735b-rpmh-regulators";
- vdd-l1-l2-supply= <&vreg_s3b>;
- vdd-l3-supply= <&vreg_s3b>;
- vdd-l4-supply= <&vreg_s1b>;
- vdd-l5-supply= <&vreg_s2b>;
- vdd-l6-supply= <&vreg_s2b>;
- vdd-l7-l8-supply= <&vreg_s2b>;
- vdd-l9-supply= <&vreg_s3b>;
- vdd-l10-supply= <&vreg_s1b>;
- vdd-l11-supply= <&vreg_s3b>;
- vdd-l12-supply= <&vreg_s3b>;
+ vdd-l1-l2-supply = <&vreg_s3b>;
+ vdd-l3-supply = <&vreg_s3b>;
+ vdd-l4-supply = <&vreg_s1b>;
+ vdd-l5-supply = <&vreg_s2b>;
+ vdd-l6-supply = <&vreg_s2b>;
+ vdd-l7-l8-supply = <&vreg_s2b>;
+ vdd-l9-supply = <&vreg_s3b>;
+ vdd-l10-supply = <&vreg_s1b>;
+ vdd-l11-supply = <&vreg_s3b>;
+ vdd-l12-supply = <&vreg_s3b>;
qcom,pmic-id = "f";
diff --git a/arch/arm64/boot/dts/qcom/milos-nothing-asteroids.dts b/arch/arm64/boot/dts/qcom/milos-nothing-asteroids.dts
index 7393978926e4..787acef4a4c8 100644
--- a/arch/arm64/boot/dts/qcom/milos-nothing-asteroids.dts
+++ b/arch/arm64/boot/dts/qcom/milos-nothing-asteroids.dts
@@ -25,31 +25,7 @@
};
chosen {
- #address-cells = <2>;
- #size-cells = <2>;
- ranges;
-
stdout-path = "serial0:115200n8";
-
- framebuffer0: framebuffer@e3940000 {
- compatible = "simple-framebuffer";
- reg = <0x0 0xe3940000 0x0 (2392 * 1080 * 4)>;
- width = <1080>;
- height = <2392>;
- stride = <(1080 * 4)>;
- format = "a8r8g8b8";
- panel = <&panel>;
- interconnects = <&mmss_noc MASTER_MDP QCOM_ICC_TAG_ALWAYS
- &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>;
- clocks = <&gcc GCC_DISP_HF_AXI_CLK>;
-
- /* Dummy panel for simple-framebuffer dimension info */
- panel: dummy-panel {
- compatible = "boe,bf068mwm-td0";
- height-mm = <157>;
- width-mm = <71>;
- };
- };
};
gpio-keys {
@@ -131,15 +107,6 @@
mem-type = <2>;
pmsg-size = <0x200000>;
};
-
- /*
- * ABL is powering down display and controller if this node is
- * not named exactly "splash_region".
- */
- splash_region@e3940000 {
- reg = <0x0 0xe3940000 0x0 0x2b00000>;
- no-map;
- };
};
};
@@ -507,11 +474,6 @@
};
};
-&dispcc {
- /* Disable for now so simple-framebuffer continues working */
- status = "disabled";
-};
-
&gcc {
protected-clocks = <GCC_PCIE_1_AUX_CLK>, <GCC_PCIE_1_AUX_CLK_SRC>,
<GCC_PCIE_1_CFG_AHB_CLK>, <GCC_PCIE_1_MSTR_AXI_CLK>,
diff --git a/arch/arm64/boot/dts/qcom/milos.dtsi b/arch/arm64/boot/dts/qcom/milos.dtsi
index c6594c86e86e..435d878246fa 100644
--- a/arch/arm64/boot/dts/qcom/milos.dtsi
+++ b/arch/arm64/boot/dts/qcom/milos.dtsi
@@ -2250,7 +2250,7 @@
pdc: interrupt-controller@b220000 {
compatible = "qcom,milos-pdc", "qcom,pdc";
- reg = <0x0 0x0b220000 0x0 0x30000>,
+ reg = <0x0 0x0b220000 0x0 0x10000>,
<0x0 0x174000f0 0x0 0x64>;
interrupt-parent = <&intc>;
diff --git a/arch/arm64/boot/dts/qcom/monaco-arduino-monza.dts b/arch/arm64/boot/dts/qcom/monaco-arduino-monza.dts
index 8b3ed73feb6e..7d75a5466950 100644
--- a/arch/arm64/boot/dts/qcom/monaco-arduino-monza.dts
+++ b/arch/arm64/boot/dts/qcom/monaco-arduino-monza.dts
@@ -7,10 +7,9 @@
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
+#include <dt-bindings/pwm/pwm.h>
#include <dt-bindings/sound/qcom,q6dsp-lpass-ports.h>
-#include "monaco.dtsi"
-#include "monaco-pmics.dtsi"
#include "monaco-monza-som.dtsi"
/ {
@@ -172,6 +171,26 @@
};
};
+&cci1 {
+ status = "okay";
+};
+
+&cci1_i2c1 {
+ fan_controller: fan-controller@2f {
+ compatible = "microchip,emc2305";
+ reg = <0x2f>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #pwm-cells = <3>;
+
+ fan: fan@0 {
+ reg = <0x0>;
+ pwms = <&fan_controller 26000 PWM_POLARITY_INVERTED 1>;
+ #cooling-cells = <2>;
+ };
+ };
+};
+
&ethernet0 {
phy-mode = "2500base-x";
phy-handle = <&hsgmii_phy0>;
@@ -425,6 +444,27 @@
reset-gpios = <&tlmm 23 GPIO_ACTIVE_LOW>;
};
+&thermal_zones {
+ cpuss-0-0-thermal {
+ polling-delay = <2000>;
+
+ trips {
+ cpuss0_active: cpuss-active {
+ temperature = <32000>;
+ hysteresis = <2000>;
+ type = "active";
+ };
+ };
+
+ cooling-maps {
+ map-active {
+ trip = <&cpuss0_active>;
+ cooling-device = <&fan 0 THERMAL_NO_LIMIT>;
+ };
+ };
+ };
+};
+
&tlmm {
pcie0_default_state: pcie0-default-state {
wake-pins {
diff --git a/arch/arm64/boot/dts/qcom/monaco.dtsi b/arch/arm64/boot/dts/qcom/monaco.dtsi
index e0243901abe9..64fc0d592282 100644
--- a/arch/arm64/boot/dts/qcom/monaco.dtsi
+++ b/arch/arm64/boot/dts/qcom/monaco.dtsi
@@ -310,16 +310,6 @@
little_cpu_sleep_0: cpu-sleep-0-0 {
compatible = "arm,idle-state";
- idle-state-name = "silver-power-collapse";
- arm,psci-suspend-param = <0x40000003>;
- entry-latency-us = <449>;
- exit-latency-us = <801>;
- min-residency-us = <1574>;
- local-timer-stop;
- };
-
- little_cpu_sleep_1: cpu-sleep-0-1 {
- compatible = "arm,idle-state";
idle-state-name = "silver-rail-power-collapse";
arm,psci-suspend-param = <0x40000004>;
entry-latency-us = <602>;
@@ -330,16 +320,6 @@
big_cpu_sleep_0: cpu-sleep-1-0 {
compatible = "arm,idle-state";
- idle-state-name = "gold-power-collapse";
- arm,psci-suspend-param = <0x40000003>;
- entry-latency-us = <549>;
- exit-latency-us = <901>;
- min-residency-us = <1774>;
- local-timer-stop;
- };
-
- big_cpu_sleep_1: cpu-sleep-1-1 {
- compatible = "arm,idle-state";
idle-state-name = "gold-rail-power-collapse";
arm,psci-suspend-param = <0x40000004>;
entry-latency-us = <702>;
@@ -681,49 +661,49 @@
cpu_pd0: power-domain-cpu0 {
#power-domain-cells = <0>;
power-domains = <&cluster_pd0>;
- domain-idle-states = <&big_cpu_sleep_0 &big_cpu_sleep_1>;
+ domain-idle-states = <&big_cpu_sleep_0>;
};
cpu_pd1: power-domain-cpu1 {
#power-domain-cells = <0>;
power-domains = <&cluster_pd0>;
- domain-idle-states = <&big_cpu_sleep_0 &big_cpu_sleep_1>;
+ domain-idle-states = <&big_cpu_sleep_0>;
};
cpu_pd2: power-domain-cpu2 {
#power-domain-cells = <0>;
power-domains = <&cluster_pd0>;
- domain-idle-states = <&big_cpu_sleep_0 &big_cpu_sleep_1>;
+ domain-idle-states = <&big_cpu_sleep_0>;
};
cpu_pd3: power-domain-cpu3 {
#power-domain-cells = <0>;
power-domains = <&cluster_pd0>;
- domain-idle-states = <&big_cpu_sleep_0 &big_cpu_sleep_1>;
+ domain-idle-states = <&big_cpu_sleep_0>;
};
cpu_pd4: power-domain-cpu4 {
#power-domain-cells = <0>;
power-domains = <&cluster_pd1>;
- domain-idle-states = <&little_cpu_sleep_0 &little_cpu_sleep_1>;
+ domain-idle-states = <&little_cpu_sleep_0>;
};
cpu_pd5: power-domain-cpu5 {
#power-domain-cells = <0>;
power-domains = <&cluster_pd1>;
- domain-idle-states = <&little_cpu_sleep_0 &little_cpu_sleep_1>;
+ domain-idle-states = <&little_cpu_sleep_0>;
};
cpu_pd6: power-domain-cpu6 {
#power-domain-cells = <0>;
power-domains = <&cluster_pd1>;
- domain-idle-states = <&little_cpu_sleep_0 &little_cpu_sleep_1>;
+ domain-idle-states = <&little_cpu_sleep_0>;
};
cpu_pd7: power-domain-cpu7 {
#power-domain-cells = <0>;
power-domains = <&cluster_pd1>;
- domain-idle-states = <&little_cpu_sleep_0 &little_cpu_sleep_1>;
+ domain-idle-states = <&little_cpu_sleep_0>;
};
cluster_pd0: power-domain-cluster0 {
@@ -2927,7 +2907,7 @@
};
};
- lpi_i2s4_active: lpi_i2s4-active-state {
+ lpi_i2s4_active: lpi-i2s4-active-state {
data0-pins {
pins = "gpio17";
function = "i2s4_data";
@@ -6106,7 +6086,7 @@
pdc: interrupt-controller@b220000 {
compatible = "qcom,qcs8300-pdc", "qcom,pdc";
- reg = <0x0 0xb220000 0x0 0x30000>,
+ reg = <0x0 0xb220000 0x0 0x10000>,
<0x0 0x17c000f0 0x0 0x64>;
interrupt-parent = <&intc>;
#interrupt-cells = <2>;
diff --git a/arch/arm64/boot/dts/qcom/msm8996-xiaomi-gemini.dts b/arch/arm64/boot/dts/qcom/msm8996-xiaomi-gemini.dts
index fd3a2121465b..ca22e2f9d20a 100644
--- a/arch/arm64/boot/dts/qcom/msm8996-xiaomi-gemini.dts
+++ b/arch/arm64/boot/dts/qcom/msm8996-xiaomi-gemini.dts
@@ -39,7 +39,7 @@
haptics: drv2604@5a {
compatible = "ti,drv2604";
reg = <0x5a>;
- enable-gpio = <&tlmm 93 0x00>;
+ enable-gpios = <&tlmm 93 GPIO_ACTIVE_HIGH>;
mode = <DRV260X_LRA_MODE>;
library-sel = <DRV260X_LIB_LRA>;
pinctrl-names = "default","sleep";
diff --git a/arch/arm64/boot/dts/qcom/msm8996.dtsi b/arch/arm64/boot/dts/qcom/msm8996.dtsi
index 2f67e665996f..818e5660df91 100644
--- a/arch/arm64/boot/dts/qcom/msm8996.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8996.dtsi
@@ -1632,6 +1632,30 @@
/* Sleep state for BLSP2_I2C5 is missing.. */
+ blsp2_spi5_default: blsp2-spi5-default-state {
+ spi-pins {
+ pins = "gpio58", "gpio59", "gpio61";
+ function = "blsp_spi11";
+ drive-strength = <12>;
+ bias-disable;
+ };
+
+ cs-pins {
+ pins = "gpio60";
+ function = "blsp_spi11";
+ drive-strength = <16>;
+ bias-disable;
+ output-high;
+ };
+ };
+
+ blsp2_spi5_sleep: blsp2-spi5-sleep-state {
+ pins = "gpio58", "gpio59", "gpio60", "gpio61";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
cdc_reset_active: cdc-reset-active-state {
pins = "gpio64";
function = "gpio";
@@ -3433,6 +3457,23 @@
status = "disabled";
};
+ blsp2_spi5: spi@75b9000 {
+ compatible = "qcom,spi-qup-v2.2.1";
+ reg = <0x75b9000 0x600>;
+ interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc GCC_BLSP2_QUP5_SPI_APPS_CLK>,
+ <&gcc GCC_BLSP2_AHB_CLK>;
+ clock-names = "core", "iface";
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&blsp2_spi5_default>;
+ pinctrl-1 = <&blsp2_spi5_sleep>;
+ dmas = <&blsp2_dma 20>, <&blsp2_dma 21>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
blsp2_i2c6: i2c@75ba000 {
compatible = "qcom,i2c-qup-v2.2.1";
reg = <0x75ba000 0x1000>;
diff --git a/arch/arm64/boot/dts/qcom/pm7550-eliza.dtsi b/arch/arm64/boot/dts/qcom/pm7550-eliza.dtsi
new file mode 100644
index 000000000000..9b907f69264b
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/pm7550-eliza.dtsi
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2026 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/spmi/spmi.h>
+
+/ {
+ thermal-zones {
+ pm7550-thermal {
+ polling-delay-passive = <100>;
+
+ thermal-sensors = <&pm7550_temp_alarm>;
+
+ trips {
+ trip0 {
+ temperature = <95000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+
+ trip1 {
+ /*
+ * Current Linux driver currently only supports up to
+ * 125°C, should be updated to 145°C once available.
+ */
+ temperature = <125000>;
+ hysteresis = <0>;
+ type = "critical";
+ };
+ };
+ };
+ };
+};
+
+&spmi_bus0 {
+ pm7550: pmic@1 {
+ compatible = "qcom,pm7550", "qcom,spmi-pmic";
+ reg = <1 SPMI_USID>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pm7550_temp_alarm: temp-alarm@a00 {
+ compatible = "qcom,spmi-temp-alarm";
+ reg = <0xa00>;
+ interrupts = <0x1 0xa 0x0 IRQ_TYPE_EDGE_BOTH>;
+ #thermal-sensor-cells = <0>;
+ };
+
+ pm7550_gpios: gpio@8800 {
+ compatible = "qcom,pm7550-gpio", "qcom,spmi-gpio";
+ reg = <0x8800>;
+ gpio-controller;
+ gpio-ranges = <&pm7550_gpios 0 0 12>;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/pm8550vs-d-eliza.dtsi b/arch/arm64/boot/dts/qcom/pm8550vs-d-eliza.dtsi
new file mode 100644
index 000000000000..548d2aa83962
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/pm8550vs-d-eliza.dtsi
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2026 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/spmi/spmi.h>
+
+/ {
+ thermal-zones {
+ pm8550vs-d-thermal {
+ polling-delay-passive = <100>;
+
+ thermal-sensors = <&pm8550vs_d_temp_alarm>;
+
+ trips {
+ trip0 {
+ temperature = <95000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+
+ trip1 {
+ temperature = <115000>;
+ hysteresis = <0>;
+ type = "hot";
+ };
+
+ trip2 {
+ temperature = <145000>;
+ hysteresis = <0>;
+ type = "critical";
+ };
+ };
+ };
+ };
+};
+
+&spmi_bus0 {
+ pm8550vs_d: pmic@3 {
+ compatible = "qcom,pm8550vs", "qcom,spmi-pmic";
+ reg = <3 SPMI_USID>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pm8550vs_d_temp_alarm: temp-alarm@a00 {
+ compatible = "qcom,spmi-temp-alarm";
+ reg = <0xa00>;
+ interrupts = <0x3 0xa 0x0 IRQ_TYPE_EDGE_BOTH>;
+ #thermal-sensor-cells = <0>;
+ };
+
+ pm8550vs_d_gpios: gpio@8800 {
+ compatible = "qcom,pm8550vs-gpio", "qcom,spmi-gpio";
+ reg = <0x8800>;
+ gpio-controller;
+ gpio-ranges = <&pm8550vs_d_gpios 0 0 6>;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/pm8550vs-g-eliza.dtsi b/arch/arm64/boot/dts/qcom/pm8550vs-g-eliza.dtsi
new file mode 100644
index 000000000000..4ad2cd189a6c
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/pm8550vs-g-eliza.dtsi
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2026 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/spmi/spmi.h>
+
+/ {
+ thermal-zones {
+ pm8550vs-g-thermal {
+ polling-delay-passive = <100>;
+
+ thermal-sensors = <&pm8550vs_g_temp_alarm>;
+
+ trips {
+ trip0 {
+ temperature = <95000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+
+ trip1 {
+ temperature = <115000>;
+ hysteresis = <0>;
+ type = "hot";
+ };
+
+ trip2 {
+ temperature = <145000>;
+ hysteresis = <0>;
+ type = "critical";
+ };
+ };
+ };
+ };
+};
+
+&spmi_bus0 {
+ pm8550vs_g: pmic@6 {
+ compatible = "qcom,pm8550vs", "qcom,spmi-pmic";
+ reg = <6 SPMI_USID>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pm8550vs_g_temp_alarm: temp-alarm@a00 {
+ compatible = "qcom,spmi-temp-alarm";
+ reg = <0xa00>;
+ interrupts = <0x6 0xa 0x0 IRQ_TYPE_EDGE_BOTH>;
+ #thermal-sensor-cells = <0>;
+ };
+
+ pm8550vs_g_gpios: gpio@8800 {
+ compatible = "qcom,pm8550vs-gpio", "qcom,spmi-gpio";
+ reg = <0x8800>;
+ gpio-controller;
+ gpio-ranges = <&pm8550vs_g_gpios 0 0 6>;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/pmk8550-eliza.dtsi b/arch/arm64/boot/dts/qcom/pmk8550-eliza.dtsi
new file mode 100644
index 000000000000..e0ff4ff9c469
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/pmk8550-eliza.dtsi
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2026 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/spmi/spmi.h>
+
+/ {
+ reboot-mode {
+ compatible = "nvmem-reboot-mode";
+ nvmem-cells = <&reboot_reason>;
+ nvmem-cell-names = "reboot-mode";
+ mode-recovery = <0x01>;
+ mode-bootloader = <0x02>;
+ };
+};
+
+&spmi_bus0 {
+ pmk8550: pmic@0 {
+ compatible = "qcom,pm8550", "qcom,spmi-pmic";
+ reg = <0x0 SPMI_USID>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pmk8550_pon: pon@1300 {
+ compatible = "qcom,pmk8350-pon";
+ reg = <0x1300>, <0x800>;
+ reg-names = "hlos", "pbs";
+
+ pon_pwrkey: pwrkey {
+ compatible = "qcom,pmk8350-pwrkey";
+ interrupts = <0x0 0x13 0x7 IRQ_TYPE_EDGE_BOTH>;
+ linux,code = <KEY_POWER>;
+ status = "disabled";
+ };
+
+ pon_resin: resin {
+ compatible = "qcom,pmk8350-resin";
+ interrupts = <0x0 0x13 0x6 IRQ_TYPE_EDGE_BOTH>;
+ status = "disabled";
+ };
+ };
+
+ pmk8550_rtc: rtc@6100 {
+ compatible = "qcom,pmk8350-rtc";
+ reg = <0x6100>, <0x6200>;
+ reg-names = "rtc", "alarm";
+ interrupts = <0x0 0x62 0x1 IRQ_TYPE_EDGE_RISING>;
+ };
+
+ pmk8550_sdam_2: nvram@7100 {
+ compatible = "qcom,spmi-sdam";
+ reg = <0x7100>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x7100 0x100>;
+
+ reboot_reason: reboot-reason@48 {
+ reg = <0x48 0x1>;
+ bits = <1 7>;
+ };
+ };
+
+ pmk8550_gpios: gpio@b800 {
+ compatible = "qcom,pmk8550-gpio", "qcom,spmi-gpio";
+ reg = <0xb800>;
+ gpio-controller;
+ gpio-ranges = <&pmk8550_gpios 0 0 6>;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ pmk8550_pwm: pwm {
+ compatible = "qcom,pmk8550-pwm";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #pwm-cells = <2>;
+
+ status = "disabled";
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/pmr735d-eliza.dtsi b/arch/arm64/boot/dts/qcom/pmr735d-eliza.dtsi
new file mode 100644
index 000000000000..1c29d8ddea65
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/pmr735d-eliza.dtsi
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2026 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/spmi/spmi.h>
+
+/ {
+ thermal-zones {
+ pmr735d-thermal {
+ polling-delay-passive = <100>;
+
+ thermal-sensors = <&pmr735d_temp_alarm>;
+
+ trips {
+ trip0 {
+ temperature = <95000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+
+ trip1 {
+ temperature = <115000>;
+ hysteresis = <0>;
+ type = "hot";
+ };
+
+ trip2 {
+ temperature = <145000>;
+ hysteresis = <0>;
+ type = "critical";
+ };
+ };
+ };
+ };
+};
+
+&spmi_bus0 {
+ pmr735d: pmic@a {
+ compatible = "qcom,pmr735d", "qcom,spmi-pmic";
+ reg = <0xa SPMI_USID>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pmr735d_temp_alarm: temp-alarm@a00 {
+ compatible = "qcom,spmi-temp-alarm";
+ reg = <0xa00>;
+ interrupts = <0xa 0xa 0x0 IRQ_TYPE_EDGE_BOTH>;
+ #thermal-sensor-cells = <0>;
+ };
+
+ pmr735d_gpios: gpio@8800 {
+ compatible = "qcom,pmr735d-gpio", "qcom,spmi-gpio";
+ reg = <0x8800>;
+ gpio-controller;
+ gpio-ranges = <&pmr735d_gpios 0 0 2>;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/purwa.dtsi b/arch/arm64/boot/dts/qcom/purwa.dtsi
index 5b17840fb62f..3d73d1211cd0 100644
--- a/arch/arm64/boot/dts/qcom/purwa.dtsi
+++ b/arch/arm64/boot/dts/qcom/purwa.dtsi
@@ -6,6 +6,8 @@
/* X1P42100 is heavily based on hamoa, with some meaningful differences */
#include "hamoa.dtsi"
+#include <dt-bindings/clock/qcom,x1p42100-videocc.h>
+
/delete-node/ &bwmon_cluster0;
/delete-node/ &cluster_pd2;
/delete-node/ &cpu_map_cluster2;
@@ -36,6 +38,10 @@
/delete-node/ &thermal_gpuss_6;
/delete-node/ &thermal_gpuss_7;
+&camcc {
+ compatible = "qcom,x1p42100-camcc";
+};
+
&gcc {
compatible = "qcom,x1p42100-gcc", "qcom,x1e80100-gcc";
};
@@ -258,3 +264,7 @@
&tsens3 {
status = "disabled";
};
+
+&videocc {
+ compatible = "qcom,x1p42100-videocc";
+};
diff --git a/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts b/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts
index aa7c525237b9..f072bd96c7d4 100644
--- a/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts
+++ b/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts
@@ -40,9 +40,9 @@
#size-cells = <2>;
ranges;
- framebuffer0: framebuffer@a000000 {
+ framebuffer {
compatible = "simple-framebuffer";
- reg = <0x0 0xe1000000 0x0 (2700 * 1224 * 4)>;
+ memory-region = <&cont_splash_mem>;
width = <1224>;
height = <2700>;
stride = <(1224 * 4)>;
@@ -866,8 +866,33 @@
&i2c2 {
status = "okay";
- /* AW88261FCR amplifier @ 34 */
- /* AW88261FCR amplifier @ 35 */
+ /* Top speaker / ear speaker */
+ aw88261_l: audio-codec@34 {
+ compatible = "awinic,aw88261";
+ reg = <0x34>;
+
+ dvdd-supply = <&vreg_l18b>;
+ sound-name-prefix = "Amplifier L";
+ firmware-name = "qcom/qcm6490/fairphone5/aw88261_acf.bin";
+
+ awinic,audio-channel = <0>;
+
+ #sound-dai-cells = <0>;
+ };
+
+ /* Bottom speaker */
+ aw88261_r: audio-codec@35 {
+ compatible = "awinic,aw88261";
+ reg = <0x35>;
+
+ dvdd-supply = <&vreg_l18b>;
+ sound-name-prefix = "Amplifier R";
+ firmware-name = "qcom/qcm6490/fairphone5/aw88261_acf.bin";
+
+ awinic,audio-channel = <1>;
+
+ #sound-dai-cells = <0>;
+ };
};
&i2c4 {
@@ -1160,6 +1185,13 @@
status = "okay";
};
+&q6afedai {
+ dai@127 {
+ reg = <QUINARY_MI2S_RX>;
+ qcom,sd-lines = <0>;
+ };
+};
+
&qup_spi13_cs {
drive-strength = <6>;
bias-disable;
@@ -1237,6 +1269,11 @@
compatible = "fairphone,fp5-sndcard";
model = "Fairphone 5";
+ pinctrl-0 = <&lpass_i2s1_active>;
+ pinctrl-1 = <&lpass_i2s1_sleep>;
+ pinctrl-names = "default",
+ "sleep";
+
mm1-dai-link {
link-name = "MultiMedia1";
@@ -1245,6 +1282,22 @@
};
};
+ i2s-dai-link {
+ link-name = "Quinary MI2S Playback";
+
+ codec {
+ sound-dai = <&aw88261_l>, <&aw88261_r>;
+ };
+
+ cpu {
+ sound-dai = <&q6afedai QUINARY_MI2S_RX>;
+ };
+
+ platform {
+ sound-dai = <&q6routing>;
+ };
+ };
+
displayport-rx-dai-link {
link-name = "DisplayPort Playback";
diff --git a/arch/arm64/boot/dts/qcom/qcm6490-particle-tachyon.dts b/arch/arm64/boot/dts/qcom/qcm6490-particle-tachyon.dts
index fef9fb51642d..94eebb7de7b9 100644
--- a/arch/arm64/boot/dts/qcom/qcm6490-particle-tachyon.dts
+++ b/arch/arm64/boot/dts/qcom/qcm6490-particle-tachyon.dts
@@ -543,9 +543,6 @@
};
&pcie0 {
- perst-gpios = <&tlmm 87 GPIO_ACTIVE_LOW>;
- wake-gpios = <&tlmm 89 GPIO_ACTIVE_HIGH>;
-
pinctrl-0 = <&pcie0_reset_n>, <&pcie0_wake_n>, <&pcie0_clkreq_n>;
pinctrl-names = "default";
@@ -559,9 +556,12 @@
status = "okay";
};
-&pcie1 {
- perst-gpios = <&tlmm 2 GPIO_ACTIVE_LOW>;
+&pcie0_port {
+ reset-gpios = <&tlmm 87 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 89 GPIO_ACTIVE_HIGH>;
+};
+&pcie1 {
pinctrl-0 = <&pcie1_reset_n>, <&pcie1_wake_n>, <&pcie1_clkreq_n>;
pinctrl-names = "default";
@@ -577,6 +577,10 @@
status = "okay";
};
+&pcie1_port0 {
+ reset-gpios = <&tlmm 2 GPIO_ACTIVE_LOW>;
+};
+
&pmk8350_adc_tm {
status = "okay";
diff --git a/arch/arm64/boot/dts/qcom/qcm6490-shift-otter.dts b/arch/arm64/boot/dts/qcom/qcm6490-shift-otter.dts
index 1398a4dfb037..e5366cfd3a02 100644
--- a/arch/arm64/boot/dts/qcom/qcm6490-shift-otter.dts
+++ b/arch/arm64/boot/dts/qcom/qcm6490-shift-otter.dts
@@ -39,9 +39,9 @@
stdout-path = "serial0:115200n8";
- framebuffer0: framebuffer@a000000 {
+ framebuffer {
compatible = "simple-framebuffer";
- reg = <0x0 0xe1000000 0x0 (2400 * 1080 * 4)>;
+ memory-region = <&cont_splash_mem>;
width = <1080>;
height = <2400>;
stride = <(1080 * 4)>;
diff --git a/arch/arm64/boot/dts/qcom/qcs615-ride.dts b/arch/arm64/boot/dts/qcom/qcs615-ride.dts
index 51b13b492472..047b4efb04b9 100644
--- a/arch/arm64/boot/dts/qcom/qcs615-ride.dts
+++ b/arch/arm64/boot/dts/qcom/qcs615-ride.dts
@@ -232,8 +232,8 @@
vreg_l2a: ldo2 {
regulator-name = "vreg_l2a";
- regulator-min-microvolt = <1650000>;
- regulator-max-microvolt = <3100000>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2960000>;
regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>;
regulator-allow-set-load;
regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
@@ -599,7 +599,7 @@
cd-gpios = <&tlmm 99 GPIO_ACTIVE_LOW>;
vmmc-supply = <&vreg_l10a>;
- vqmmc-supply = <&vreg_s4a>;
+ vqmmc-supply = <&vreg_l2a>;
status = "okay";
};
diff --git a/arch/arm64/boot/dts/qcom/qcs6490-radxa-dragon-q6a.dts b/arch/arm64/boot/dts/qcom/qcs6490-radxa-dragon-q6a.dts
index 6c1a73f18ec1..82ebd88f9aba 100644
--- a/arch/arm64/boot/dts/qcom/qcs6490-radxa-dragon-q6a.dts
+++ b/arch/arm64/boot/dts/qcom/qcs6490-radxa-dragon-q6a.dts
@@ -526,9 +526,6 @@
};
&pcie0 {
- perst-gpios = <&tlmm 87 GPIO_ACTIVE_LOW>;
- wake-gpios = <&tlmm 89 GPIO_ACTIVE_HIGH>;
-
pinctrl-0 = <&pcie0_clkreq_n>, <&pcie0_reset_n>, <&pcie0_wake_n>;
pinctrl-names = "default";
@@ -542,10 +539,12 @@
status = "okay";
};
-&pcie1 {
- perst-gpios = <&tlmm 2 GPIO_ACTIVE_LOW>;
- wake-gpios = <&tlmm 3 GPIO_ACTIVE_HIGH>;
+&pcie0_port {
+ reset-gpios = <&tlmm 87 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 89 GPIO_ACTIVE_HIGH>;
+};
+&pcie1 {
pinctrl-0 = <&pcie1_clkreq_n>, <&pcie1_reset_n>, <&pcie1_wake_n>;
pinctrl-names = "default";
@@ -570,6 +569,11 @@
status = "okay";
};
+&pcie1_port0 {
+ reset-gpios = <&tlmm 2 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 3 GPIO_ACTIVE_HIGH>;
+};
+
&pm7325_gpios {
pm7325_adc_default: adc-default-state {
pins = "gpio2";
diff --git a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts
index 9c24802e476e..e9a932c90d14 100644
--- a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts
+++ b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts
@@ -841,8 +841,6 @@
};
&pcie1 {
- perst-gpios = <&tlmm 2 GPIO_ACTIVE_LOW>;
-
pinctrl-0 = <&pcie1_reset_n>, <&pcie1_wake_n>, <&pcie1_clkreq_n>;
pinctrl-names = "default";
@@ -867,6 +865,8 @@
};
&pcie1_port0 {
+ reset-gpios = <&tlmm 2 GPIO_ACTIVE_LOW>;
+
pcie@0,0 {
compatible = "pci1179,0623";
reg = <0x10000 0x0 0x0 0x0 0x0>;
diff --git a/arch/arm64/boot/dts/qcom/qcs6490-thundercomm-minipc-g1iot.dts b/arch/arm64/boot/dts/qcom/qcs6490-thundercomm-minipc-g1iot.dts
index 7de63ee37a84..c8eed8ba93f5 100644
--- a/arch/arm64/boot/dts/qcom/qcs6490-thundercomm-minipc-g1iot.dts
+++ b/arch/arm64/boot/dts/qcom/qcs6490-thundercomm-minipc-g1iot.dts
@@ -688,9 +688,6 @@
};
&pcie0 {
- perst-gpios = <&tlmm 87 GPIO_ACTIVE_LOW>;
- wake-gpios = <&tlmm 89 GPIO_ACTIVE_HIGH>;
-
pinctrl-0 = <&pcie0_clkreq_n>,
<&pcie0_reset_n>,
<&pcie0_wake_n>;
@@ -706,10 +703,12 @@
status = "okay";
};
-&pcie1 {
- perst-gpios = <&tlmm 2 GPIO_ACTIVE_LOW>;
- wake-gpios = <&tlmm 3 GPIO_ACTIVE_HIGH>;
+&pcie0_port {
+ reset-gpios = <&tlmm 87 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 89 GPIO_ACTIVE_HIGH>;
+};
+&pcie1 {
pinctrl-0 = <&pcie1_clkreq_n>,
<&pcie1_reset_n>,
<&pcie1_wake_n>;
@@ -736,6 +735,9 @@
};
&pcie1_port0 {
+ reset-gpios = <&tlmm 2 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 3 GPIO_ACTIVE_HIGH>;
+
pcie@0,0 {
compatible = "pci1179,0623";
reg = <0x10000 0x0 0x0 0x0 0x0>;
diff --git a/arch/arm64/boot/dts/qcom/qcs6490-thundercomm-rubikpi3.dts b/arch/arm64/boot/dts/qcom/qcs6490-thundercomm-rubikpi3.dts
index e701cc39210f..d8a9a7e47bdc 100644
--- a/arch/arm64/boot/dts/qcom/qcs6490-thundercomm-rubikpi3.dts
+++ b/arch/arm64/boot/dts/qcom/qcs6490-thundercomm-rubikpi3.dts
@@ -816,9 +816,6 @@
};
&pcie0 {
- perst-gpios = <&tlmm 87 GPIO_ACTIVE_LOW>;
- wake-gpios = <&tlmm 89 GPIO_ACTIVE_HIGH>;
-
pinctrl-0 = <&pcie0_clkreq_n>,
<&pcie0_reset_n>,
<&pcie0_wake_n>;
@@ -834,10 +831,12 @@
status = "okay";
};
-&pcie1 {
- perst-gpios = <&tlmm 2 GPIO_ACTIVE_LOW>;
- wake-gpios = <&tlmm 3 GPIO_ACTIVE_LOW>;
+&pcie0_port {
+ reset-gpios = <&tlmm 87 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 89 GPIO_ACTIVE_HIGH>;
+};
+&pcie1 {
pinctrl-0 = <&pcie1_clkreq_n>,
<&pcie1_reset_n>,
<&pcie1_wake_n>;
@@ -853,6 +852,11 @@
status = "okay";
};
+&pcie1_port0 {
+ reset-gpios = <&tlmm 2 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 3 GPIO_ACTIVE_LOW>;
+};
+
&pm7325_gpios {
kypd_vol_up_n: kypd-vol-up-n-state {
pins = "gpio6";
diff --git a/arch/arm64/boot/dts/qcom/qdu1000.dtsi b/arch/arm64/boot/dts/qcom/qdu1000.dtsi
index 952d4270d118..26cc86d12f72 100644
--- a/arch/arm64/boot/dts/qcom/qdu1000.dtsi
+++ b/arch/arm64/boot/dts/qcom/qdu1000.dtsi
@@ -1054,7 +1054,7 @@
pdc: interrupt-controller@b220000 {
compatible = "qcom,qdu1000-pdc", "qcom,pdc";
- reg = <0x0 0xb220000 0x0 0x30000>, <0x0 0x174000f0 0x0 0x64>;
+ reg = <0x0 0xb220000 0x0 0x10000>, <0x0 0x174000f0 0x0 0x64>;
qcom,pdc-ranges = <0 480 12>, <14 494 24>, <40 520 54>,
<94 609 31>, <125 63 1>;
#interrupt-cells = <2>;
diff --git a/arch/arm64/boot/dts/qcom/qrb2210-rb1-vision-mezzanine.dtso b/arch/arm64/boot/dts/qcom/qrb2210-rb1-vision-mezzanine.dtso
index c314cd6dd484..f5e6021a3354 100644
--- a/arch/arm64/boot/dts/qcom/qrb2210-rb1-vision-mezzanine.dtso
+++ b/arch/arm64/boot/dts/qcom/qrb2210-rb1-vision-mezzanine.dtso
@@ -60,7 +60,7 @@
link-frequencies = /bits/ 64 <400000000>;
data-lanes = <1 2>;
remote-endpoint = <&csiphy0_ep>;
- };
- };
+ };
+ };
};
};
diff --git a/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts b/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts
index 22baee407fbe..9b05f6d843cf 100644
--- a/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts
+++ b/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts
@@ -741,6 +741,12 @@
remote-endpoint = <&pmi632_ss_in>;
};
+&venus {
+ firmware-name = "qcom/venus-6.0/venus.mbn";
+
+ status = "okay";
+};
+
&wifi {
/* SoC */
vdd-0.8-cx-mx-supply = <&vreg_l8a_0p664>;
diff --git a/arch/arm64/boot/dts/qcom/sar2130p.dtsi b/arch/arm64/boot/dts/qcom/sar2130p.dtsi
index 3c9529bb2f76..767f7cc218f1 100644
--- a/arch/arm64/boot/dts/qcom/sar2130p.dtsi
+++ b/arch/arm64/boot/dts/qcom/sar2130p.dtsi
@@ -2417,7 +2417,7 @@
pdc: interrupt-controller@b220000 {
compatible = "qcom,sar2130p-pdc", "qcom,pdc";
- reg = <0x0 0x0b220000 0x0 0x30000>, <0x0 0x174000f0 0x0 0x64>;
+ reg = <0x0 0x0b220000 0x0 0x10000>, <0x0 0x174000f0 0x0 0x64>;
qcom,pdc-ranges = <0 480 94>,
<94 609 31>,
<125 63 1>,
diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi
index b398f69917f0..cd4a0e281cf8 100644
--- a/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi
@@ -99,6 +99,11 @@
stdout-path = "serial0:115200n8";
};
+ firmware {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ };
+
/* FIXED REGULATORS - parents above children */
/* This is the top level supply and variable voltage */
diff --git a/arch/arm64/boot/dts/qcom/sc7180.dtsi b/arch/arm64/boot/dts/qcom/sc7180.dtsi
index fa65c485172f..18f9cb82639a 100644
--- a/arch/arm64/boot/dts/qcom/sc7180.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7180.dtsi
@@ -3514,7 +3514,7 @@
pdc: interrupt-controller@b220000 {
compatible = "qcom,sc7180-pdc", "qcom,pdc";
- reg = <0 0x0b220000 0 0x30000>;
+ reg = <0 0x0b220000 0 0x10000>;
qcom,pdc-ranges = <0 480 94>, <94 609 31>, <125 63 1>;
#interrupt-cells = <2>;
interrupt-parent = <&intc>;
diff --git a/arch/arm64/boot/dts/qcom/sc7280-herobrine.dtsi b/arch/arm64/boot/dts/qcom/sc7280-herobrine.dtsi
index 5c5e4f1dd221..58ea0532c0fb 100644
--- a/arch/arm64/boot/dts/qcom/sc7280-herobrine.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7280-herobrine.dtsi
@@ -25,6 +25,11 @@
stdout-path = "serial0:115200n8";
};
+ firmware {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ };
+
/*
* FIXED REGULATORS
*
diff --git a/arch/arm64/boot/dts/qcom/sc7280-idp.dtsi b/arch/arm64/boot/dts/qcom/sc7280-idp.dtsi
index 8cac4ce9c851..6bb806931b79 100644
--- a/arch/arm64/boot/dts/qcom/sc7280-idp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7280-idp.dtsi
@@ -418,7 +418,6 @@
&pcie1 {
status = "okay";
- perst-gpios = <&tlmm 2 GPIO_ACTIVE_LOW>;
vddpe-3v3-supply = <&nvme_3v3_regulator>;
@@ -433,6 +432,10 @@
vdda-pll-supply = <&vreg_l6b_1p2>;
};
+&pcie1_port0 {
+ reset-gpios = <&tlmm 2 GPIO_ACTIVE_LOW>;
+};
+
&pmk8350_vadc {
channel@3 {
reg = <PMK8350_ADC7_DIE_TEMP>;
diff --git a/arch/arm64/boot/dts/qcom/sc8180x-lenovo-flex-5g.dts b/arch/arm64/boot/dts/qcom/sc8180x-lenovo-flex-5g.dts
index d86a31ddede2..7601afc3d7bf 100644
--- a/arch/arm64/boot/dts/qcom/sc8180x-lenovo-flex-5g.dts
+++ b/arch/arm64/boot/dts/qcom/sc8180x-lenovo-flex-5g.dts
@@ -26,6 +26,7 @@
compatible = "pwm-backlight";
pwms = <&pmc8180c_lpg 4 1000000>;
enable-gpios = <&pmc8180c_gpios 8 GPIO_ACTIVE_HIGH>;
+ power-supply = <&vled_bl_pw>;
pinctrl-0 = <&bl_pwm_default>;
pinctrl-names = "default";
@@ -157,14 +158,39 @@
};
};
- vph_pwr: vph-pwr-regulator {
+ vled_bl_pw: regulator-vled-bl-pw {
compatible = "regulator-fixed";
- regulator-name = "vph_pwr";
- regulator-min-microvolt = <3700000>;
- regulator-max-microvolt = <3700000>;
+
+ regulator-name = "VLED_BL_PW";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+
+ gpio = <&pmc8180_2_gpios 1 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+
+ pinctrl-0 = <&bl_pwr_en>;
+ pinctrl-names = "default";
+
+ regulator-boot-on;
};
- vreg_s4a_1p8: pm8150-s4-regulator {
+ vreg_lcm_3v3: regulator-edp-3p3 {
+ compatible = "regulator-fixed";
+
+ regulator-name = "VREG_LCM_3V3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+
+ gpio = <&tlmm 130 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+
+ pinctrl-0 = <&lcm_3v3_en>;
+ pinctrl-names = "default";
+
+ regulator-boot-on;
+ };
+
+ vreg_s4a_1p8: regulator-pm8150-s4 {
compatible = "regulator-fixed";
regulator-name = "vreg_s4a_1p8";
@@ -177,6 +203,13 @@
vin-supply = <&vph_pwr>;
};
+ vph_pwr: regulator-vph-pwr {
+ compatible = "regulator-fixed";
+ regulator-name = "vph_pwr";
+ regulator-min-microvolt = <3700000>;
+ regulator-max-microvolt = <3700000>;
+ };
+
usbprim-sbu-mux {
compatible = "pericom,pi3usb102", "gpio-sbu-mux";
@@ -438,6 +471,7 @@
aux-bus {
panel {
compatible = "edp-panel";
+ power-supply = <&vreg_lcm_3v3>;
no-hpd;
backlight = <&backlight>;
@@ -472,6 +506,13 @@
status = "okay";
};
+&pmc8180_2_gpios {
+ bl_pwr_en: bl-pwr-en-state {
+ pins = "gpio1";
+ function = "normal";
+ };
+};
+
&pmc8180_pwrkey {
status = "okay";
};
@@ -765,6 +806,12 @@
drive-strength = <2>;
};
+ lcm_3v3_en: lcm-3v3-en-state {
+ pins = "gpio130";
+ function = "gpio";
+ bias-disable;
+ };
+
usbprim_sbu_default: usbprim-sbu-state {
oe-n-pins {
pins = "gpio152";
diff --git a/arch/arm64/boot/dts/qcom/sc8180x-primus.dts b/arch/arm64/boot/dts/qcom/sc8180x-primus.dts
index aff398390eba..e34f4758ebe2 100644
--- a/arch/arm64/boot/dts/qcom/sc8180x-primus.dts
+++ b/arch/arm64/boot/dts/qcom/sc8180x-primus.dts
@@ -29,9 +29,10 @@
compatible = "pwm-backlight";
pwms = <&pmc8180c_lpg 4 1000000>;
enable-gpios = <&pmc8180c_gpios 8 GPIO_ACTIVE_HIGH>;
+ power-supply = <&vled_bl_pw>;
- pinctrl-names = "default";
pinctrl-0 = <&bl_pwm_default>;
+ pinctrl-names = "default";
};
chosen {
@@ -167,7 +168,39 @@
};
};
- vreg_nvme_0p9: nvme-0p9-regulator {
+ vled_bl_pw: regulator-vled-bl-pw {
+ compatible = "regulator-fixed";
+
+ regulator-name = "VLED_BL_PW";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+
+ gpio = <&pmc8180_2_gpios 1 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+
+ pinctrl-0 = <&bl_pwr_en>;
+ pinctrl-names = "default";
+
+ regulator-boot-on;
+ };
+
+ vreg_lcm_3v3: regulator-edp-3p3 {
+ compatible = "regulator-fixed";
+
+ regulator-name = "VREG_LCM_3V3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+
+ gpio = <&tlmm 130 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+
+ pinctrl-0 = <&lcm_3v3_en>;
+ pinctrl-names = "default";
+
+ regulator-boot-on;
+ };
+
+ vreg_nvme_0p9: regulator-nvme-0p9 {
compatible = "regulator-fixed";
regulator-name = "vreg_nvme_0p9";
@@ -177,7 +210,7 @@
regulator-always-on;
};
- vreg_nvme_3p3: nvme-3p3-regulator {
+ vreg_nvme_3p3: regulator-nvme-3p3 {
compatible = "regulator-fixed";
regulator-name = "vreg_nvme_3p3";
@@ -190,7 +223,7 @@
regulator-always-on;
};
- vdd_kb_tp_3v3: vdd-kb-tp-3v3-regulator {
+ vdd_kb_tp_3v3: regulator-vdd-kb-tp-3v3 {
compatible = "regulator-fixed";
regulator-name = "vdd_kb_tp_3v3";
regulator-min-microvolt = <3300000>;
@@ -205,7 +238,7 @@
pinctrl-0 = <&kb_tp_3v3_en_active_state>;
};
- vph_pwr: vph-pwr-regulator {
+ vph_pwr: regulator-vph-pwr {
compatible = "regulator-fixed";
regulator-name = "vph_pwr";
regulator-min-microvolt = <3700000>;
@@ -540,6 +573,7 @@
aux-bus {
panel {
compatible = "edp-panel";
+ power-supply = <&vreg_lcm_3v3>;
backlight = <&backlight>;
@@ -769,6 +803,12 @@
};
/* PINCTRL */
+&pmc8180_2_gpios {
+ bl_pwr_en: bl-pwr-en-state {
+ pins = "gpio1";
+ function = "normal";
+ };
+};
&pmc8180c_gpios {
bl_pwm_default: bl-pwm-default-state {
@@ -950,4 +990,10 @@
bias-pull-up;
};
};
+
+ lcm_3v3_en: lcm-3v3-en-state {
+ pins = "gpio130";
+ function = "gpio";
+ bias-disable;
+ };
};
diff --git a/arch/arm64/boot/dts/qcom/sc8180x.dtsi b/arch/arm64/boot/dts/qcom/sc8180x.dtsi
index 45391768e245..b532e33a2639 100644
--- a/arch/arm64/boot/dts/qcom/sc8180x.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc8180x.dtsi
@@ -3554,7 +3554,7 @@
pdc: interrupt-controller@b220000 {
compatible = "qcom,sc8180x-pdc", "qcom,pdc";
- reg = <0 0x0b220000 0 0x30000>;
+ reg = <0 0x0b220000 0 0x10000>;
qcom,pdc-ranges = <0 480 94>, <94 609 31>;
#interrupt-cells = <2>;
interrupt-parent = <&intc>;
diff --git a/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts b/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts
index 91ba02d28bc3..218573a97785 100644
--- a/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts
+++ b/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts
@@ -674,8 +674,9 @@
reg = <0x10>;
reset-gpios = <&tlmm 15 GPIO_ACTIVE_LOW>;
+
+ pinctrl-0 = <&cam_rgb_default>, <&cam_mclk3_default>;
pinctrl-names = "default";
- pinctrl-0 = <&cam_rgb_default>;
leds = <&privacy_led>;
led-names = "privacy";
@@ -1562,13 +1563,6 @@
};
cam_rgb_default: cam-rgb-default-state {
- mclk-pins {
- pins = "gpio17";
- function = "cam_mclk";
- drive-strength = <16>;
- bias-disable;
- };
-
sc-rgb-xshut-n-pins {
pins = "gpio15";
function = "gpio";
diff --git a/arch/arm64/boot/dts/qcom/sc8280xp-microsoft-arcata.dts b/arch/arm64/boot/dts/qcom/sc8280xp-microsoft-arcata.dts
index 3d589f05b90e..89c4ba267b07 100644
--- a/arch/arm64/boot/dts/qcom/sc8280xp-microsoft-arcata.dts
+++ b/arch/arm64/boot/dts/qcom/sc8280xp-microsoft-arcata.dts
@@ -6,6 +6,8 @@
/dts-v1/;
#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/gpio-keys.h>
+#include <dt-bindings/input/input.h>
#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
#include "sc8280xp.dtsi"
@@ -46,11 +48,56 @@
#sound-dai-cells = <1>;
};
+ backlight: backlight {
+ compatible = "pwm-backlight";
+ pwms = <&pmc8280c_lpg 3 1000000>;
+ enable-gpios = <&pmc8280_1_gpios 8 GPIO_ACTIVE_HIGH>;
+
+ pinctrl-0 = <&edp_bl_en>, <&edp_bl_pwm>;
+ pinctrl-names = "default";
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+
+ pinctrl-0 = <&hall_int_n_default>, <&vol_down_n>, <&vol_up_n>;
+ pinctrl-names = "default";
+
+ key-vol-down {
+ label = "Volume Down";
+ gpios = <&pmc8280_1_gpios 6 GPIO_ACTIVE_LOW>;
+ linux,code = <KEY_VOLUMEDOWN>;
+ debounce-interval = <15>;
+ linux,can-disable;
+ wakeup-source;
+ };
+
+ key-vol-up {
+ label = "Volume Up";
+ gpios = <&pmc8280_1_gpios 9 GPIO_ACTIVE_LOW>;
+ linux,code = <KEY_VOLUMEUP>;
+ debounce-interval = <15>;
+ linux,can-disable;
+ wakeup-source;
+ };
+
+ switch-lid {
+ label = "lid";
+ gpios = <&tlmm 180 GPIO_ACTIVE_LOW>;
+ linux,input-type = <EV_SW>;
+ linux,code = <SW_LID>;
+ wakeup-source;
+ wakeup-event-action = <EV_ACT_DEASSERTED>;
+ };
+ };
+
pmic-glink {
compatible = "qcom,sc8280xp-pmic-glink", "qcom,pmic-glink";
#address-cells = <1>;
#size-cells = <0>;
+ orientation-gpios = <&tlmm 166 GPIO_ACTIVE_HIGH>,
+ <&tlmm 49 GPIO_ACTIVE_HIGH>;
/* Left-side top port */
connector@0 {
@@ -127,6 +174,22 @@
};
};
+ vreg_edp_3p3: regulator-edp-3p3 {
+ compatible = "regulator-fixed";
+
+ regulator-name = "VREG_EDP_3P3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+
+ gpio = <&tlmm 36 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+
+ pinctrl-0 = <&edp_reg_en>;
+ pinctrl-names = "default";
+
+ regulator-boot-on;
+ };
+
vreg_nvme: regulator-nvme {
compatible = "regulator-fixed";
@@ -243,7 +306,7 @@
usb0-sbu-mux {
compatible = "pericom,pi3usb102", "gpio-sbu-mux";
- enable-gpios = <&tlmm 101 GPIO_ACTIVE_LOW>;
+ enable-gpios = <&tlmm 100 GPIO_ACTIVE_LOW>;
select-gpios = <&tlmm 164 GPIO_ACTIVE_HIGH>;
pinctrl-0 = <&usb0_sbu_default>;
@@ -277,6 +340,70 @@
};
};
};
+
+ wcn6855-pmu {
+ compatible = "qcom,wcn6855-pmu";
+
+ pinctrl-0 = <&bt_default>, <&wlan_en>;
+ pinctrl-names = "default";
+
+ wlan-enable-gpios = <&tlmm 134 GPIO_ACTIVE_HIGH>;
+ bt-enable-gpios = <&tlmm 133 GPIO_ACTIVE_HIGH>;
+ swctrl-gpios = <&tlmm 132 GPIO_ACTIVE_HIGH>;
+
+ vddio-supply = <&vreg_s10b>;
+ vddaon-supply = <&vreg_s12b>;
+ vddpmu-supply = <&vreg_s12b>;
+ vddpmumx-supply = <&vreg_s12b>;
+ vddpmucx-supply = <&vreg_s12b>;
+ vddrfa0p95-supply = <&vreg_s12b>;
+ vddrfa1p3-supply = <&vreg_s11b>;
+ vddrfa1p9-supply = <&vreg_s1c>;
+ vddpcie1p3-supply = <&vreg_s11b>;
+ vddpcie1p9-supply = <&vreg_s1c>;
+
+ regulators {
+ vreg_pmu_rfa_cmn_0p8: ldo0 {
+ regulator-name = "vreg_pmu_rfa_cmn_0p8";
+ };
+
+ vreg_pmu_aon_0p8: ldo1 {
+ regulator-name = "vreg_pmu_aon_0p8";
+ };
+
+ vreg_pmu_wlcx_0p8: ldo2 {
+ regulator-name = "vreg_pmu_wlcx_0p8";
+ };
+
+ vreg_pmu_wlmx_0p8: ldo3 {
+ regulator-name = "vreg_pmu_wlmx_0p8";
+ };
+
+ vreg_pmu_btcmx_0p8: ldo4 {
+ regulator-name = "vreg_pmu_btcmx_0p8";
+ };
+
+ vreg_pmu_pcie_1p8: ldo5 {
+ regulator-name = "vreg_pmu_pcie_1p8";
+ };
+
+ vreg_pmu_pcie_0p9: ldo6 {
+ regulator-name = "vreg_pmu_pcie_0p9";
+ };
+
+ vreg_pmu_rfa_0p8: ldo7 {
+ regulator-name = "vreg_pmu_rfa_0p8";
+ };
+
+ vreg_pmu_rfa_1p2: ldo8 {
+ regulator-name = "vreg_pmu_rfa_1p2";
+ };
+
+ vreg_pmu_rfa_1p7: ldo9 {
+ regulator-name = "vreg_pmu_rfa_1p7";
+ };
+ };
+ };
};
&apps_rsc {
@@ -303,7 +430,6 @@
regulator-min-microvolt = <1272000>;
regulator-max-microvolt = <1272000>;
regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
- regulator-always-on;
};
vreg_s12b: smps12 {
@@ -311,7 +437,6 @@
regulator-min-microvolt = <984000>;
regulator-max-microvolt = <984000>;
regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
- regulator-always-on;
};
vreg_l3b: ldo3 {
@@ -335,7 +460,6 @@
regulator-max-microvolt = <880000>;
regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
regulator-boot-on;
- regulator-always-on; // FIXME: VDD_A_EDP_0_0P9
};
};
@@ -439,10 +563,6 @@
status = "okay";
};
-&dispcc1 {
- status = "okay";
-};
-
&gpi_dma0 {
status = "okay";
};
@@ -472,7 +592,7 @@
};
&mdss0_dp0_out {
- data-lanes = <0 1>;
+ data-lanes = <0 1 2 3>;
remote-endpoint = <&usb_0_qmpphy_dp_in>;
};
@@ -481,10 +601,46 @@
};
&mdss0_dp1_out {
- data-lanes = <0 1>;
+ data-lanes = <0 1 2 3>;
remote-endpoint = <&usb_1_qmpphy_dp_in>;
};
+&mdss0_dp3 {
+ compatible = "qcom,sc8280xp-edp";
+ /delete-property/ #sound-dai-cells;
+
+ data-lanes = <0 1 2 3>;
+
+ status = "okay";
+
+ aux-bus {
+ panel {
+ compatible = "edp-panel";
+
+ backlight = <&backlight>;
+ power-supply = <&vreg_edp_3p3>;
+
+ port {
+ edp_panel_in: endpoint {
+ remote-endpoint = <&mdss0_dp3_out>;
+ };
+ };
+ };
+ };
+};
+
+&mdss0_dp3_out {
+ remote-endpoint = <&edp_panel_in>;
+};
+
+&mdss0_dp3_phy {
+ compatible = "qcom,sc8280xp-edp-phy";
+ vdda-phy-supply = <&vreg_l6b>;
+ vdda-pll-supply = <&vreg_l3b>;
+
+ status = "okay";
+};
+
&pcie2a {
vddpe-3v3-supply = <&vreg_nvme>;
@@ -546,6 +702,16 @@
compatible = "pci17cb,1103";
reg = <0x10000 0x0 0x0 0x0 0x0>;
+ vddrfacmn-supply = <&vreg_pmu_rfa_cmn_0p8>;
+ vddaon-supply = <&vreg_pmu_aon_0p8>;
+ vddwlcx-supply = <&vreg_pmu_wlcx_0p8>;
+ vddwlmx-supply = <&vreg_pmu_wlmx_0p8>;
+ vddpcie1p8-supply = <&vreg_pmu_pcie_1p8>;
+ vddpcie0p9-supply = <&vreg_pmu_pcie_0p9>;
+ vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>;
+ vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>;
+ vddrfa1p8-supply = <&vreg_pmu_rfa_1p7>;
+
qcom,calibration-variant = "MS_SP9_5G";
};
};
@@ -557,6 +723,10 @@
status = "okay";
};
+&pmc8280c_lpg {
+ status = "okay";
+};
+
&pmk8280_pon_pwrkey {
status = "okay";
};
@@ -566,20 +736,11 @@
};
&pmk8280_rtc {
- nvmem-cells = <&rtc_offset>;
- nvmem-cell-names = "offset";
+ qcom,uefi-rtc-info;
status = "okay";
};
-&pmk8280_sdam_6 {
- status = "okay";
-
- rtc_offset: rtc-offset@bc {
- reg = <0xbc 0x4>;
- };
-};
-
&qup0 {
status = "okay";
};
@@ -619,9 +780,6 @@
"VA DMIC0", "MIC BIAS1",
"VA DMIC1", "MIC BIAS1",
"VA DMIC2", "MIC BIAS3",
- "VA DMIC0", "VA MIC BIAS1",
- "VA DMIC1", "VA MIC BIAS1",
- "VA DMIC2", "VA MIC BIAS3",
"TX SWR_ADC1", "ADC2_OUTPUT";
wcd-playback-dai-link {
@@ -726,20 +884,16 @@
bluetooth {
compatible = "qcom,wcn6855-bt";
- vddio-supply = <&vreg_s10b>;
- vddbtcxmx-supply = <&vreg_s12b>;
- vddrfacmn-supply = <&vreg_s12b>;
- vddrfa0p8-supply = <&vreg_s12b>;
- vddrfa1p2-supply = <&vreg_s11b>;
- vddrfa1p7-supply = <&vreg_s1c>;
+ vddrfacmn-supply = <&vreg_pmu_rfa_cmn_0p8>;
+ vddaon-supply = <&vreg_pmu_aon_0p8>;
+ vddwlcx-supply = <&vreg_pmu_wlcx_0p8>;
+ vddwlmx-supply = <&vreg_pmu_wlmx_0p8>;
+ vddbtcmx-supply = <&vreg_pmu_btcmx_0p8>;
+ vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>;
+ vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>;
+ vddrfa1p7-supply = <&vreg_pmu_rfa_1p7>;
max-speed = <3200000>;
-
- enable-gpios = <&tlmm 133 GPIO_ACTIVE_HIGH>;
- swctrl-gpios = <&tlmm 132 GPIO_ACTIVE_HIGH>;
-
- pinctrl-0 = <&bt_default>;
- pinctrl-names = "default";
};
};
@@ -782,6 +936,7 @@
vdda-phy-supply = <&vreg_l9d>;
vdda-pll-supply = <&vreg_l4d>;
+ mode-switch;
orientation-switch;
status = "okay";
@@ -819,6 +974,7 @@
vdda-phy-supply = <&vreg_l4b>;
vdda-pll-supply = <&vreg_l3b>;
+ mode-switch;
orientation-switch;
status = "okay";
@@ -857,6 +1013,29 @@
status = "okay";
};
+&pmc8280_1_gpios {
+ edp_bl_en: edp-bl-en-state {
+ pins = "gpio8";
+ function = "normal";
+ };
+
+ vol_down_n: vol-down-n-state {
+ pins = "gpio6";
+ function = "normal";
+ power-source = <1>;
+ input-enable;
+ bias-pull-up;
+ };
+
+ vol_up_n: vol-up-n-state {
+ pins = "gpio9";
+ function = "normal";
+ power-source = <1>;
+ input-enable;
+ bias-pull-up;
+ };
+};
+
&pmc8280_2_gpios {
wwan_sw_en: wwan-sw-en-state {
pins = "gpio1";
@@ -864,6 +1043,13 @@
};
};
+&pmc8280c_gpios {
+ edp_bl_pwm: edp-bl-pwm-state {
+ pins = "gpio8";
+ function = "func1";
+ };
+};
+
&pmr735a_gpios {
hastings_reg_en: hastings-reg-en-state {
pins = "gpio1";
@@ -887,6 +1073,20 @@
};
};
+ edp_reg_en: edp-reg-en-state {
+ pins = "gpio36";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ hall_int_n_default: hall-int-n-state {
+ pins = "gpio180";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
nvme_reg_en: nvme-reg-en-state {
pins = "gpio135";
function = "gpio";
@@ -1000,7 +1200,7 @@
usb0_sbu_default: usb0-sbu-state {
oe-n-pins {
- pins = "gpio101";
+ pins = "gpio100";
function = "gpio";
bias-disable;
drive-strength = <16>;
@@ -1039,4 +1239,11 @@
bias-disable;
};
};
+
+ wlan_en: wlan-en-state {
+ pins = "gpio134";
+ function = "gpio";
+ drive-strength = <8>;
+ bias-pull-down;
+ };
};
diff --git a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi
index 97ccabb30b74..fbcfd3883bbb 100644
--- a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi
@@ -5441,7 +5441,7 @@
pdc: interrupt-controller@b220000 {
compatible = "qcom,sc8280xp-pdc", "qcom,pdc";
- reg = <0 0x0b220000 0 0x30000>, <0 0x17c000f0 0 0x60>;
+ reg = <0 0x0b220000 0 0x10000>, <0 0x17c000f0 0 0x60>;
qcom,pdc-ranges = <0 480 40>,
<40 140 14>,
<54 263 1>,
@@ -5599,6 +5599,62 @@
gpio-ranges = <&tlmm 0 0 230>;
wakeup-parent = <&pdc>;
+ cam_mclk0_default: cam-mclk0-default-state {
+ pins = "gpio119";
+ function = "cam_mclk";
+ drive-strength = <6>;
+ bias-disable;
+ };
+
+ cam_mclk1_default: cam-mclk1-default-state {
+ pins = "gpio120";
+ function = "cam_mclk";
+ drive-strength = <6>;
+ bias-disable;
+ };
+
+ cam_mclk2_default: cam-mclk2-default-state {
+ pins = "gpio16";
+ function = "cam_mclk";
+ drive-strength = <6>;
+ bias-disable;
+ };
+
+ cam_mclk3_default: cam-mclk3-default-state {
+ pins = "gpio17";
+ function = "cam_mclk";
+ drive-strength = <6>;
+ bias-disable;
+ };
+
+ cam_mclk4_default: cam-mclk4-default-state {
+ pins = "gpio6";
+ function = "cam_mclk";
+ drive-strength = <6>;
+ bias-disable;
+ };
+
+ cam_mclk5_default: cam-mclk5-default-state {
+ pins = "gpio7";
+ function = "cam_mclk";
+ drive-strength = <6>;
+ bias-disable;
+ };
+
+ cam_mclk6_default: cam-mclk6-default-state {
+ pins = "gpio33";
+ function = "cam_mclk";
+ drive-strength = <6>;
+ bias-disable;
+ };
+
+ cam_mclk7_default: cam-mclk7-default-state {
+ pins = "gpio34";
+ function = "cam_mclk";
+ drive-strength = <6>;
+ bias-disable;
+ };
+
cci0_default: cci0-default-state {
cci0_i2c0_default: cci0-i2c0-default-pins {
/* cci_i2c_sda0, cci_i2c_scl0 */
diff --git a/arch/arm64/boot/dts/qcom/sdm670-google-common.dtsi b/arch/arm64/boot/dts/qcom/sdm670-google-common.dtsi
index 0f57b915186b..b4854801a5f5 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-google-common.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-google-common.dtsi
@@ -522,6 +522,11 @@
};
};
+&lpi_tlmm {
+ /* sensor gpios are protected */
+ gpio-reserved-ranges = <0 8>, <12 6>;
+};
+
&mdss {
status = "okay";
};
diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi
index 30844b150c80..5c60ea36f04a 100644
--- a/arch/arm64/boot/dts/qcom/sdm670.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi
@@ -1646,7 +1646,7 @@
pdc: interrupt-controller@b220000 {
compatible = "qcom,sdm670-pdc", "qcom,pdc";
- reg = <0 0x0b220000 0 0x30000>;
+ reg = <0 0x0b220000 0 0x10000>;
qcom,pdc-ranges = <0 480 40>, <41 521 7>, <49 529 4>,
<54 534 24>, <79 559 15>, <94 609 15>,
<115 630 7>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-google-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-google-common.dtsi
index b2dc0327dff8..9368fd6b8751 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-google-common.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-google-common.dtsi
@@ -66,8 +66,8 @@
no-map;
};
- cdsp_mem: cdsp-mem@97D00000 {
- reg = <0 0x97D00000 0 0x800000>;
+ cdsp_mem: cdsp-mem@97d00000 {
+ reg = <0 0x97d00000 0 0x800000>;
no-map;
};
@@ -81,8 +81,8 @@
no-map;
};
- spss_mem: spss@99B00000 {
- reg = <0 0x99B00000 0 0x100000>;
+ spss_mem: spss@99b00000 {
+ reg = <0 0x99b00000 0 0x100000>;
no-map;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 13b85624c186..745ca60fc8ed 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -5105,7 +5105,7 @@
pdc_intc: interrupt-controller@b220000 {
compatible = "qcom,sdm845-pdc", "qcom,pdc";
- reg = <0 0x0b220000 0 0x30000>;
+ reg = <0 0x0b220000 0 0x10000>;
qcom,pdc-ranges = <0 480 94>, <94 609 15>, <115 630 7>;
#interrupt-cells = <2>;
interrupt-parent = <&intc>;
diff --git a/arch/arm64/boot/dts/qcom/sdx75.dtsi b/arch/arm64/boot/dts/qcom/sdx75.dtsi
index d1b61530b562..85cc9c6e6f83 100644
--- a/arch/arm64/boot/dts/qcom/sdx75.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdx75.dtsi
@@ -1100,7 +1100,7 @@
pdc: interrupt-controller@b220000 {
compatible = "qcom,sdx75-pdc", "qcom,pdc";
- reg = <0x0 0xb220000 0x0 0x30000>,
+ reg = <0x0 0xb220000 0x0 0x10000>,
<0x0 0x174000f0 0x0 0x64>;
qcom,pdc-ranges = <0 147 52>,
<52 266 32>,
diff --git a/arch/arm64/boot/dts/qcom/shikra-cqm-evk.dts b/arch/arm64/boot/dts/qcom/shikra-cqm-evk.dts
new file mode 100644
index 000000000000..0a52ab9b7a4c
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/shikra-cqm-evk.dts
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+/dts-v1/;
+
+#include "shikra-cqm-som.dtsi"
+#include "shikra-evk.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. Shikra CQM EVK";
+ compatible = "qcom,shikra-cqm-evk", "qcom,shikra-cqm-som", "qcom,shikra";
+ chassis-type = "embedded";
+
+ aliases {
+ mmc0 = &sdhc_1;
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&sdhc_1 {
+ vmmc-supply = <&pm4125_l20>;
+ vqmmc-supply = <&pm4125_l14>;
+
+ pinctrl-0 = <&sdc1_state_on>;
+ pinctrl-1 = <&sdc1_state_off>;
+ pinctrl-names = "default", "sleep";
+
+ non-removable;
+ supports-cqe;
+ no-sdio;
+ no-sd;
+
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/shikra-cqm-som.dtsi b/arch/arm64/boot/dts/qcom/shikra-cqm-som.dtsi
new file mode 100644
index 000000000000..dc3861489f64
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/shikra-cqm-som.dtsi
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
+
+#include "shikra.dtsi"
+#include "pm4125.dtsi"
+#include "pm8005.dtsi"
+
+/ {
+ gpio-keys {
+ compatible = "gpio-keys";
+ label = "gpio-keys";
+ pinctrl-0 = <&vol_up_n>;
+ pinctrl-names = "default";
+
+ key-volume-up {
+ label = "Volume Up";
+ gpios = <&pm4125_gpios 9 GPIO_ACTIVE_LOW>;
+ linux,input-type = <1>;
+ linux,code = <KEY_VOLUMEUP>;
+ wakeup-source;
+ debounce-interval = <15>;
+ linux,can-disable;
+ };
+ };
+};
+
+&pm4125_gpios {
+ vol_up_n: vol-up-n-state {
+ pins = "gpio9";
+ function = PMIC_GPIO_FUNC_NORMAL;
+ input-enable;
+ bias-pull-up;
+ power-source = <0>;
+ };
+};
+
+&pm4125_resin {
+ linux,code = <KEY_VOLUMEDOWN>;
+
+ status = "okay";
+};
+
+&pm8005_regulators {
+ status = "disabled";
+};
+
+&rpm_requests {
+ regulators {
+ compatible = "qcom,rpm-pm2250-regulators";
+
+ pm4125_s2: s2 {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ pm4125_l3: l3 {
+ regulator-min-microvolt = <624000>;
+ regulator-max-microvolt = <650000>;
+ };
+
+ pm4125_l4: l4 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2960000>;
+ };
+
+ pm4125_l5: l5 {
+ regulator-min-microvolt = <1232000>;
+ regulator-max-microvolt = <1304000>;
+ };
+
+ pm4125_l6: l6 {
+ regulator-min-microvolt = <788000>;
+ regulator-max-microvolt = <1050000>;
+ };
+
+ pm4125_l7: l7 {
+ regulator-min-microvolt = <664000>;
+ regulator-max-microvolt = <664000>;
+ };
+
+ pm4125_l8: l8 {
+ regulator-min-microvolt = <928000>;
+ regulator-max-microvolt = <1000000>;
+ };
+
+ pm4125_l9: l9 {
+ regulator-min-microvolt = <875000>;
+ regulator-max-microvolt = <1000000>;
+ };
+
+ pm4125_l10: l10 {
+ regulator-min-microvolt = <1304000>;
+ regulator-max-microvolt = <1304000>;
+ };
+
+ pm4125_l12: l12 {
+ regulator-min-microvolt = <928000>;
+ regulator-max-microvolt = <975000>;
+ };
+
+ pm4125_l13: l13 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ pm4125_l14: l14 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ pm4125_l15: l15 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ pm4125_l16: l16 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ pm4125_l17: l17 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3544000>;
+ };
+
+ pm4125_l18: l18 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2960000>;
+ };
+
+ pm4125_l19: l19 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2960000>;
+ };
+
+ pm4125_l20: l20 {
+ regulator-min-microvolt = <2952000>;
+ regulator-max-microvolt = <2952000>;
+ };
+
+ pm4125_l21: l21 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3056000>;
+ };
+
+ pm4125_l22: l22 {
+ regulator-min-microvolt = <3304000>;
+ regulator-max-microvolt = <3304000>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/shikra-cqs-evk.dts b/arch/arm64/boot/dts/qcom/shikra-cqs-evk.dts
new file mode 100644
index 000000000000..b3f19a64d7ae
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/shikra-cqs-evk.dts
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+/dts-v1/;
+
+#include "shikra-cqm-som.dtsi"
+#include "shikra-evk.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. Shikra CQS EVK";
+ compatible = "qcom,shikra-cqs-evk", "qcom,shikra-cqs-som", "qcom,shikra";
+ chassis-type = "embedded";
+
+ aliases {
+ mmc0 = &sdhc_1;
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&sdhc_1 {
+ vmmc-supply = <&pm4125_l20>;
+ vqmmc-supply = <&pm4125_l14>;
+
+ pinctrl-0 = <&sdc1_state_on>;
+ pinctrl-1 = <&sdc1_state_off>;
+ pinctrl-names = "default", "sleep";
+
+ non-removable;
+ supports-cqe;
+ no-sdio;
+ no-sd;
+
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/shikra-evk.dtsi b/arch/arm64/boot/dts/qcom/shikra-evk.dtsi
new file mode 100644
index 000000000000..6eb4184f7642
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/shikra-evk.dtsi
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+&qupv3_0 {
+ firmware-name = "qcom/shikra/qupv3fw.elf";
+
+ status = "okay";
+};
+
+&uart0 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/shikra-iqs-evk.dts b/arch/arm64/boot/dts/qcom/shikra-iqs-evk.dts
new file mode 100644
index 000000000000..3003a47bd759
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/shikra-iqs-evk.dts
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+/dts-v1/;
+
+#include "shikra-iqs-som.dtsi"
+#include "shikra-evk.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. Shikra IQS EVK";
+ compatible = "qcom,shikra-iqs-evk", "qcom,shikra-iqs-som", "qcom,shikra";
+ chassis-type = "embedded";
+
+ aliases {
+ mmc0 = &sdhc_1;
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&sdhc_1 {
+ vmmc-supply = <&pm8150_l17>;
+ vqmmc-supply = <&pm8150_s4>;
+
+ pinctrl-0 = <&sdc1_state_on>;
+ pinctrl-1 = <&sdc1_state_off>;
+ pinctrl-names = "default", "sleep";
+
+ non-removable;
+ supports-cqe;
+ no-sdio;
+ no-sd;
+
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/shikra-iqs-som.dtsi b/arch/arm64/boot/dts/qcom/shikra-iqs-som.dtsi
new file mode 100644
index 000000000000..73945bf42112
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/shikra-iqs-som.dtsi
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
+
+#include "shikra.dtsi"
+#include "pm8150.dtsi"
+
+/ {
+ gpio-key {
+ compatible = "gpio-keys";
+ label = "gpio-keys";
+ pinctrl-names = "default";
+ pinctrl-0 = <&vol_up_n>;
+
+ key-volume-up {
+ label = "Volume Up";
+ gpios = <&pm8150_gpios 6 GPIO_ACTIVE_LOW>;
+ linux,input-type = <1>;
+ linux,code = <KEY_VOLUMEUP>;
+ wakeup-source;
+ debounce-interval = <15>;
+ linux,can-disable;
+ };
+ };
+};
+
+&pm8150_gpios {
+ vol_up_n: vol-up-n-state {
+ pins = "gpio6";
+ function = PMIC_GPIO_FUNC_NORMAL;
+ input-enable;
+ bias-pull-up;
+ power-source = <0>;
+ };
+
+};
+
+&pon_pwrkey {
+ status = "okay";
+};
+
+&pon_resin {
+ linux,code = <KEY_VOLUMEDOWN>;
+ status = "okay";
+};
+
+&rpm_requests {
+ regulators {
+ compatible = "qcom,rpm-pm8150-regulators";
+
+ pm8150_s4: s4 {
+ regulator-min-microvolt = <1080000>;
+ regulator-max-microvolt = <2040000>;
+ };
+
+ pm8150_s5: s5 {
+ regulator-min-microvolt = <1574000>;
+ regulator-max-microvolt = <2040000>;
+ };
+
+ pm8150_s6: s6 {
+ regulator-min-microvolt = <382000>;
+ regulator-max-microvolt = <1352000>;
+ };
+
+ pm8150_s7: s7 {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ pm8150_s8: s8 {
+ regulator-min-microvolt = <570000>;
+ regulator-max-microvolt = <650000>;
+ };
+
+ pm8150_l1: l1 {
+ regulator-min-microvolt = <312000>;
+ regulator-max-microvolt = <1304000>;
+ };
+
+ pm8150_l2: l2 {
+ regulator-min-microvolt = <1650000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ pm8150_l3: l3 {
+ regulator-min-microvolt = <312000>;
+ regulator-max-microvolt = <1304000>;
+ };
+
+ pm8150_l4: l4 {
+ regulator-min-microvolt = <875000>;
+ regulator-max-microvolt = <975000>;
+ };
+
+ pm8150_l5: l5 {
+ regulator-min-microvolt = <788000>;
+ regulator-max-microvolt = <1050000>;
+ };
+
+ pm8150_l6: l6 {
+ regulator-min-microvolt = <875000>;
+ regulator-max-microvolt = <1000000>;
+ };
+
+ pm8150_l7: l7 {
+ regulator-min-microvolt = <1504000>;
+ regulator-max-microvolt = <2000000>;
+ };
+
+ pm8150_l8: l8 {
+ regulator-min-microvolt = <1150000>;
+ regulator-max-microvolt = <1304000>;
+ };
+
+ pm8150_l9: l9 {
+ regulator-min-microvolt = <875000>;
+ regulator-max-microvolt = <1000000>;
+ };
+
+ pm8150_l10: l10 {
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <3544000>;
+ };
+
+ pm8150_l11: l11 {
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1304000>;
+ };
+
+ pm8150_l12: l12 {
+ regulator-min-microvolt = <1650000>;
+ regulator-max-microvolt = <1950000>;
+ };
+
+ pm8150_l13: l13 {
+ regulator-min-microvolt = <2921000>;
+ regulator-max-microvolt = <3230000>;
+ };
+
+ pm8150_l14: l14 {
+ regulator-min-microvolt = <1700000>;
+ regulator-max-microvolt = <1910000>;
+ };
+
+ pm8150_l15: l15 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1900000>;
+ };
+
+ pm8150_l16: l16 {
+ regulator-min-microvolt = <1504000>;
+ regulator-max-microvolt = <3544000>;
+ };
+
+ pm8150_l17: l17 {
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <3544000>;
+ };
+
+ pm8150_l18: l18 {
+ regulator-min-microvolt = <400000>;
+ regulator-max-microvolt = <728000>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/shikra.dtsi b/arch/arm64/boot/dts/qcom/shikra.dtsi
new file mode 100644
index 000000000000..4e5bc9e17c8e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/shikra.dtsi
@@ -0,0 +1,842 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <dt-bindings/clock/qcom,rpmcc.h>
+#include <dt-bindings/clock/qcom,shikra-gcc.h>
+#include <dt-bindings/interconnect/qcom,icc.h>
+#include <dt-bindings/interconnect/qcom,rpm-icc.h>
+#include <dt-bindings/interconnect/qcom,shikra.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/power/qcom-rpmpd.h>
+
+/ {
+ interrupt-parent = <&intc>;
+
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ clocks {
+ xo_board: xo-board {
+ compatible = "fixed-clock";
+ clock-frequency = <38400000>;
+ #clock-cells = <0>;
+ };
+
+ sleep_clk: sleep-clk {
+ compatible = "fixed-clock";
+ clock-frequency = <32764>;
+ #clock-cells = <0>;
+ };
+ };
+
+ cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ cpu0: cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a55";
+ reg = <0x0 0x0>;
+ enable-method = "psci";
+ next-level-cache = <&l3>;
+ capacity-dmips-mhz = <1024>;
+ dynamic-power-coefficient = <100>;
+ };
+
+ cpu1: cpu@100 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a55";
+ reg = <0x0 0x100>;
+ enable-method = "psci";
+ next-level-cache = <&l3>;
+ capacity-dmips-mhz = <1024>;
+ dynamic-power-coefficient = <100>;
+ };
+
+ cpu2: cpu@200 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a55";
+ reg = <0x0 0x200>;
+ enable-method = "psci";
+ next-level-cache = <&l3>;
+ capacity-dmips-mhz = <1024>;
+ dynamic-power-coefficient = <100>;
+ };
+
+ cpu3: cpu@300 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a78c";
+ reg = <0x0 0x300>;
+ enable-method = "psci";
+ next-level-cache = <&l2_3>;
+ capacity-dmips-mhz = <1946>;
+ dynamic-power-coefficient = <489>;
+
+ l2_3: l2-cache {
+ compatible = "cache";
+ cache-level = <2>;
+ cache-unified;
+ next-level-cache = <&l3>;
+ cache-size = <0x40000>;
+ };
+ };
+
+ cpu-map {
+ cluster0 {
+ core0 {
+ cpu = <&cpu0>;
+ };
+
+ core1 {
+ cpu = <&cpu1>;
+ };
+
+ core2 {
+ cpu = <&cpu2>;
+ };
+ };
+
+ cluster1 {
+ core0 {
+ cpu = <&cpu3>;
+ };
+ };
+ };
+
+ l3: l3-cache {
+ compatible = "cache";
+ cache-level = <3>;
+ cache-unified;
+ cache-size = <0x80000>;
+ };
+ };
+
+ firmware {
+ scm {
+ compatible = "qcom,scm-shikra", "qcom,scm";
+ clocks = <&rpmcc RPM_SMD_CE1_CLK>;
+ clock-names = "core";
+ qcom,dload-mode = <&tcsr_regs 0x13000>;
+ #reset-cells = <1>;
+ interconnects = <&system_noc MASTER_CRYPTO_CORE0 RPM_ALWAYS_TAG
+ &mc_virt SLAVE_EBI_CH0 RPM_ALWAYS_TAG>;
+ };
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+ /* We expect the bootloader to fill in the size */
+ reg = <0x0 0x80000000 0x0 0x0>;
+ };
+
+ pmu-a55 {
+ compatible = "arm,cortex-a55-pmu";
+ interrupts = <GIC_PPI 5 IRQ_TYPE_LEVEL_HIGH &ppi_cluster0>;
+ };
+
+ pmu-a78c {
+ compatible = "arm,cortex-a78-pmu";
+ interrupts = <GIC_PPI 5 IRQ_TYPE_LEVEL_HIGH &ppi_cluster1>;
+ };
+
+ psci {
+ compatible = "arm,psci-1.0";
+ method = "smc";
+ };
+
+ rpm: remoteproc {
+ compatible = "qcom,shikra-rpm-proc", "qcom,rpm-proc";
+
+ glink-edge {
+ compatible = "qcom,glink-rpm";
+ interrupts = <GIC_SPI 194 IRQ_TYPE_EDGE_RISING 0>;
+ qcom,rpm-msg-ram = <&rpm_msg_ram>;
+ mboxes = <&apcs_glb 0>;
+
+ rpm_requests: rpm-requests {
+ compatible = "qcom,rpm-shikra", "qcom,glink-smd-rpm";
+ qcom,glink-channels = "rpm_requests";
+
+ rpmcc: clock-controller {
+ compatible = "qcom,rpmcc-shikra", "qcom,rpmcc-qcm2290", "qcom,rpmcc";
+ clocks = <&xo_board>;
+ clock-names = "xo";
+ #clock-cells = <1>;
+ };
+
+ rpmpd: power-controller {
+ compatible = "qcom,shikra-rpmpd";
+ #power-domain-cells = <1>;
+ operating-points-v2 = <&rpmpd_opp_table>;
+
+ rpmpd_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ rpmpd_opp_min_svs: opp1 {
+ opp-level = <RPM_SMD_LEVEL_MIN_SVS>;
+ };
+
+ rpmpd_opp_low_svs: opp2 {
+ opp-level = <RPM_SMD_LEVEL_LOW_SVS>;
+ };
+
+ rpmpd_opp_svs: opp3 {
+ opp-level = <RPM_SMD_LEVEL_SVS>;
+ };
+
+ rpmpd_opp_svs_plus: opp4 {
+ opp-level = <RPM_SMD_LEVEL_SVS_PLUS>;
+ };
+
+ rpmpd_opp_nom: opp5 {
+ opp-level = <RPM_SMD_LEVEL_NOM>;
+ };
+
+ rpmpd_opp_nom_plus: opp6 {
+ opp-level = <RPM_SMD_LEVEL_NOM_PLUS>;
+ };
+
+ rpmpd_opp_turbo: opp7 {
+ opp-level = <RPM_SMD_LEVEL_TURBO>;
+ };
+
+ rpmpd_opp_turbo_plus: opp8 {
+ opp-level = <RPM_SMD_LEVEL_TURBO_NO_CPR>;
+ };
+ };
+ };
+ };
+ };
+
+ mpm: interrupt-controller {
+ compatible = "qcom,mpm";
+ qcom,rpm-msg-ram = <&apss_mpm>;
+ interrupts = <GIC_SPI 197 IRQ_TYPE_EDGE_RISING 0>;
+ mboxes = <&apcs_glb 1>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ #power-domain-cells = <0>;
+ interrupt-parent = <&intc>;
+ qcom,mpm-pin-count = <96>;
+ qcom,mpm-pin-map = <2 275>, /* TSENS0 uplow */
+ <12 422>, /* DWC3 ss_phy_irq */
+ <58 272>, /* QUSB2_PHY dmse_hv_vddmx */
+ <59 273>, /* QUSB2_PHY dpse_hv_vddmx */
+ <86 183>, /* MPM wake, SPMI */
+ <90 157>, /* QUSB2_PHY DM */
+ <91 158>; /* QUSB2_PHY DP */
+ };
+ };
+
+ reserved_memory: reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ hyp_mem: hyp@80000000 {
+ reg = <0x0 0x80000000 0x0 0x1600000>;
+ no-map;
+ };
+
+ xblboot_mem: xblboot@85e00000 {
+ reg = <0x0 0x85e00000 0x0 0x100000>;
+ no-map;
+ };
+
+ secdata_apss_mem: secdata-apss@85fff000 {
+ reg = <0x0 0x85fff000 0x0 0x1000>;
+ no-map;
+ };
+
+ smem_mem: smem@86000000 {
+ compatible = "qcom,smem";
+ reg = <0x0 0x86000000 0x0 0x200000>;
+ no-map;
+
+ hwlocks = <&tcsr_mutex 3>;
+ };
+
+ audio_heap_mem: audio-heap@86200000 {
+ reg = <0x0 0x86200000 0x0 0x100000>;
+ no-map;
+ };
+
+ tz_stat_mem: tz-stat@a0000000 {
+ reg = <0x0 0xa0000000 0x0 0x100000>;
+ no-map;
+ };
+
+ qtee_mem: qtee@a1300000 {
+ reg = <0x0 0xa1300000 0x0 0x500000>;
+ no-map;
+ };
+
+ tz_apps_mem: tz-apps@a1800000 {
+ reg = <0x0 0xa1800000 0x0 0x2100000>;
+ no-map;
+ };
+
+ mpss_wlan_mem: mpss-wlan@ab000000 {
+ reg = <0x0 0xab000000 0x0 0x6e00000>;
+ no-map;
+ };
+
+ wlan_mem: wlan@b2300000 {
+ reg = <0x0 0xb2300000 0x0 0x100000>;
+ no-map;
+ };
+
+ cdsp_mem: cdsp@b2400000 {
+ reg = <0x0 0xb2400000 0x0 0x1900000>;
+ no-map;
+ };
+
+ gpu_micro_code_mem: gpu-micro-code@b3d00000 {
+ reg = <0x0 0xb3d00000 0x0 0x2000>;
+ no-map;
+ };
+
+ video_mem: video@b3d02000 {
+ reg = <0x0 0xb3d02000 0x0 0x700000>;
+ no-map;
+ };
+
+ lmcu_mem: lmcu@b4402000 {
+ reg = <0x0 0xb4402000 0x0 0x300000>;
+ no-map;
+ };
+
+ lmcu_dtb_mem: lmcu-dtb@b4702000 {
+ reg = <0x0 0xb4702000 0x0 0x40000>;
+ no-map;
+ };
+ };
+
+ soc: soc@0 {
+ compatible = "simple-bus";
+
+ #address-cells = <2>;
+ #size-cells = <2>;
+ dma-ranges = <0x0 0x0 0x0 0x0 0x10 0x0>;
+ ranges = <0x0 0x0 0x0 0x0 0x10 0x0>;
+
+ tcsr_mutex: syscon@340000 {
+ compatible = "qcom,tcsr-mutex";
+ reg = <0x0 0x00340000 0x0 0x20000>;
+ #hwlock-cells = <1>;
+ };
+
+ tcsr_regs: syscon@3c0000 {
+ compatible = "qcom,shikra-tcsr", "syscon";
+ reg = <0x0 0x003c0000 0x0 0x40000>;
+ };
+
+ tlmm: pinctrl@500000 {
+ compatible = "qcom,shikra-tlmm";
+ reg = <0x0 0x00500000 0x0 0x700000>;
+
+ interrupts = <GIC_SPI 227 IRQ_TYPE_LEVEL_HIGH 0>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ gpio-ranges = <&tlmm 0 0 165>;
+ wakeup-parent = <&mpm>;
+
+ qup_uart0_default: qup-uart0-default-state {
+ pins = "gpio0", "gpio1";
+ function = "qup0_se0";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ sdc1_state_on: sdc1-on-state {
+ clk-pins {
+ pins = "sdc1_clk";
+ drive-strength = <6>;
+ bias-disable;
+ };
+
+ cmd-pins {
+ pins = "sdc1_cmd";
+ drive-strength = <6>;
+ bias-pull-up;
+ };
+
+ data-pins {
+ pins = "sdc1_data";
+ drive-strength = <6>;
+ bias-pull-up;
+ };
+
+ rclk-pins {
+ pins = "sdc1_rclk";
+ bias-pull-down;
+ };
+ };
+
+ sdc1_state_off: sdc1-off-state {
+ clk-pins {
+ pins = "sdc1_clk";
+ drive-strength = <2>;
+ bias-bus-hold;
+ };
+
+ cmd-pins {
+ pins = "sdc1_cmd";
+ drive-strength = <2>;
+ bias-bus-hold;
+ };
+
+ data-pins {
+ pins = "sdc1_data";
+ drive-strength = <2>;
+ bias-bus-hold;
+ };
+
+ rclk-pins {
+ pins = "sdc1_rclk";
+ bias-bus-hold;
+ };
+ };
+ };
+
+ mem_noc: interconnect@d00000 {
+ compatible = "qcom,shikra-mem-noc-core";
+ reg = <0x0 0x00d00000 0x0 0x43080>;
+ clocks = <&gcc GCC_DDRSS_GPU_AXI_CLK>;
+ clock-names = "gpu_axi";
+ #interconnect-cells = <2>;
+ };
+
+ llcc: system-cache-controller@e00000 {
+ compatible = "qcom,shikra-llcc";
+ reg = <0x0 0x00e00000 0x0 0x80000>,
+ <0x0 0x00f00000 0x0 0x80000>,
+ <0x0 0x01000000 0x0 0x80000>;
+ reg-names = "llcc0_base",
+ "llcc1_base",
+ "llcc_broadcast_base";
+ interrupts = <GIC_SPI 539 IRQ_TYPE_LEVEL_HIGH 0>;
+ };
+
+ gcc: clock-controller@1400000 {
+ compatible = "qcom,shikra-gcc";
+ reg = <0x0 0x01400000 0x0 0x1f0000>;
+ clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>,
+ <&sleep_clk>,
+ <0>,
+ <0>,
+ <0>,
+ <0>,
+ <0>,
+ <0>;
+ power-domains = <&rpmpd RPMPD_VDDCX>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ #power-domain-cells = <1>;
+ };
+
+ system_noc: interconnect@1880000 {
+ compatible = "qcom,shikra-sys-noc";
+ reg = <0x0 0x01880000 0x0 0x6a080>;
+ clocks = <&gcc GCC_EMAC0_AXI_SYS_NOC_CLK>,
+ <&gcc GCC_EMAC1_AXI_SYS_NOC_CLK>,
+ <&gcc GCC_SYS_NOC_USB2_PRIM_AXI_CLK>,
+ <&gcc GCC_SYS_NOC_USB3_PRIM_AXI_CLK>;
+ clock-names = "emac0_axi",
+ "emac1_axi",
+ "usb2_axi",
+ "usb3_axi";
+ #interconnect-cells = <2>;
+
+ clk_virt: interconnect-clk {
+ compatible = "qcom,shikra-clk-virt";
+ #interconnect-cells = <2>;
+ };
+
+ mc_virt: interconnect-mc {
+ compatible = "qcom,shikra-mc-virt";
+ #interconnect-cells = <2>;
+ };
+
+ mmrt_virt: interconnect-mmrt {
+ compatible = "qcom,shikra-mmrt-virt";
+ #interconnect-cells = <2>;
+ };
+
+ mmnrt_virt: interconnect-mmnrt {
+ compatible = "qcom,shikra-mmnrt-virt";
+ #interconnect-cells = <2>;
+ };
+ };
+
+ config_noc: interconnect@1900000 {
+ compatible = "qcom,shikra-config-noc";
+ reg = <0x0 0x01900000 0x0 0x8080>;
+ #interconnect-cells = <2>;
+ };
+
+ qfprom: efuse@1b44000 {
+ compatible = "qcom,shikra-qfprom", "qcom,qfprom";
+ reg = <0x0 0x01b44000 0x0 0x3000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ qusb2_hstx_trim_1: hstx-trim@25b {
+ reg = <0x25b 0x1>;
+ bits = <1 4>;
+ };
+
+ gpu_speed_bin: gpu-speed-bin@2006 {
+ reg = <0x2006 0x2>;
+ bits = <5 8>;
+ };
+ };
+
+ spmi_bus: spmi@1c40000 {
+ compatible = "qcom,spmi-pmic-arb";
+ reg = <0x0 0x01c40000 0x0 0x1100>,
+ <0x0 0x01e00000 0x0 0x2000000>,
+ <0x0 0x03e00000 0x0 0x100000>,
+ <0x0 0x03f00000 0x0 0xa0000>,
+ <0x0 0x01c0a000 0x0 0x26000>;
+ reg-names = "core",
+ "chnls",
+ "obsrvr",
+ "intr",
+ "cnfg";
+ interrupts-extended = <&mpm 86 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "periph_irq";
+ interrupt-controller;
+ #interrupt-cells = <4>;
+ #address-cells = <2>;
+ #size-cells = <0>;
+ qcom,channel = <0>;
+ qcom,ee = <0>;
+ };
+
+ rpm_msg_ram: sram@45f0000 {
+ compatible = "qcom,rpm-msg-ram", "mmio-sram";
+ reg = <0x0 0x045f0000 0x0 0x7000>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0x0 0x045f0000 0x7000>;
+
+ apss_mpm: sram@1b8 {
+ reg = <0x1b8 0x48>;
+ };
+ };
+
+ sram@4690000 {
+ compatible = "qcom,rpm-stats";
+ reg = <0x0 0x04690000 0x0 0x14000>;
+ };
+
+ sdhc_1: mmc@4744000 {
+ compatible = "qcom,shikra-sdhci", "qcom,sdhci-msm-v5";
+
+ reg = <0x0 0x04744000 0x0 0x1000>,
+ <0x0 0x04745000 0x0 0x1000>;
+ reg-names = "hc",
+ "cqhci";
+
+ iommus = <&apps_smmu 0xc0 0x0>;
+
+ interrupts = <GIC_SPI 348 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 352 IRQ_TYPE_LEVEL_HIGH 0>;
+ interrupt-names = "hc_irq",
+ "pwr_irq";
+
+ clocks = <&gcc GCC_SDCC1_AHB_CLK>,
+ <&gcc GCC_SDCC1_APPS_CLK>,
+ <&rpmcc RPM_SMD_XO_CLK_SRC>;
+ clock-names = "iface",
+ "core",
+ "xo";
+
+ interconnects = <&system_noc MASTER_SDCC_1 RPM_ALWAYS_TAG
+ &mc_virt SLAVE_EBI_CH0 RPM_ALWAYS_TAG>,
+ <&mem_noc MASTER_AMPSS_M0 RPM_ACTIVE_TAG
+ &config_noc SLAVE_SDCC_1 RPM_ACTIVE_TAG>;
+ interconnect-names = "sdhc-ddr",
+ "cpu-sdhc";
+
+ power-domains = <&rpmpd RPMPD_VDDCX>;
+ operating-points-v2 = <&sdhc1_opp_table>;
+
+ qcom,dll-config = <0x000f642c>;
+ qcom,ddr-config = <0x80040868>;
+
+ bus-width = <8>;
+
+ mmc-ddr-1_8v;
+ mmc-hs200-1_8v;
+ mmc-hs400-1_8v;
+ mmc-hs400-enhanced-strobe;
+
+ resets = <&gcc GCC_SDCC1_BCR>;
+
+ status = "disabled";
+
+ sdhc1_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ opp-100000000 {
+ opp-hz = /bits/ 64 <100000000>;
+ required-opps = <&rpmpd_opp_low_svs>;
+ opp-peak-kBps = <250000 133320>;
+ opp-avg-kBps = <104000 0>;
+ };
+
+ opp-384000000 {
+ opp-hz = /bits/ 64 <384000000>;
+ required-opps = <&rpmpd_opp_nom>;
+ opp-peak-kBps = <800000 300000>;
+ opp-avg-kBps = <400000 0>;
+ };
+ };
+ };
+
+ qupv3_0: geniqup@4ac0000 {
+ compatible = "qcom,geni-se-qup";
+ reg = <0x0 0x04ac0000 0x0 0x2000>;
+
+ clocks = <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+ <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+ clock-names = "m-ahb",
+ "s-ahb";
+
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ uart0: serial@4a80000 {
+ compatible = "qcom,geni-debug-uart";
+ reg = <0x0 0x04a80000 0x0 0x4000>;
+
+ interrupts = <GIC_SPI 527 IRQ_TYPE_LEVEL_HIGH 0>;
+
+ clocks = <&gcc GCC_QUPV3_WRAP0_S0_CLK>;
+ clock-names = "se";
+
+ interconnects = <&clk_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG
+ &clk_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>,
+ <&mem_noc MASTER_AMPSS_M0 RPM_ALWAYS_TAG
+ &config_noc SLAVE_QUP_0 RPM_ALWAYS_TAG>;
+ interconnect-names = "qup-core",
+ "qup-config";
+
+ pinctrl-0 = <&qup_uart0_default>;
+ pinctrl-names = "default";
+
+ status = "disabled";
+ };
+ };
+
+ sram@c11e000 {
+ compatible = "qcom,shikra-imem", "mmio-sram";
+ reg = <0x0 0x0c11e000 0x0 0x1000>;
+ ranges = <0x0 0x0 0x0c11e000 0x1000>;
+
+ no-memory-wc;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ pil-sram@94c {
+ compatible = "qcom,pil-reloc-info";
+ reg = <0x94c 0xc8>;
+ };
+ };
+
+ apps_smmu: iommu@c600000 {
+ compatible = "qcom,shikra-smmu-500", "qcom,smmu-500", "arm,mmu-500";
+ reg = <0x0 0x0c600000 0x0 0x80000>;
+ #iommu-cells = <2>;
+ #global-interrupts = <1>;
+
+ interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH 0>;
+ };
+
+ intc: interrupt-controller@f200000 {
+ compatible = "arm,gic-v3";
+ reg = <0x0 0xf200000 0x0 0x10000>,
+ <0x0 0xf240000 0x0 0x80000>;
+
+ interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH 0>;
+
+ #interrupt-cells = <4>;
+ interrupt-controller;
+
+ #redistributor-regions = <1>;
+ redistributor-stride = <0x0 0x20000>;
+
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ ppi-partitions {
+ ppi_cluster0: interrupt-partition-0 {
+ affinity = <&cpu0 &cpu1 &cpu2>;
+ };
+
+ ppi_cluster1: interrupt-partition-1 {
+ affinity = <&cpu3>;
+ };
+ };
+ };
+
+ apcs_glb: mailbox@f400000 {
+ compatible = "qcom,shikra-apss-shared", "qcom,sdm845-apss-shared";
+ reg = <0x0 0x0f400000 0x0 0x1000>;
+ #mbox-cells = <1>;
+ };
+
+ watchdog@f410000 {
+ compatible = "qcom,apss-wdt-shikra", "qcom,kpss-wdt";
+ reg = <0x0 0x0f410000 0x0 0x1000>;
+ interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH 0>;
+ clocks = <&sleep_clk>;
+ };
+
+ timer@f420000 {
+ compatible = "arm,armv7-timer-mem";
+ reg = <0x0 0x0f420000 0x0 0x1000>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0x0 0x0 0x10000000>;
+
+ frame@f421000 {
+ reg = <0x0f421000 0x1000>,
+ <0x0f422000 0x1000>;
+ frame-number = <0>;
+ interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH 0>;
+ };
+
+ frame@f423000 {
+ reg = <0x0f423000 0x1000>;
+ frame-number = <1>;
+ interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH 0>;
+ status = "disabled";
+ };
+
+ frame@f425000 {
+ reg = <0x0f425000 0x1000>;
+ frame-number = <2>;
+ interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH 0>;
+ status = "disabled";
+ };
+
+ frame@f427000 {
+ reg = <0x0f427000 0x1000>;
+ frame-number = <3>;
+ interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH 0>;
+ status = "disabled";
+ };
+
+ frame@f429000 {
+ reg = <0x0f429000 0x1000>;
+ frame-number = <4>;
+ interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH 0>;
+ status = "disabled";
+ };
+
+ frame@f42b000 {
+ reg = <0x0f42b000 0x1000>;
+ frame-number = <5>;
+ interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH 0>;
+ status = "disabled";
+ };
+
+ frame@f42d000 {
+ reg = <0x0f42d000 0x1000>;
+ frame-number = <6>;
+ interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH 0>;
+ status = "disabled";
+ };
+ };
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+
+ interrupts = <GIC_PPI 1 IRQ_TYPE_LEVEL_LOW 0>,
+ <GIC_PPI 2 IRQ_TYPE_LEVEL_LOW 0>,
+ <GIC_PPI 3 IRQ_TYPE_LEVEL_LOW 0>,
+ <GIC_PPI 0 IRQ_TYPE_LEVEL_LOW 0>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sm4450.dtsi b/arch/arm64/boot/dts/qcom/sm4450.dtsi
index 696e2e0841ad..b7dc40f3778c 100644
--- a/arch/arm64/boot/dts/qcom/sm4450.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm4450.dtsi
@@ -464,7 +464,7 @@
pdc: interrupt-controller@b220000 {
compatible = "qcom,sm4450-pdc", "qcom,pdc";
- reg = <0 0x0b220000 0 0x30000>, <0 0x174000f0 0 0x64>;
+ reg = <0 0x0b220000 0 0x10000>, <0 0x174000f0 0 0x64>;
qcom,pdc-ranges = <0 480 94>, <94 494 31>,
<125 63 1>;
#interrupt-cells = <2>;
diff --git a/arch/arm64/boot/dts/qcom/sm6115.dtsi b/arch/arm64/boot/dts/qcom/sm6115.dtsi
index bd94eb87d6f9..3520802d1fed 100644
--- a/arch/arm64/boot/dts/qcom/sm6115.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm6115.dtsi
@@ -1853,6 +1853,71 @@
#iommu-cells = <2>;
};
+ venus: video-codec@5a00000 {
+ compatible = "qcom,sm6115-venus",
+ "qcom,qcm2290-venus";
+ reg = <0x0 0x5a00000 0x0 0xf0000>;
+ interrupts = <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>;
+
+ power-domains = <&gcc GCC_VENUS_GDSC>,
+ <&gcc GCC_VCODEC0_GDSC>,
+ <&rpmpd SM6115_VDDCX>;
+ power-domain-names = "venus",
+ "vcodec0",
+ "cx";
+ operating-points-v2 = <&venus_opp_table>;
+
+ clocks = <&gcc GCC_VIDEO_VENUS_CTL_CLK>,
+ <&gcc GCC_VIDEO_AHB_CLK>,
+ <&gcc GCC_VENUS_CTL_AXI_CLK>,
+ <&gcc GCC_VIDEO_THROTTLE_CORE_CLK>,
+ <&gcc GCC_VIDEO_VCODEC0_SYS_CLK>,
+ <&gcc GCC_VCODEC0_AXI_CLK>;
+ clock-names = "core",
+ "iface",
+ "bus",
+ "throttle",
+ "vcodec0_core",
+ "vcodec0_bus";
+
+ memory-region = <&pil_video_mem>;
+ iommus = <&apps_smmu 0x860 0x0>,
+ <&apps_smmu 0x880 0x0>;
+
+ interconnects = <&mmnrt_virt MASTER_VIDEO_P0 RPM_ALWAYS_TAG
+ &bimc SLAVE_EBI_CH0 RPM_ALWAYS_TAG>,
+ <&bimc MASTER_AMPSS_M0 RPM_ACTIVE_TAG
+ &config_noc SLAVE_VENUS_CFG RPM_ACTIVE_TAG>;
+ interconnect-names = "video-mem",
+ "cpu-cfg";
+
+ status = "disabled";
+
+ venus_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ opp-133333333 {
+ opp-hz = /bits/ 64 <133333333>;
+ required-opps = <&rpmpd_opp_low_svs>;
+ };
+
+ opp-240000000 {
+ opp-hz = /bits/ 64 <240000000>;
+ required-opps = <&rpmpd_opp_svs>;
+ };
+
+ opp-300000000 {
+ opp-hz = /bits/ 64 <300000000>;
+ required-opps = <&rpmpd_opp_svs_plus>;
+ };
+
+ opp-384000000 {
+ opp-hz = /bits/ 64 <384000000>;
+ required-opps = <&rpmpd_opp_nom>;
+ };
+ };
+ };
+
mdss: display-subsystem@5e00000 {
compatible = "qcom,sm6115-mdss";
reg = <0x0 0x05e00000 0x0 0x1000>;
diff --git a/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo-common.dtsi b/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo-common.dtsi
index 7d8481173171..a5458ab41629 100644
--- a/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo-common.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo-common.dtsi
@@ -47,22 +47,22 @@
};
reserved-memory {
- adsp_pil_mem: adsp_pil_mem@55300000 {
+ adsp_pil_mem: adsp-pil-mem@55300000 {
reg = <0x0 0x55300000 0x0 0x2200000>;
no-map;
};
- ipa_fw_mem: ipa_fw_mem@57500000 {
+ ipa_fw_mem: ipa-fw-mem@57500000 {
reg = <0x0 0x57500000 0x0 0x10000>;
no-map;
};
- ipa_gsi_mem: ipa_gsi_mem@57510000 {
+ ipa_gsi_mem: ipa-gsi-mem@57510000 {
reg = <0x0 0x57510000 0x0 0x5000>;
no-map;
};
- gpu_mem: gpu_mem@57515000 {
+ gpu_mem: gpu-mem@57515000 {
reg = <0x0 0x57515000 0x0 0x2000>;
no-map;
};
diff --git a/arch/arm64/boot/dts/qcom/sm6125-xiaomi-laurel-sprout.dts b/arch/arm64/boot/dts/qcom/sm6125-xiaomi-laurel-sprout.dts
index b9d9439e230b..139f2b401af5 100644
--- a/arch/arm64/boot/dts/qcom/sm6125-xiaomi-laurel-sprout.dts
+++ b/arch/arm64/boot/dts/qcom/sm6125-xiaomi-laurel-sprout.dts
@@ -198,7 +198,7 @@
status = "okay";
panel@0 {
- compatible = "samsung,s6e8fco-m1906f9";
+ compatible = "samsung,s6e8fc0-m1906f9";
reg = <0>;
reset-gpios = <&tlmm 90 GPIO_ACTIVE_LOW>;
diff --git a/arch/arm64/boot/dts/qcom/sm6350.dtsi b/arch/arm64/boot/dts/qcom/sm6350.dtsi
index 947e17b5a5eb..51e0cb5cce66 100644
--- a/arch/arm64/boot/dts/qcom/sm6350.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm6350.dtsi
@@ -2569,7 +2569,7 @@
pdc: interrupt-controller@b220000 {
compatible = "qcom,sm6350-pdc", "qcom,pdc";
- reg = <0x0 0x0b220000 0x0 0x30000>, <0x0 0x17c000f0 0x0 0x64>;
+ reg = <0x0 0x0b220000 0x0 0x10000>, <0x0 0x17c000f0 0x0 0x64>;
qcom,pdc-ranges = <0 480 94>, <94 609 31>,
<125 63 1>, <126 655 12>, <138 139 15>;
#interrupt-cells = <2>;
diff --git a/arch/arm64/boot/dts/qcom/sm7325-xiaomi-taoyao.dts b/arch/arm64/boot/dts/qcom/sm7325-xiaomi-taoyao.dts
new file mode 100644
index 000000000000..6f8bc65bb99b
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sm7325-xiaomi-taoyao.dts
@@ -0,0 +1,913 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (c) 2025, Stanislav Zaikin <zstaseg@gmail.com>
+ */
+
+/dts-v1/;
+
+/* PM7250B is configured to use SID8/9 */
+#define PM7250B_SID 8
+#define PM7250B_SID1 9
+
+#include <dt-bindings/arm/qcom,ids.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/iio/qcom,spmi-adc7-pm7325.h>
+#include <dt-bindings/iio/qcom,spmi-adc7-pmk8350.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
+#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+#include <dt-bindings/sound/qcom,q6afe.h>
+#include <dt-bindings/sound/qcom,q6asm.h>
+
+#include "sm7325.dtsi"
+#include "pm7325.dtsi"
+#include "pm7250b.dtsi" /* PM7250B */
+#include "pm8350c.dtsi" /* PM7350C */
+#include "pmk8350.dtsi" /* PMK7325 */
+
+/* The following reserved memory regions have different addresses or sizes */
+/delete-node/ &adsp_mem;
+/delete-node/ &adsp_rpc_remote_heap_mem;
+/delete-node/ &cdsp_mem;
+/delete-node/ &rmtfs_mem;
+
+/ {
+ model = "Xiaomi 12 Lite 5G";
+ compatible = "xiaomi,taoyao", "qcom,sm7325";
+ chassis-type = "handset";
+
+ aliases {
+ serial0 = &uart5;
+ serial1 = &uart7;
+ };
+
+ chosen {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ framebuffer0: framebuffer {
+ compatible = "simple-framebuffer";
+ memory-region = <&framebuffer_reserved>;
+ width = <1080>;
+ height = <2400>;
+ stride = <(1080 * 4)>;
+ format = "a8r8g8b8";
+
+ clocks = <&gcc GCC_DISP_HF_AXI_CLK>;
+ };
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+
+ pinctrl-0 = <&key_vol_up>;
+ pinctrl-names = "default";
+
+ key-volume-up {
+ label = "Volume Up";
+ gpios = <&pm7325_gpios 6 GPIO_ACTIVE_LOW>;
+ linux,code = <KEY_VOLUMEUP>;
+ };
+ };
+
+ pmic-glink {
+ compatible = "qcom,sm7325-pmic-glink",
+ "qcom,qcm6490-pmic-glink",
+ "qcom,pmic-glink";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ orientation-gpios = <&tlmm 140 GPIO_ACTIVE_HIGH>;
+
+ connector@0 {
+ compatible = "usb-c-connector";
+ reg = <0>;
+ power-role = "dual";
+ data-role = "dual";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ pmic_glink_hs_in: endpoint {
+ remote-endpoint = <&usb_1_dwc3_hs>;
+ };
+ };
+
+ port@2 {
+ reg = <2>;
+
+ pmic_glink_sbu: endpoint {
+ remote-endpoint = <&fsa4480_sbu_mux>;
+ };
+ };
+ };
+ };
+ };
+
+ vreg_oled_dvdd: regulator-oled-dvdd {
+ compatible = "regulator-fixed";
+ regulator-name = "oled_dvdd";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ gpio = <&tlmm 46 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ vin-supply = <&vreg_s1b_1p856>;
+ regulator-boot-on;
+ };
+
+ /* S2B is really ebi.lvl but it's there for supply map completeness sake. */
+ vreg_s2b_0p7: regulator-smpb2 {
+ compatible = "regulator-fixed";
+ regulator-name = "vreg_s2b_0p7";
+
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <700000>;
+ regulator-always-on;
+ vin-supply = <&vph_pwr>;
+ };
+
+ vph_pwr: regulator-vph-pwr {
+ compatible = "regulator-fixed";
+ regulator-name = "vph_pwr";
+ regulator-min-microvolt = <3700000>;
+ regulator-max-microvolt = <3700000>;
+ };
+
+ reserved-memory {
+ cdsp_secure_heap_mem: cdsp-secure-heap@81800000 {
+ reg = <0x0 0x81800000 0x0 0x1e00000>;
+ no-map;
+ };
+
+ cvp_mem: cvp@86200000 {
+ reg = <0x0 0x86200000 0x0 0x500000>;
+ no-map;
+ };
+
+ adsp_mem: adsp@86700000 {
+ reg = <0x0 0x86700000 0x0 0x4000000>;
+ no-map;
+ };
+
+ camera_mem: camera@8ad00000 {
+ reg = <0x0 0x8ad00000 0x0 0x500000>;
+ no-map;
+ };
+
+ ipa_gsi_mem: ipa-gsi@8b710000 {
+ reg = <0x0 0x8b710000 0x0 0xa000>;
+ no-map;
+ };
+
+ cdsp_mem: cdsp@9c700000 {
+ reg = <0x0 0x9c700000 0x0 0x1e00000>;
+ no-map;
+ };
+
+ ramoops@a9000000 {
+ compatible = "ramoops";
+ reg = <0x0 0xa9000000 0x0 0x200000>;
+ mem-type = <2>;
+ pmsg-size = <0x100000>;
+ record-size = <0x100000>;
+ };
+
+ removed_mem: removed@c0000000 {
+ reg = <0x0 0xc0000000 0x0 0x6800000>;
+ no-map;
+ };
+
+ pil_trustedvm_mem: pil-trustedvm-region@d0800000 {
+ reg = <0x0 0xd0800000 0x0 0x76f7000>;
+ no-map;
+ };
+
+ qrtr_shmem: qrtr-shmem@d7ef7000 {
+ reg = <0x0 0xd7ef7000 0x0 0x9000>;
+ no-map;
+ };
+
+ neuron_block_0_mem: neuron-block@d7f00000 {
+ reg = <0x0 0xd7f00000 0x0 0x80000>;
+ no-map;
+ };
+
+ neuron_block_1_mem: neuron-block@d7f80000 {
+ reg = <0x0 0xd7f80000 0x0 0x80000>;
+ no-map;
+ };
+
+ adsp_rpc_remote_heap_mem: adsp-rpc-remote-heap@e0400000 {
+ reg = <0x0 0xe0400000 0x0 0x800000>;
+ no-map;
+ };
+
+ framebuffer_reserved: framebuffer@e1000000 {
+ reg = <0x0 0xe1000000 0x0 (1080 * 2400 * 4)>;
+ no-map;
+ };
+
+ rmtfs_mem: rmtfs@e7d00000 {
+ compatible = "qcom,rmtfs-mem";
+ reg = <0x0 0xe7d00000 0x0 0x280000>;
+ no-map;
+
+ qcom,client-id = <1>;
+ qcom,vmid = <QCOM_SCM_VMID_MSS_MSA>,
+ <QCOM_SCM_VMID_NAV>;
+ };
+ };
+
+ wcn6750-pmu {
+ compatible = "qcom,wcn6750-pmu";
+ pinctrl-0 = <&hst_bt_en>,
+ <&hst_sw_ctrl>;
+ pinctrl-names = "default";
+ vddio-supply = <&vreg_l19b_1p8>;
+ vddaon-supply = <&vreg_s7b_0p952>;
+ vddasd-supply = <&vreg_l11c_2p8>;
+ vddpmu-supply = <&vreg_s7b_0p952>;
+ vddrfa0p8-supply = <&vreg_s7b_0p952>;
+ vddrfa1p2-supply = <&vreg_s8b_1p256>;
+ vddrfa1p7-supply = <&vreg_s1b_1p856>;
+ vddrfa2p2-supply = <&vreg_s1c_2p2>;
+
+ bt-enable-gpios = <&tlmm 85 GPIO_ACTIVE_HIGH>;
+ swctrl-gpios = <&tlmm 86 GPIO_ACTIVE_HIGH>;
+
+ regulators {
+ vreg_pmu_rfa_cmn: ldo0 {
+ regulator-name = "vreg_pmu_rfa_cmn";
+ };
+
+ vreg_pmu_aon_0p59: ldo1 {
+ regulator-name = "vreg_pmu_aon_0p59";
+ };
+
+ vreg_pmu_wlcx_0p8: ldo2 {
+ regulator-name = "vreg_pmu_wlcx_0p8";
+ };
+
+ vreg_pmu_wlmx_0p85: ldo3 {
+ regulator-name = "vreg_pmu_wlmx_0p85";
+ };
+
+ vreg_pmu_btcmx_0p85: ldo4 {
+ regulator-name = "vreg_pmu_btcmx_0p85";
+ };
+
+ vreg_pmu_rfa_0p8: ldo5 {
+ regulator-name = "vreg_pmu_rfa_0p8";
+ };
+
+ vreg_pmu_rfa_1p2: ldo6 {
+ regulator-name = "vreg_pmu_rfa_1p2";
+ };
+
+ vreg_pmu_rfa_1p7: ldo7 {
+ regulator-name = "vreg_pmu_rfa_1p7";
+ };
+ };
+ };
+};
+
+&apps_rsc {
+ regulators-0 {
+ compatible = "qcom,pm7325-rpmh-regulators";
+ qcom,pmic-id = "b";
+
+ vdd-s1-supply = <&vph_pwr>;
+ vdd-s2-supply = <&vph_pwr>;
+ vdd-s7-supply = <&vph_pwr>;
+ vdd-s8-supply = <&vph_pwr>;
+
+ vdd-l1-l4-l12-l15-supply = <&vreg_s7b_0p952>;
+ vdd-l2-l7-supply = <&vreg_bob>;
+ vdd-l3-supply = <&vreg_s2b_0p7>;
+ vdd-l5-supply = <&vreg_s2b_0p7>;
+ vdd-l6-l9-l10-supply = <&vreg_s8b_1p256>;
+ vdd-l8-supply = <&vreg_s7b_0p952>;
+ vdd-l11-l17-l18-l19-supply = <&vreg_s1b_1p856>;
+ vdd-l13-supply = <&vreg_s7b_0p952>;
+ vdd-l14-l16-supply = <&vreg_s8b_1p256>;
+
+ /*
+ * S2, L4-L5 are ARCs:
+ * S2 - ebi.lvl,
+ * L4 - lmx.lvl,
+ * L5 - lcx.lvl.
+ *
+ * L10 are unused.
+ */
+
+ vreg_s1b_1p856: smps1 {
+ regulator-name = "vreg_s1b_1p856";
+ regulator-min-microvolt = <1840000>;
+ regulator-max-microvolt = <2040000>;
+ };
+
+ vreg_s7b_0p952: smps7 {
+ regulator-name = "vreg_s7b_0p952";
+ regulator-min-microvolt = <535000>;
+ regulator-max-microvolt = <1120000>;
+ };
+
+ vreg_s8b_1p256: smps8 {
+ regulator-name = "vreg_s8b_1p256";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_RET>;
+ };
+
+ vreg_l1b_0p912: ldo1 {
+ regulator-name = "vreg_l1b_0p912";
+ regulator-min-microvolt = <825000>;
+ regulator-max-microvolt = <925000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l2b_3p072: ldo2 {
+ regulator-name = "vreg_l2b_3p072";
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <3544000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l3b_0p6: ldo3 {
+ regulator-name = "vreg_l3b_0p6";
+ regulator-min-microvolt = <312000>;
+ regulator-max-microvolt = <910000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l6b_1p2: ldo6 {
+ regulator-name = "vreg_l6b_1p2";
+ regulator-min-microvolt = <1140000>;
+ regulator-max-microvolt = <1260000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l7b_2p96: ldo7 {
+ regulator-name = "vreg_l7b_2p96";
+ /* Constrained for UFS VCC, at least until UFS driver scales voltage */
+ regulator-min-microvolt = <2952000>;
+ regulator-max-microvolt = <2952000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l8b_0p904: ldo8 {
+ regulator-name = "vreg_l8b_0p904";
+ regulator-min-microvolt = <870000>;
+ regulator-max-microvolt = <970000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l9b_1p2: ldo9 {
+ regulator-name = "vreg_l9b_1p2";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1304000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ regulator-allow-set-load;
+ regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l11b_1p776: ldo11 {
+ regulator-name = "vreg_l11b_1p776";
+ regulator-min-microvolt = <1504000>;
+ regulator-max-microvolt = <2000000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l12b_0p8: ldo12 {
+ regulator-name = "vreg_l12b_0p8";
+ regulator-min-microvolt = <751000>;
+ regulator-max-microvolt = <824000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l13b_0p8: ldo13 {
+ regulator-name = "vreg_l13b_0p8";
+ regulator-min-microvolt = <530000>;
+ regulator-max-microvolt = <824000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l14b_1p2: ldo14 {
+ regulator-name = "vreg_l14b_1p2";
+ regulator-min-microvolt = <1080000>;
+ regulator-max-microvolt = <1304000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l15b_0p88: ldo15 {
+ regulator-name = "vreg_l15b_0p88";
+ regulator-min-microvolt = <765000>;
+ regulator-max-microvolt = <1020000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l16b_1p2: ldo16 {
+ regulator-name = "vreg_l16b_1p2";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1300000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l17b_1p8: ldo17 {
+ regulator-name = "vreg_l17b_1p8";
+ regulator-min-microvolt = <1700000>;
+ regulator-max-microvolt = <1900000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l18b_1p8: ldo18 {
+ regulator-name = "vreg_l18b_1p8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2000000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l19b_1p8: ldo19 {
+ regulator-name = "vreg_l19b_1p8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2000000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+ };
+
+ regulators-1 {
+ compatible = "qcom,pm8350c-rpmh-regulators";
+ qcom,pmic-id = "c";
+
+ vdd-s1-supply = <&vph_pwr>;
+ vdd-s2-supply = <&vph_pwr>;
+ vdd-s5-supply = <&vph_pwr>;
+ vdd-s7-supply = <&vph_pwr>;
+ vdd-s9-supply = <&vph_pwr>;
+ vdd-s10-supply = <&vph_pwr>;
+
+ vdd-l1-l12-supply = <&vreg_s1b_1p856>;
+ vdd-l2-l8-supply = <&vreg_s1b_1p856>;
+ vdd-l3-l4-l5-l7-l13-supply = <&vreg_bob>;
+ vdd-l6-l9-l11-supply = <&vreg_bob>;
+ vdd-l10-supply = <&vreg_s7b_0p952>;
+
+ vdd-bob-supply = <&vph_pwr>;
+
+ /*
+ * S2, S5, S7, S10 are ARCs:
+ * S2 - cx.lvl,
+ * S5 - mss.lvl,
+ * S7 - gfx.lvl,
+ * S10 - mx.lvl.
+ */
+
+ vreg_s1c_2p2: smps1 {
+ regulator-name = "vreg_s1c_2p2";
+ regulator-min-microvolt = <2190000>;
+ regulator-max-microvolt = <2210000>;
+ };
+
+ vreg_s9c_0p676: smps9 {
+ regulator-name = "vreg_s9c_0p676";
+ regulator-min-microvolt = <1010000>;
+ regulator-max-microvolt = <1170000>;
+ };
+
+ vreg_l1c_1p8: ldo1 {
+ regulator-name = "vreg_l1c_1p8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1980000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l2c_1p8: ldo2 {
+ regulator-name = "vreg_l2c_1p8";
+ regulator-min-microvolt = <1620000>;
+ regulator-max-microvolt = <1980000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l3c_3p0: ldo3 {
+ regulator-name = "vreg_l3c_3p0";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <3540000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l4c_1p8_3p0: ldo4 {
+ regulator-name = "vreg_l4c_1p8_3p0";
+ regulator-min-microvolt = <1620000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l5c_1p8_3p0: ldo5 {
+ regulator-name = "vreg_l5c_1p8_3p0";
+ regulator-min-microvolt = <1620000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l6c_2p96: ldo6 {
+ regulator-name = "vreg_l6c_2p96";
+ regulator-min-microvolt = <1650000>;
+ regulator-max-microvolt = <3544000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l7c_3p0: ldo7 {
+ regulator-name = "vreg_l7c_3p0";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3544000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l8c_1p8: ldo8 {
+ regulator-name = "vreg_l8c_1p8";
+ regulator-min-microvolt = <1620000>;
+ regulator-max-microvolt = <2000000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l9c_2p96: ldo9 {
+ regulator-name = "vreg_l9c_2p96";
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <3544000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l10c_0p88: ldo10 {
+ regulator-name = "vreg_l10c_0p88";
+ regulator-min-microvolt = <720000>;
+ regulator-max-microvolt = <1050000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ regulator-allow-set-load;
+ regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l11c_2p8: ldo11 {
+ regulator-name = "vreg_l11c_2p8";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <3544000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l12c_1p8: ldo12 {
+ regulator-name = "vreg_l12c_1p8";
+ regulator-min-microvolt = <1650000>;
+ regulator-max-microvolt = <2000000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l13c_3p0: ldo13 {
+ regulator-name = "vreg_l13c_3p0";
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <3544000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_bob: bob {
+ regulator-name = "vreg_bob";
+ regulator-min-microvolt = <3008000>;
+ regulator-max-microvolt = <3960000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_AUTO>;
+ };
+ };
+};
+
+&dispcc {
+ status = "disabled";
+};
+
+&gcc {
+ protected-clocks = <GCC_CFG_NOC_LPASS_CLK>,
+ <GCC_MSS_CFG_AHB_CLK>,
+ <GCC_MSS_OFFLINE_AXI_CLK>,
+ <GCC_MSS_Q6SS_BOOT_CLK_SRC>,
+ <GCC_MSS_Q6_MEMNOC_AXI_CLK>,
+ <GCC_MSS_SNOC_AXI_CLK>,
+ <GCC_QSPI_CNOC_PERIPH_AHB_CLK>,
+ <GCC_QSPI_CORE_CLK>,
+ <GCC_QSPI_CORE_CLK_SRC>,
+ <GCC_SEC_CTRL_CLK_SRC>,
+ <GCC_WPSS_AHB_BDG_MST_CLK>,
+ <GCC_WPSS_AHB_CLK>,
+ <GCC_WPSS_RSCP_CLK>;
+};
+
+&gpi_dma0 {
+ status = "okay";
+};
+
+&gpi_dma1 {
+ status = "okay";
+};
+
+&gpu {
+ status = "okay";
+};
+
+&gpu_zap_shader {
+ firmware-name = "qcom/sm7325/xiaomi/taoyao/a660_zap.mbn";
+};
+
+&i2c1 {
+ clock-frequency = <100000>;
+
+ status = "okay";
+
+ typec-mux@42 {
+ compatible = "fcs,fsa4480";
+ reg = <0x42>;
+
+ vcc-supply = <&vreg_bob>;
+
+ mode-switch;
+ orientation-switch;
+
+ port {
+ fsa4480_sbu_mux: endpoint {
+ remote-endpoint = <&pmic_glink_sbu>;
+ };
+ };
+ };
+};
+
+&ipa {
+ firmware-name = "qcom/sm7325/xiaomi/taoyao/ipa_fws.mbn";
+
+ status = "okay";
+};
+
+&lpass_audiocc {
+ compatible = "qcom,qcm6490-lpassaudiocc";
+ /delete-property/ power-domains;
+};
+
+&pm7325_gpios {
+ key_vol_up: key-vol-up-n-state {
+ pins = "gpio6";
+ function = PMIC_GPIO_FUNC_NORMAL;
+ power-source = <1>;
+ bias-pull-up;
+ input-enable;
+ };
+};
+
+&pmk8350_rtc {
+ status = "okay";
+};
+
+&pon_pwrkey {
+ status = "okay";
+};
+
+&pon_resin {
+ linux,code = <KEY_VOLUMEDOWN>;
+
+ status = "okay";
+};
+
+&qup_spi13_cs {
+ drive-strength = <6>;
+ bias-disable;
+};
+
+&qup_spi13_data_clk {
+ drive-strength = <6>;
+ bias-disable;
+};
+
+&qupv3_id_0 {
+ status = "okay";
+};
+
+&qupv3_id_1 {
+ status = "okay";
+};
+
+&remoteproc_adsp {
+ firmware-name = "qcom/sm7325/xiaomi/taoyao/adsp.mbn";
+
+ status = "okay";
+};
+
+&remoteproc_cdsp {
+ firmware-name = "qcom/sm7325/xiaomi/taoyao/cdsp.mbn";
+
+ status = "okay";
+};
+
+&remoteproc_mpss {
+ firmware-name = "qcom/sm7325/xiaomi/taoyao/modem.mbn";
+
+ status = "okay";
+};
+
+&remoteproc_wpss {
+ firmware-name = "qcom/sm7325/xiaomi/taoyao/wpss.mbn";
+
+ status = "okay";
+};
+
+&spi13 {
+ status = "okay";
+
+ touchscreen@0 {
+ compatible = "goodix,gt9916";
+ reg = <0>;
+
+ interrupts-extended = <&tlmm 81 IRQ_TYPE_LEVEL_LOW>;
+
+ reset-gpios = <&tlmm 105 GPIO_ACTIVE_LOW>;
+
+ avdd-supply = <&vreg_l7c_3p0>;
+ vddio-supply = <&vreg_l2c_1p8>;
+
+ spi-max-frequency = <5000000>;
+
+ touchscreen-size-x = <10800>;
+ touchscreen-size-y = <24000>;
+
+ pinctrl-0 = <&ts_irq>, <&ts_reset>;
+ pinctrl-names = "default";
+ };
+};
+
+&tlmm {
+ /*
+ * 48-51: presumably NFC SE
+ * 56-59: presumably fingerprint reader
+ */
+ gpio-reserved-ranges = <48 4>, <56 4>;
+
+ bt_uart_sleep_cts: bt-uart-sleep-cts-state {
+ pins = "gpio28";
+ function = "gpio";
+ bias-bus-hold;
+ };
+
+ bt_uart_sleep_rts: bt-uart-sleep-rts-state {
+ pins = "gpio29";
+ function = "gpio";
+ bias-pull-down;
+ };
+
+ bt_uart_sleep_txd: bt-uart-sleep-txd-state {
+ pins = "gpio30";
+ function = "gpio";
+ bias-pull-up;
+ };
+
+ bt_uart_sleep_rxd: bt-uart-sleep-rxd-state {
+ pins = "gpio31";
+ function = "gpio";
+ bias-pull-up;
+ };
+
+ sde_dsi_active: sde-dsi-active-state {
+ pins = "gpio44";
+ function = "gpio";
+ drive-strength = <8>;
+ bias-disable;
+ };
+
+ sde_dsi_sleep: sde-dsi-sleep-state {
+ pins = "gpio44";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ sde_te_active_sleep: sde-te-active-state {
+ pins = "gpio80";
+ function = "mdp_vsync";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+
+ ts_irq: ts-irq-state {
+ pins = "gpio81";
+ function = "gpio";
+ drive-strength = <8>;
+ bias-pull-up;
+ };
+
+ hst_bt_en: hst-bt-en-state {
+ pins = "gpio85";
+ function = "gpio";
+ bias-disable;
+ };
+
+ hst_sw_ctrl: hst-sw-ctrl-state {
+ pins = "gpio86";
+ function = "gpio";
+ bias-pull-down;
+ };
+
+ ts_reset: ts-reset-state {
+ pins = "gpio105";
+ function = "gpio";
+ drive-strength = <8>;
+ bias-pull-up;
+ };
+};
+
+&uart5 {
+ status = "okay";
+};
+
+&uart7 {
+ /delete-property/interrupts;
+ interrupts-extended = <&intc GIC_SPI 608 IRQ_TYPE_LEVEL_HIGH>,
+ <&tlmm 31 IRQ_TYPE_EDGE_FALLING>;
+
+ pinctrl-1 = <&bt_uart_sleep_cts>,
+ <&bt_uart_sleep_rts>,
+ <&bt_uart_sleep_txd>,
+ <&bt_uart_sleep_rxd>;
+ pinctrl-names = "default", "sleep";
+
+ status = "okay";
+
+ bluetooth: bluetooth {
+ compatible = "qcom,wcn6750-bt";
+
+ vddrfacmn-supply = <&vreg_pmu_rfa_cmn>;
+ vddaon-supply = <&vreg_pmu_aon_0p59>;
+ vddbtcmx-supply = <&vreg_pmu_btcmx_0p85>;
+ vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>;
+ vddrfa1p7-supply = <&vreg_pmu_rfa_1p7>;
+ vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>;
+ max-speed = <3200000>;
+ };
+};
+
+&ufs_mem_hc {
+ reset-gpios = <&tlmm 175 GPIO_ACTIVE_LOW>;
+
+ vcc-supply = <&vreg_l7b_2p96>;
+ vcc-max-microamp = <800000>;
+ /*
+ * Technically l9b enables an eLDO (supplied by s1b) which then powers
+ * VCCQ2 of the UFS.
+ */
+ vccq2-supply = <&vreg_l9b_1p2>;
+ vccq2-max-microamp = <900000>;
+
+ status = "okay";
+};
+
+&ufs_mem_phy {
+ vdda-phy-supply = <&vreg_l10c_0p88>;
+ vdda-pll-supply = <&vreg_l6b_1p2>;
+
+ status = "okay";
+};
+
+&usb_1 {
+ /* USB 2.0 only */
+ qcom,select-utmi-as-pipe-clk;
+
+ maximum-speed = "high-speed";
+ /* Remove USB3 phy */
+ phys = <&usb_1_hsphy>;
+ phy-names = "usb2-phy";
+
+ status = "okay";
+};
+
+&usb_1_dwc3_hs {
+ remote-endpoint = <&pmic_glink_hs_in>;
+};
+
+&usb_1_hsphy {
+ vdda-pll-supply = <&vreg_l10c_0p88>;
+ vdda18-supply = <&vreg_l1c_1p8>;
+ vdda33-supply = <&vreg_l2b_3p072>;
+
+ status = "okay";
+};
+
+&venus {
+ firmware-name = "qcom/sm7325/xiaomi/taoyao/vpu20_1v.mbn";
+
+ status = "okay";
+};
+
+&wifi {
+ qcom,calibration-variant = "Xiaomi_taoyao";
+
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi
index 0e101096209a..661848ef5eee 100644
--- a/arch/arm64/boot/dts/qcom/sm8150.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi
@@ -4174,7 +4174,7 @@
pdc: interrupt-controller@b220000 {
compatible = "qcom,sm8150-pdc", "qcom,pdc";
- reg = <0 0x0b220000 0 0x30000>;
+ reg = <0 0x0b220000 0 0x10000>;
qcom,pdc-ranges = <0 480 94>, <94 609 31>,
<125 63 1>;
#interrupt-cells = <2>;
diff --git a/arch/arm64/boot/dts/qcom/sm8250.dtsi b/arch/arm64/boot/dts/qcom/sm8250.dtsi
index 05e765616112..afdd3378f0ab 100644
--- a/arch/arm64/boot/dts/qcom/sm8250.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8250.dtsi
@@ -10,6 +10,7 @@
#include <dt-bindings/clock/qcom,gpucc-sm8250.h>
#include <dt-bindings/clock/qcom,rpmh.h>
#include <dt-bindings/dma/qcom-gpi.h>
+#include <dt-bindings/firmware/qcom,scm.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interconnect/qcom,osm-l3.h>
#include <dt-bindings/interconnect/qcom,sm8250.h>
@@ -863,6 +864,14 @@
reg = <0x0 0x8bf00000 0x0 0x4600000>;
no-map;
};
+
+ adsp_rpc_remote_heap_mem: adsp-rpc-remote-heap {
+ compatible = "shared-dma-pool";
+ alloc-ranges = <0x0 0x80000000 0x0 0x80000000>;
+ reusable;
+ alignment = <0x0 0x400000>;
+ size = <0x0 0x800000>;
+ };
};
smem {
@@ -5053,7 +5062,7 @@
pdc: interrupt-controller@b220000 {
compatible = "qcom,sm8250-pdc", "qcom,pdc";
- reg = <0 0x0b220000 0 0x30000>, <0 0x17c000f0 0 0x60>;
+ reg = <0 0x0b220000 0 0x10000>, <0 0x17c000f0 0 0x60>;
qcom,pdc-ranges = <0 480 94>, <94 609 31>,
<125 63 1>, <126 716 12>;
#interrupt-cells = <2>;
@@ -6084,6 +6093,9 @@
compatible = "qcom,fastrpc";
qcom,glink-channels = "fastrpcglink-apps-dsp";
label = "adsp";
+ memory-region = <&adsp_rpc_remote_heap_mem>;
+ qcom,vmids = <QCOM_SCM_VMID_LPASS
+ QCOM_SCM_VMID_ADSP_HEAP>;
qcom,non-secure-domain;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/arm64/boot/dts/qcom/sm8350.dtsi b/arch/arm64/boot/dts/qcom/sm8350.dtsi
index dd205f54000f..72ecfaeefdd3 100644
--- a/arch/arm64/boot/dts/qcom/sm8350.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8350.dtsi
@@ -3258,7 +3258,7 @@
pdc: interrupt-controller@b220000 {
compatible = "qcom,sm8350-pdc", "qcom,pdc";
- reg = <0 0x0b220000 0 0x30000>, <0 0x17c000f0 0 0x60>;
+ reg = <0 0x0b220000 0 0x10000>, <0 0x17c000f0 0 0x60>;
qcom,pdc-ranges = <0 480 40>, <40 140 14>, <54 263 1>, <55 306 4>,
<59 312 3>, <62 374 2>, <64 434 2>, <66 438 3>,
<69 86 1>, <70 520 54>, <124 609 31>, <155 63 1>,
diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi
index 56cb6e959e4e..7ddd0f5f539c 100644
--- a/arch/arm64/boot/dts/qcom/sm8450.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi
@@ -3728,7 +3728,7 @@
pdc: interrupt-controller@b220000 {
compatible = "qcom,sm8450-pdc", "qcom,pdc";
- reg = <0 0x0b220000 0 0x30000>, <0 0x174000f0 0 0x64>;
+ reg = <0 0x0b220000 0 0x10000>, <0 0x174000f0 0 0x64>;
qcom,pdc-ranges = <0 480 12>, <14 494 24>, <40 520 54>,
<94 609 31>, <125 63 1>, <126 716 12>;
#interrupt-cells = <2>;
diff --git a/arch/arm64/boot/dts/qcom/sm8550.dtsi b/arch/arm64/boot/dts/qcom/sm8550.dtsi
index 83136efb7724..7599b7b7e645 100644
--- a/arch/arm64/boot/dts/qcom/sm8550.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8550.dtsi
@@ -4620,7 +4620,7 @@
pdc: interrupt-controller@b220000 {
compatible = "qcom,sm8550-pdc", "qcom,pdc";
- reg = <0 0x0b220000 0 0x30000>, <0 0x174000f0 0 0x64>;
+ reg = <0 0x0b220000 0 0x10000>, <0 0x174000f0 0 0x64>;
qcom,pdc-ranges = <0 480 94>, <94 609 31>,
<125 63 1>, <126 716 12>,
<138 251 5>;
diff --git a/arch/arm64/boot/dts/qcom/sm8650.dtsi b/arch/arm64/boot/dts/qcom/sm8650.dtsi
index 447b788fcbb9..9ecbc0010694 100644
--- a/arch/arm64/boot/dts/qcom/sm8650.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8650.dtsi
@@ -75,6 +75,11 @@
compatible = "arm,cortex-a520";
reg = <0 0>;
+ i-cache-size = <65536>;
+ i-cache-line-size = <64>;
+ d-cache-size = <65536>;
+ d-cache-line-size = <64>;
+
clocks = <&cpufreq_hw 0>;
power-domains = <&cpu_pd0>;
@@ -103,11 +108,15 @@
cache-level = <2>;
cache-unified;
next-level-cache = <&l3_0>;
+ cache-size = <524288>;
+ cache-line-size = <64>;
l3_0: l3-cache {
compatible = "cache";
cache-level = <3>;
cache-unified;
+ cache-size = <12582912>;
+ cache-line-size = <64>;
};
};
};
@@ -117,6 +126,11 @@
compatible = "arm,cortex-a520";
reg = <0 0x100>;
+ i-cache-size = <65536>;
+ i-cache-line-size = <64>;
+ d-cache-size = <65536>;
+ d-cache-line-size = <64>;
+
clocks = <&cpufreq_hw 0>;
power-domains = <&cpu_pd1>;
@@ -146,6 +160,11 @@
compatible = "arm,cortex-a720";
reg = <0 0x200>;
+ i-cache-size = <65536>;
+ i-cache-line-size = <64>;
+ d-cache-size = <65536>;
+ d-cache-line-size = <64>;
+
clocks = <&cpufreq_hw 3>;
power-domains = <&cpu_pd2>;
@@ -153,7 +172,7 @@
enable-method = "psci";
next-level-cache = <&l2_200>;
- capacity-dmips-mhz = <1792>;
+ capacity-dmips-mhz = <2909>;
dynamic-power-coefficient = <238>;
qcom,freq-domain = <&cpufreq_hw 3>;
@@ -174,6 +193,8 @@
cache-level = <2>;
cache-unified;
next-level-cache = <&l3_0>;
+ cache-size = <524288>;
+ cache-line-size = <64>;
};
};
@@ -182,6 +203,11 @@
compatible = "arm,cortex-a720";
reg = <0 0x300>;
+ i-cache-size = <65536>;
+ i-cache-line-size = <64>;
+ d-cache-size = <65536>;
+ d-cache-line-size = <64>;
+
clocks = <&cpufreq_hw 3>;
power-domains = <&cpu_pd3>;
@@ -189,7 +215,7 @@
enable-method = "psci";
next-level-cache = <&l2_300>;
- capacity-dmips-mhz = <1792>;
+ capacity-dmips-mhz = <2909>;
dynamic-power-coefficient = <238>;
qcom,freq-domain = <&cpufreq_hw 3>;
@@ -210,6 +236,8 @@
cache-level = <2>;
cache-unified;
next-level-cache = <&l3_0>;
+ cache-size = <524288>;
+ cache-line-size = <64>;
};
};
@@ -218,6 +246,11 @@
compatible = "arm,cortex-a720";
reg = <0 0x400>;
+ i-cache-size = <65536>;
+ i-cache-line-size = <64>;
+ d-cache-size = <65536>;
+ d-cache-line-size = <64>;
+
clocks = <&cpufreq_hw 3>;
power-domains = <&cpu_pd4>;
@@ -225,7 +258,7 @@
enable-method = "psci";
next-level-cache = <&l2_400>;
- capacity-dmips-mhz = <1792>;
+ capacity-dmips-mhz = <2909>;
dynamic-power-coefficient = <238>;
qcom,freq-domain = <&cpufreq_hw 3>;
@@ -246,6 +279,8 @@
cache-level = <2>;
cache-unified;
next-level-cache = <&l3_0>;
+ cache-size = <524288>;
+ cache-line-size = <64>;
};
};
@@ -254,6 +289,11 @@
compatible = "arm,cortex-a720";
reg = <0 0x500>;
+ i-cache-size = <65536>;
+ i-cache-line-size = <64>;
+ d-cache-size = <65536>;
+ d-cache-line-size = <64>;
+
clocks = <&cpufreq_hw 1>;
power-domains = <&cpu_pd5>;
@@ -261,7 +301,7 @@
enable-method = "psci";
next-level-cache = <&l2_500>;
- capacity-dmips-mhz = <1792>;
+ capacity-dmips-mhz = <2909>;
dynamic-power-coefficient = <238>;
qcom,freq-domain = <&cpufreq_hw 1>;
@@ -282,6 +322,8 @@
cache-level = <2>;
cache-unified;
next-level-cache = <&l3_0>;
+ cache-size = <524288>;
+ cache-line-size = <64>;
};
};
@@ -290,6 +332,11 @@
compatible = "arm,cortex-a720";
reg = <0 0x600>;
+ i-cache-size = <65536>;
+ i-cache-line-size = <64>;
+ d-cache-size = <65536>;
+ d-cache-line-size = <64>;
+
clocks = <&cpufreq_hw 1>;
power-domains = <&cpu_pd6>;
@@ -297,7 +344,7 @@
enable-method = "psci";
next-level-cache = <&l2_600>;
- capacity-dmips-mhz = <1792>;
+ capacity-dmips-mhz = <2909>;
dynamic-power-coefficient = <238>;
qcom,freq-domain = <&cpufreq_hw 1>;
@@ -318,6 +365,8 @@
cache-level = <2>;
cache-unified;
next-level-cache = <&l3_0>;
+ cache-size = <524288>;
+ cache-line-size = <64>;
};
};
@@ -326,6 +375,11 @@
compatible = "arm,cortex-x4";
reg = <0 0x700>;
+ i-cache-size = <65536>;
+ i-cache-line-size = <64>;
+ d-cache-size = <65536>;
+ d-cache-line-size = <64>;
+
clocks = <&cpufreq_hw 2>;
power-domains = <&cpu_pd7>;
@@ -333,7 +387,7 @@
enable-method = "psci";
next-level-cache = <&l2_700>;
- capacity-dmips-mhz = <1894>;
+ capacity-dmips-mhz = <3591>;
dynamic-power-coefficient = <588>;
qcom,freq-domain = <&cpufreq_hw 2>;
@@ -354,6 +408,8 @@
cache-level = <2>;
cache-unified;
next-level-cache = <&l3_0>;
+ cache-size = <2097152>;
+ cache-line-size = <64>;
};
};
@@ -4681,18 +4737,18 @@
pinctrl-0 = <&rx_swr_active>;
pinctrl-names = "default";
- qcom,din-ports = <0>;
+ qcom,din-ports = <1>;
qcom,dout-ports = <11>;
- qcom,ports-sinterval = /bits/ 16 <0x03 0x1f 0x1f 0x07 0x03 0xff 0xff 0x31 0xff 0xff 0xff>;
- qcom,ports-offset1 = /bits/ 8 <0x00 0x00 0x0b 0x09 0x01 0xff 0xff 0x00 0xff 0xff 0xff>;
- qcom,ports-offset2 = /bits/ 8 <0x00 0x00 0x0b 0x00 0x00 0xff 0xff 0x00 0xff 0xff 0xff>;
- qcom,ports-hstart = /bits/ 8 <0xff 0x03 0xff 0xff 0xff 0xff 0xff 0x00 0xff 0xff 0xff>;
- qcom,ports-hstop = /bits/ 8 <0xff 0x06 0xff 0xff 0xff 0xff 0xff 0x0f 0xff 0xff 0xff>;
- qcom,ports-word-length = /bits/ 8 <0x01 0x07 0x04 0xff 0xff 0xff 0xff 0x18 0xff 0xff 0xff>;
- qcom,ports-block-pack-mode = /bits/ 8 <0xff 0x00 0x01 0xff 0xff 0xff 0xff 0x01 0xff 0xff 0xff>;
- qcom,ports-block-group-count = /bits/ 8 <0xff 0xff 0xff 0x01 0x03 0xff 0xff 0x00 0xff 0xff 0xff>;
- qcom,ports-lane-control = /bits/ 8 <0x01 0x00 0x00 0x00 0x00 0xff 0xff 0x01 0xff 0xff 0xff>;
+ qcom,ports-sinterval = /bits/ 16 <0x03 0x1f 0x1f 0x07 0x03 0xff 0xff 0x31 0xff 0xff 0xff 0xff>;
+ qcom,ports-offset1 = /bits/ 8 <0x00 0x00 0x0b 0x09 0x01 0xff 0xff 0x00 0xff 0xff 0xff 0xff>;
+ qcom,ports-offset2 = /bits/ 8 <0x00 0x00 0x0b 0x00 0x00 0xff 0xff 0x00 0xff 0xff 0xff 0xff>;
+ qcom,ports-hstart = /bits/ 8 <0xff 0x03 0xff 0xff 0xff 0xff 0xff 0x00 0xff 0xff 0xff 0xff>;
+ qcom,ports-hstop = /bits/ 8 <0xff 0x06 0xff 0xff 0xff 0xff 0xff 0x0f 0xff 0xff 0xff 0xff>;
+ qcom,ports-word-length = /bits/ 8 <0x01 0x07 0x04 0xff 0xff 0xff 0xff 0x18 0xff 0xff 0xff 0xff>;
+ qcom,ports-block-pack-mode = /bits/ 8 <0xff 0x00 0x01 0xff 0xff 0xff 0xff 0x01 0xff 0xff 0xff 0xff>;
+ qcom,ports-block-group-count = /bits/ 8 <0xff 0xff 0xff 0x01 0x03 0xff 0xff 0x00 0xff 0xff 0xff 0xff>;
+ qcom,ports-lane-control = /bits/ 8 <0x01 0x00 0x00 0x00 0x00 0xff 0xff 0x01 0xff 0xff 0xff 0xff>;
#address-cells = <2>;
#size-cells = <0>;
@@ -4778,17 +4834,17 @@
pinctrl-names = "default";
qcom,din-ports = <4>;
- qcom,dout-ports = <0>;
-
- qcom,ports-sinterval-low = /bits/ 8 <0x01 0x01 0x03 0x03>;
- qcom,ports-offset1 = /bits/ 8 <0x00 0x00 0x01 0x01>;
- qcom,ports-offset2 = /bits/ 8 <0x00 0x00 0x00 0x00>;
- qcom,ports-hstart = /bits/ 8 <0xff 0xff 0xff 0xff>;
- qcom,ports-hstop = /bits/ 8 <0xff 0xff 0xff 0xff>;
- qcom,ports-word-length = /bits/ 8 <0xff 0xff 0xff 0xff>;
- qcom,ports-block-pack-mode = /bits/ 8 <0xff 0xff 0xff 0xff>;
- qcom,ports-block-group-count = /bits/ 8 <0xff 0xff 0xff 0xff>;
- qcom,ports-lane-control = /bits/ 8 <0x01 0x02 0x00 0x00>;
+ qcom,dout-ports = <1>;
+
+ qcom,ports-sinterval-low = /bits/ 8 <0x00 0x01 0x01 0x03 0x03>;
+ qcom,ports-offset1 = /bits/ 8 <0x00 0x00 0x00 0x01 0x01>;
+ qcom,ports-offset2 = /bits/ 8 <0x00 0x00 0x00 0x00 0x00>;
+ qcom,ports-hstart = /bits/ 8 <0xff 0xff 0xff 0xff 0xff>;
+ qcom,ports-hstop = /bits/ 8 <0xff 0xff 0xff 0xff 0xff>;
+ qcom,ports-word-length = /bits/ 8 <0xff 0xff 0xff 0xff 0xff>;
+ qcom,ports-block-pack-mode = /bits/ 8 <0xff 0xff 0xff 0xff 0xff>;
+ qcom,ports-block-group-count = /bits/ 8 <0xff 0xff 0xff 0xff 0xff>;
+ qcom,ports-lane-control = /bits/ 8 <0xff 0x01 0x02 0x00 0x00>;
#address-cells = <2>;
#size-cells = <0>;
@@ -5998,7 +6054,7 @@
pdc: interrupt-controller@b220000 {
compatible = "qcom,sm8650-pdc", "qcom,pdc";
- reg = <0 0x0b220000 0 0x30000>, <0 0x174000f0 0 0x64>;
+ reg = <0 0x0b220000 0 0x10000>, <0 0x174000f0 0 0x64>;
interrupt-parent = <&intc>;
diff --git a/arch/arm64/boot/dts/qcom/sm8750.dtsi b/arch/arm64/boot/dts/qcom/sm8750.dtsi
index 8967b3817f55..4a48cc4771b0 100644
--- a/arch/arm64/boot/dts/qcom/sm8750.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8750.dtsi
@@ -1218,6 +1218,28 @@
status = "disabled";
};
+
+ uart15: serial@89c000 {
+ compatible = "qcom,geni-uart";
+ reg = <0x0 0x0089c000 0x0 0x4000>;
+
+ interrupts = <GIC_SPI 462 IRQ_TYPE_LEVEL_HIGH>;
+
+ clocks = <&gcc GCC_QUPV3_WRAP2_S7_CLK>;
+ clock-names = "se";
+
+ interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS
+ &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>,
+ <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS
+ &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>;
+ interconnect-names = "qup-core",
+ "qup-config";
+
+ pinctrl-0 = <&qup_uart15_default>;
+ pinctrl-names = "default";
+
+ status = "disabled";
+ };
};
i2c_master_hub_0: geniqup@9c0000 {
@@ -2085,12 +2107,12 @@
};
cambistmclkcc: clock-controller@1760000 {
- compatible = "qcom,sm8750-cambistmclkcc";
- reg = <0x0 0x1760000 0x0 0x6000>;
- clocks = <&gcc GCC_CAM_BIST_MCLK_AHB_CLK>,
- <&bi_tcxo_div2>,
- <&bi_tcxo_ao_div2>,
- <&sleep_clk>;
+ compatible = "qcom,sm8750-cambistmclkcc";
+ reg = <0x0 0x1760000 0x0 0x6000>;
+ clocks = <&gcc GCC_CAM_BIST_MCLK_AHB_CLK>,
+ <&bi_tcxo_div2>,
+ <&bi_tcxo_ao_div2>,
+ <&sleep_clk>;
power-domains = <&rpmhpd RPMHPD_MMCX>,
<&rpmhpd RPMHPD_MX>;
required-opps = <&rpmhpd_opp_low_svs>,
@@ -4060,6 +4082,14 @@
bias-pull-down;
};
+ qup_uart15_default: qup-uart15-default-state {
+ /* TX, RX */
+ pins = "gpio30", "gpio31";
+ function = "qup2_se7";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
sdc2_sleep: sdc2-sleep-state {
clk-pins {
pins = "sdc2_clk";
@@ -4962,7 +4992,7 @@
reg = <4>;
tpda_aoss_in4: endpoint {
- remote-endpoint =<&tpdm_swao_out>;
+ remote-endpoint = <&tpdm_swao_out>;
};
};
};
diff --git a/arch/arm64/boot/dts/qcom/talos-evk-som.dtsi b/arch/arm64/boot/dts/qcom/talos-evk-som.dtsi
index 294354c034c3..6d2cff3cf23c 100644
--- a/arch/arm64/boot/dts/qcom/talos-evk-som.dtsi
+++ b/arch/arm64/boot/dts/qcom/talos-evk-som.dtsi
@@ -317,6 +317,14 @@
status = "okay";
};
+&gpu {
+ status = "okay";
+};
+
+&gpu_zap_shader {
+ firmware-name = "qcom/qcs615/a612_zap.mbn";
+};
+
&i2c5 {
clock-frequency = <400000>;
status = "okay";
diff --git a/arch/arm64/boot/dts/qcom/talos.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi
index e506a16c9070..bdfb70ca9740 100644
--- a/arch/arm64/boot/dts/qcom/talos.dtsi
+++ b/arch/arm64/boot/dts/qcom/talos.dtsi
@@ -11,6 +11,7 @@
#include <dt-bindings/clock/qcom,qcs615-videocc.h>
#include <dt-bindings/clock/qcom,rpmh.h>
#include <dt-bindings/dma/qcom-gpi.h>
+#include <dt-bindings/firmware/qcom,scm.h>
#include <dt-bindings/interconnect/qcom,icc.h>
#include <dt-bindings/interconnect/qcom,osm-l3.h>
#include <dt-bindings/interconnect/qcom,qcs615-rpmh.h>
@@ -50,10 +51,10 @@
<&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>;
l2_0: l2-cache {
- compatible = "cache";
- cache-level = <2>;
- cache-unified;
- next-level-cache = <&l3_0>;
+ compatible = "cache";
+ cache-level = <2>;
+ cache-unified;
+ next-level-cache = <&l3_0>;
};
};
@@ -75,10 +76,10 @@
<&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>;
l2_100: l2-cache {
- compatible = "cache";
- cache-level = <2>;
- cache-unified;
- next-level-cache = <&l3_0>;
+ compatible = "cache";
+ cache-level = <2>;
+ cache-unified;
+ next-level-cache = <&l3_0>;
};
};
@@ -100,10 +101,10 @@
<&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>;
l2_200: l2-cache {
- compatible = "cache";
- cache-level = <2>;
- cache-unified;
- next-level-cache = <&l3_0>;
+ compatible = "cache";
+ cache-level = <2>;
+ cache-unified;
+ next-level-cache = <&l3_0>;
};
};
@@ -125,10 +126,10 @@
<&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>;
l2_300: l2-cache {
- compatible = "cache";
- cache-level = <2>;
- cache-unified;
- next-level-cache = <&l3_0>;
+ compatible = "cache";
+ cache-level = <2>;
+ cache-unified;
+ next-level-cache = <&l3_0>;
};
};
@@ -150,10 +151,10 @@
<&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>;
l2_400: l2-cache {
- compatible = "cache";
- cache-level = <2>;
- cache-unified;
- next-level-cache = <&l3_0>;
+ compatible = "cache";
+ cache-level = <2>;
+ cache-unified;
+ next-level-cache = <&l3_0>;
};
};
@@ -175,10 +176,10 @@
<&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>;
l2_500: l2-cache {
- compatible = "cache";
- cache-level = <2>;
- cache-unified;
- next-level-cache = <&l3_0>;
+ compatible = "cache";
+ cache-level = <2>;
+ cache-unified;
+ next-level-cache = <&l3_0>;
};
};
@@ -201,10 +202,10 @@
<&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>;
l2_600: l2-cache {
- compatible = "cache";
- cache-level = <2>;
- cache-unified;
- next-level-cache = <&l3_0>;
+ compatible = "cache";
+ cache-level = <2>;
+ cache-unified;
+ next-level-cache = <&l3_0>;
};
};
@@ -226,10 +227,10 @@
<&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>;
l2_700: l2-cache {
- compatible = "cache";
- cache-level = <2>;
- cache-unified;
- next-level-cache = <&l3_0>;
+ compatible = "cache";
+ cache-level = <2>;
+ cache-unified;
+ next-level-cache = <&l3_0>;
};
};
@@ -677,6 +678,14 @@
reg = <0x0 0x97715000 0x0 0x2000>;
no-map;
};
+
+ adsp_rpc_remote_heap_mem: adsp-rpc-remote-heap {
+ compatible = "shared-dma-pool";
+ alloc-ranges = <0x0 0x80000000 0x0 0x80000000>;
+ reusable;
+ alignment = <0x0 0x400000>;
+ size = <0x0 0x800000>;
+ };
};
soc: soc@0 {
@@ -4683,7 +4692,7 @@
pdc: interrupt-controller@b220000 {
compatible = "qcom,qcs615-pdc", "qcom,pdc";
- reg = <0x0 0x0b220000 0x0 0x30000>,
+ reg = <0x0 0x0b220000 0x0 0x10000>,
<0x0 0x17c000f0 0x0 0x64>;
qcom,pdc-ranges = <0 480 94>, <94 609 31>, <125 63 1>;
interrupt-parent = <&intc>;
@@ -5254,6 +5263,9 @@
compatible = "qcom,fastrpc";
qcom,glink-channels = "fastrpcglink-apps-dsp";
label = "adsp";
+ memory-region = <&adsp_rpc_remote_heap_mem>;
+ qcom,vmids = <QCOM_SCM_VMID_LPASS
+ QCOM_SCM_VMID_ADSP_HEAP>;
#address-cells = <1>;
#size-cells = <0>;
@@ -5460,6 +5472,7 @@
gpu-thermal {
thermal-sensors = <&tsens0 9>;
+ polling-delay-passive = <200>;
trips {
gpu_alert0: trip-point0 {
diff --git a/arch/arm64/boot/dts/qcom/x1e80100-honor-magicbook-art-14.dts b/arch/arm64/boot/dts/qcom/x1e80100-honor-magicbook-art-14.dts
new file mode 100644
index 000000000000..b70c1e094bbf
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/x1e80100-honor-magicbook-art-14.dts
@@ -0,0 +1,1341 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2025 Kirill A. Korinsky <kirill@korins.ky>
+ * Copyright (c) 2025 Valentin Manea <valentin.manea@mrs.ro>
+ * Copyright (c) 2026 Konstantin Shabanov <mail@etehtsea.me>
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/gpio-keys.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
+#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+
+#include "hamoa.dtsi"
+#include "hamoa-pmics.dtsi"
+
+/ {
+ model = "HONOR MagicBook Art 14 Snapdragon";
+ compatible = "honor,magicbook-art-14-snapdragon", "qcom,x1e80100";
+ chassis-type = "laptop";
+
+ aliases {
+ serial0 = &uart21;
+ serial1 = &uart14;
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+
+ pinctrl-0 = <&hall_int_n_default>;
+ pinctrl-names = "default";
+
+ switch-lid {
+ gpios = <&tlmm 92 GPIO_ACTIVE_LOW>;
+ linux,input-type = <EV_SW>;
+ linux,code = <SW_LID>;
+ wakeup-source;
+ wakeup-event-action = <EV_ACT_DEASSERTED>;
+ };
+ };
+
+ hdmi-bridge {
+ compatible = "realtek,rtd2171";
+
+ pinctrl-0 = <&hdmi_hpd_default>;
+ pinctrl-names = "default";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ hdmi_bridge_dp_in: endpoint {
+ remote-endpoint = <&usb_1_ss2_qmpphy_out_dp>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ hdmi_bridge_tmds_out: endpoint {
+ remote-endpoint = <&hdmi_con>;
+ };
+ };
+ };
+ };
+
+ hdmi-connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con: endpoint {
+ remote-endpoint = <&hdmi_bridge_tmds_out>;
+ };
+ };
+ };
+
+ pmic-glink {
+ compatible = "qcom,x1e80100-pmic-glink",
+ "qcom,sm8550-pmic-glink",
+ "qcom,pmic-glink";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ orientation-gpios = <&tlmm 121 GPIO_ACTIVE_HIGH>,
+ <&tlmm 123 GPIO_ACTIVE_HIGH>;
+
+ /* Left-side port, closer to the screen */
+ connector@0 {
+ compatible = "usb-c-connector";
+ reg = <0>;
+ power-role = "dual";
+ data-role = "dual";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ pmic_glink_ss0_hs_in: endpoint {
+ remote-endpoint = <&usb_1_ss0_dwc3_hs>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ pmic_glink_ss0_ss_in: endpoint {
+ remote-endpoint = <&usb_1_ss0_qmpphy_out>;
+ };
+ };
+ };
+ };
+
+ /* Left-side port, farther from the screen */
+ connector@1 {
+ compatible = "usb-c-connector";
+ reg = <1>;
+ power-role = "dual";
+ data-role = "dual";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ pmic_glink_ss1_hs_in: endpoint {
+ remote-endpoint = <&usb_1_ss1_dwc3_hs>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ pmic_glink_ss1_ss_in: endpoint {
+ remote-endpoint = <&usb_1_ss1_qmpphy_out>;
+ };
+ };
+ };
+ };
+ };
+
+ reserved-memory {
+ linux,cma {
+ compatible = "shared-dma-pool";
+ size = <0x0 0x8000000>;
+ reusable;
+ linux,cma-default;
+ };
+ };
+
+ sound {
+ compatible = "qcom,x1e80100-sndcard";
+ model = "X1E80100-HONOR-MagicBook-Art-14-Snapdragon";
+ audio-routing = "WooferLeft IN", "WSA WSA_SPK1 OUT",
+ "TweeterLeft IN", "WSA WSA_SPK2 OUT",
+ "WooferRight IN", "WSA2 WSA_SPK2 OUT",
+ "TweeterRight IN", "WSA2 WSA_SPK2 OUT",
+ "IN1_HPHL", "HPHL_OUT",
+ "IN2_HPHR", "HPHR_OUT",
+ "AMIC2", "MIC BIAS2",
+ "VA DMIC0", "MIC BIAS3",
+ "VA DMIC1", "MIC BIAS3",
+ "VA DMIC2", "MIC BIAS1",
+ "VA DMIC3", "MIC BIAS1",
+ "TX SWR_INPUT1", "ADC2_OUTPUT";
+
+ wcd-playback-dai-link {
+ link-name = "WCD Playback";
+
+ codec {
+ sound-dai = <&wcd938x 0>, <&swr1 0>, <&lpass_rxmacro 0>;
+ };
+
+ cpu {
+ sound-dai = <&q6apmbedai RX_CODEC_DMA_RX_0>;
+ };
+
+ platform {
+ sound-dai = <&q6apm>;
+ };
+ };
+
+ wcd-capture-dai-link {
+ link-name = "WCD Capture";
+
+ codec {
+ sound-dai = <&wcd938x 1>, <&swr2 1>, <&lpass_txmacro 0>;
+ };
+
+ cpu {
+ sound-dai = <&q6apmbedai TX_CODEC_DMA_TX_3>;
+ };
+
+ platform {
+ sound-dai = <&q6apm>;
+ };
+ };
+
+ wsa-dai-link {
+ link-name = "WSA Playback";
+
+ codec {
+ sound-dai = <&left_woofer>, <&left_tweeter>,
+ <&swr0 0>, <&lpass_wsamacro 0>,
+ <&right_woofer>, <&right_tweeter>,
+ <&swr3 0>, <&lpass_wsa2macro 0>;
+ };
+
+ cpu {
+ sound-dai = <&q6apmbedai WSA_CODEC_DMA_RX_0>;
+ };
+
+ platform {
+ sound-dai = <&q6apm>;
+ };
+ };
+
+ va-dai-link {
+ link-name = "VA Capture";
+
+ codec {
+ sound-dai = <&lpass_vamacro 0>;
+ };
+
+ cpu {
+ sound-dai = <&q6apmbedai VA_CODEC_DMA_TX_0>;
+ };
+
+ platform {
+ sound-dai = <&q6apm>;
+ };
+ };
+ };
+
+ vreg_misc_3p3: regulator-misc-3p3 {
+ compatible = "regulator-fixed";
+
+ regulator-name = "VREG_MISC_3P3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+
+ gpio = <&pm8550ve_8_gpios 6 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+
+ pinctrl-0 = <&misc_3p3_reg_en>;
+ pinctrl-names = "default";
+
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ vph_pwr: regulator-vph-pwr {
+ compatible = "regulator-fixed";
+
+ regulator-name = "vph_pwr";
+ regulator-min-microvolt = <3700000>;
+ regulator-max-microvolt = <3700000>;
+
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ vreg_wcn_0p95: regulator-wcn-0p95 {
+ compatible = "regulator-fixed";
+
+ regulator-name = "VREG_WCN_0P95";
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <950000>;
+
+ vin-supply = <&vreg_wcn_3p3>;
+ };
+
+ vreg_wcn_1p9: regulator-wcn-1p9 {
+ compatible = "regulator-fixed";
+
+ regulator-name = "VREG_WCN_1P9";
+ regulator-min-microvolt = <1900000>;
+ regulator-max-microvolt = <1900000>;
+
+ vin-supply = <&vreg_wcn_3p3>;
+ };
+
+ vreg_wcn_3p3: regulator-wcn-3p3 {
+ compatible = "regulator-fixed";
+
+ regulator-name = "VREG_WCN_3P3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+
+ gpio = <&tlmm 214 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+
+ pinctrl-0 = <&wcn_sw_en>;
+ pinctrl-names = "default";
+
+ regulator-boot-on;
+ };
+
+ wcd938x: audio-codec {
+ compatible = "qcom,wcd9385-codec";
+
+ pinctrl-0 = <&wcd_default>;
+ pinctrl-names = "default";
+
+ qcom,micbias1-microvolt = <1800000>;
+ qcom,micbias2-microvolt = <1800000>;
+ qcom,micbias3-microvolt = <1800000>;
+ qcom,micbias4-microvolt = <1800000>;
+ qcom,mbhc-buttons-vthreshold-microvolt = <75000 150000 237000 500000 500000 500000 500000 500000>;
+ qcom,mbhc-headset-vthreshold-microvolt = <1700000>;
+ qcom,mbhc-headphone-vthreshold-microvolt = <50000>;
+ qcom,rx-device = <&wcd_rx>;
+ qcom,tx-device = <&wcd_tx>;
+
+ reset-gpios = <&tlmm 191 GPIO_ACTIVE_LOW>;
+
+ vdd-buck-supply = <&vreg_l15b_1p8>;
+ vdd-rxtx-supply = <&vreg_l15b_1p8>;
+ vdd-io-supply = <&vreg_l15b_1p8>;
+ vdd-mic-bias-supply = <&vreg_bob1>;
+
+ #sound-dai-cells = <1>;
+ };
+
+ wcn7850-pmu {
+ compatible = "qcom,wcn7850-pmu";
+
+ wlan-enable-gpios = <&tlmm 117 GPIO_ACTIVE_HIGH>;
+ bt-enable-gpios = <&tlmm 116 GPIO_ACTIVE_HIGH>;
+
+ pinctrl-0 = <&wcn_wlan_bt_en>;
+ pinctrl-names = "default";
+
+ vdd-supply = <&vreg_wcn_0p95>;
+ vddio-supply = <&vreg_l15b_1p8>;
+ vddaon-supply = <&vreg_wcn_0p95>;
+ vdddig-supply = <&vreg_wcn_0p95>;
+ vddrfa1p2-supply = <&vreg_wcn_1p9>;
+ vddrfa1p8-supply = <&vreg_wcn_1p9>;
+
+ regulators {
+ vreg_pmu_rfa_cmn: ldo0 {
+ regulator-name = "vreg_pmu_rfa_cmn";
+ };
+
+ vreg_pmu_aon_0p59: ldo1 {
+ regulator-name = "vreg_pmu_aon_0p59";
+ };
+
+ vreg_pmu_wlcx_0p8: ldo2 {
+ regulator-name = "vreg_pmu_wlcx_0p8";
+ };
+
+ vreg_pmu_wlmx_0p85: ldo3 {
+ regulator-name = "vreg_pmu_wlmx_0p85";
+ };
+
+ vreg_pmu_btcmx_0p85: ldo4 {
+ regulator-name = "vreg_pmu_btcmx_0p85";
+ };
+
+ vreg_pmu_rfa_0p8: ldo5 {
+ regulator-name = "vreg_pmu_rfa_0p8";
+ };
+
+ vreg_pmu_rfa_1p2: ldo6 {
+ regulator-name = "vreg_pmu_rfa_1p2";
+ };
+
+ vreg_pmu_rfa_1p8: ldo7 {
+ regulator-name = "vreg_pmu_rfa_1p8";
+ };
+
+ vreg_pmu_pcie_0p9: ldo8 {
+ regulator-name = "vreg_pmu_pcie_0p9";
+ };
+
+ vreg_pmu_pcie_1p8: ldo9 {
+ regulator-name = "vreg_pmu_pcie_1p8";
+ };
+ };
+ };
+};
+
+&apps_rsc {
+ regulators-0 {
+ compatible = "qcom,pm8550-rpmh-regulators";
+ qcom,pmic-id = "b";
+
+ vdd-bob1-supply = <&vph_pwr>;
+ vdd-bob2-supply = <&vph_pwr>;
+ vdd-l1-l4-l10-supply = <&vreg_s4c_1p8>;
+ vdd-l2-l13-l14-supply = <&vreg_bob1>;
+ vdd-l5-l16-supply = <&vreg_bob1>;
+ vdd-l6-l7-supply = <&vreg_bob2>;
+ vdd-l8-l9-supply = <&vreg_bob1>;
+ vdd-l12-supply = <&vreg_s5j_1p2>;
+ vdd-l15-supply = <&vreg_s4c_1p8>;
+ vdd-l17-supply = <&vreg_bob2>;
+
+ vreg_bob1: bob1 {
+ regulator-name = "vreg_bob1";
+ regulator-min-microvolt = <3008000>;
+ regulator-max-microvolt = <3960000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_bob2: bob2 {
+ regulator-name = "vreg_bob2";
+ regulator-min-microvolt = <2504000>;
+ regulator-max-microvolt = <3008000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l1b_1p8: ldo1 {
+ regulator-name = "vreg_l1b_1p8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l2b_3p0: ldo2 {
+ regulator-name = "vreg_l2b_3p0";
+ regulator-min-microvolt = <3072000>;
+ regulator-max-microvolt = <3100000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l4b_1p8: ldo4 {
+ regulator-name = "vreg_l4b_1p8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l5b_3p0: ldo5 {
+ regulator-name = "vreg_l5b_3p0";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l6b_1p8: ldo6 {
+ regulator-name = "vreg_l6b_1p8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2960000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l7b_2p8: ldo7 {
+ regulator-name = "vreg_l7b_2p8";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l8b_3p0: ldo8 {
+ regulator-name = "vreg_l8b_3p0";
+ regulator-min-microvolt = <3072000>;
+ regulator-max-microvolt = <3072000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l9b_2p9: ldo9 {
+ regulator-name = "vreg_l9b_2p9";
+ regulator-min-microvolt = <2960000>;
+ regulator-max-microvolt = <2960000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l10b_1p8: ldo10 {
+ regulator-name = "vreg_l10b_1p8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l12b_1p2: ldo12 {
+ regulator-name = "vreg_l12b_1p2";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ regulator-always-on;
+ };
+
+ vreg_l13b_3p0: ldo13 {
+ regulator-name = "vreg_l13b_3p0";
+ regulator-min-microvolt = <3072000>;
+ regulator-max-microvolt = <3100000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l14b_3p0: ldo14 {
+ regulator-name = "vreg_l14b_3p0";
+ regulator-min-microvolt = <3072000>;
+ regulator-max-microvolt = <3072000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l15b_1p8: ldo15 {
+ regulator-name = "vreg_l15b_1p8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ regulator-always-on;
+ };
+
+ vreg_l16b_2p9: ldo16 {
+ regulator-name = "vreg_l16b_2p9";
+ regulator-min-microvolt = <2912000>;
+ regulator-max-microvolt = <2912000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l17b_2p5: ldo17 {
+ regulator-name = "vreg_l17b_2p5";
+ regulator-min-microvolt = <2504000>;
+ regulator-max-microvolt = <2504000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+ };
+
+ regulators-1 {
+ compatible = "qcom,pm8550ve-rpmh-regulators";
+ qcom,pmic-id = "c";
+
+ vdd-l1-supply = <&vreg_s5j_1p2>;
+ vdd-l2-supply = <&vreg_s1f_0p7>;
+ vdd-l3-supply = <&vreg_s1f_0p7>;
+ vdd-s4-supply = <&vph_pwr>;
+
+ vreg_s4c_1p8: smps4 {
+ regulator-name = "vreg_s4c_1p8";
+ regulator-min-microvolt = <1856000>;
+ regulator-max-microvolt = <2000000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l1c_1p2: ldo1 {
+ regulator-name = "vreg_l1c_1p2";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l2c_0p8: ldo2 {
+ regulator-name = "vreg_l2c_0p8";
+ regulator-min-microvolt = <880000>;
+ regulator-max-microvolt = <920000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l3c_0p8: ldo3 {
+ regulator-name = "vreg_l3c_0p8";
+ regulator-min-microvolt = <880000>;
+ regulator-max-microvolt = <920000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+ };
+
+ regulators-2 {
+ compatible = "qcom,pmc8380-rpmh-regulators";
+ qcom,pmic-id = "d";
+
+ vdd-l1-supply = <&vreg_s1f_0p7>;
+ vdd-l2-supply = <&vreg_s1f_0p7>;
+ vdd-l3-supply = <&vreg_s4c_1p8>;
+ vdd-s1-supply = <&vph_pwr>;
+
+ vreg_l1d_0p8: ldo1 {
+ regulator-name = "vreg_l1d_0p8";
+ regulator-min-microvolt = <880000>;
+ regulator-max-microvolt = <920000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l2d_0p9: ldo2 {
+ regulator-name = "vreg_l2d_0p9";
+ regulator-min-microvolt = <912000>;
+ regulator-max-microvolt = <920000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l3d_1p8: ldo3 {
+ regulator-name = "vreg_l3d_1p8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+ };
+
+ regulators-3 {
+ compatible = "qcom,pmc8380-rpmh-regulators";
+ qcom,pmic-id = "e";
+
+ vdd-l2-supply = <&vreg_s1f_0p7>;
+ vdd-l3-supply = <&vreg_s5j_1p2>;
+
+ vreg_l2e_0p8: ldo2 {
+ regulator-name = "vreg_l2e_0p8";
+ regulator-min-microvolt = <880000>;
+ regulator-max-microvolt = <920000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l3e_1p2: ldo3 {
+ regulator-name = "vreg_l3e_1p2";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+ };
+
+ regulators-4 {
+ compatible = "qcom,pmc8380-rpmh-regulators";
+ qcom,pmic-id = "f";
+
+ vdd-l1-supply = <&vreg_s5j_1p2>;
+ vdd-l2-supply = <&vreg_s5j_1p2>;
+ vdd-l3-supply = <&vreg_s5j_1p2>;
+ vdd-s1-supply = <&vph_pwr>;
+
+ vreg_s1f_0p7: smps1 {
+ regulator-name = "vreg_s1f_0p7";
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l1f_1p0: ldo1 {
+ regulator-name = "vreg_l1f_1p0";
+ regulator-min-microvolt = <1024000>;
+ regulator-max-microvolt = <1024000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l2f_1p0: ldo2 {
+ regulator-name = "vreg_l2f_1p0";
+ regulator-min-microvolt = <1024000>;
+ regulator-max-microvolt = <1024000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l3f_1p0: ldo3 {
+ regulator-name = "vreg_l3f_1p0";
+ regulator-min-microvolt = <1024000>;
+ regulator-max-microvolt = <1024000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+ };
+
+ regulators-6 {
+ compatible = "qcom,pm8550ve-rpmh-regulators";
+ qcom,pmic-id = "i";
+
+ vdd-l1-supply = <&vreg_s4c_1p8>;
+ vdd-l2-supply = <&vreg_s5j_1p2>;
+ vdd-l3-supply = <&vreg_s1f_0p7>;
+ vdd-s1-supply = <&vph_pwr>;
+ vdd-s2-supply = <&vph_pwr>;
+
+ vreg_s1i_0p9: smps1 {
+ regulator-name = "vreg_s1i_0p9";
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <920000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_s2i_1p0: smps2 {
+ regulator-name = "vreg_s2i_1p0";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l1i_1p8: ldo1 {
+ regulator-name = "vreg_l1i_1p8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l2i_1p2: ldo2 {
+ regulator-name = "vreg_l2i_1p2";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l3i_0p8: ldo3 {
+ regulator-name = "vreg_l3i_0p8";
+ regulator-min-microvolt = <880000>;
+ regulator-max-microvolt = <920000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+ };
+
+ regulators-7 {
+ compatible = "qcom,pm8550ve-rpmh-regulators";
+ qcom,pmic-id = "j";
+
+ vdd-l1-supply = <&vreg_s1f_0p7>;
+ vdd-l2-supply = <&vreg_s5j_1p2>;
+ vdd-l3-supply = <&vreg_s1f_0p7>;
+ vdd-s5-supply = <&vph_pwr>;
+
+ vreg_s5j_1p2: smps5 {
+ regulator-name = "vreg_s5j_1p2";
+ regulator-min-microvolt = <1256000>;
+ regulator-max-microvolt = <1304000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l1j_0p8: ldo1 {
+ regulator-name = "vreg_l1j_0p8";
+ regulator-min-microvolt = <880000>;
+ regulator-max-microvolt = <920000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l2j_1p2: ldo2 {
+ regulator-name = "vreg_l2j_1p2";
+ regulator-min-microvolt = <1256000>;
+ regulator-max-microvolt = <1256000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l3j_0p8: ldo3 {
+ regulator-name = "vreg_l3j_0p8";
+ regulator-min-microvolt = <880000>;
+ regulator-max-microvolt = <920000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+ };
+};
+
+&gpu {
+ status = "okay";
+
+ zap-shader {
+ firmware-name = "qcom/x1e80100/HONOR/MRO-XXX/qcdxkmsuc8380.mbn";
+ };
+};
+
+&i2c1 {
+ clock-frequency = <400000>;
+
+ status = "okay";
+
+ touchpad@5d {
+ compatible = "hid-over-i2c";
+ reg = <0x5d>;
+
+ hid-descr-addr = <0x1>;
+ interrupts-extended = <&tlmm 24 IRQ_TYPE_LEVEL_LOW>;
+
+ vdd-supply = <&vreg_misc_3p3>;
+ vddl-supply = <&vreg_l12b_1p2>;
+
+ pinctrl-0 = <&tpad_default>;
+ pinctrl-names = "default";
+
+ wakeup-source;
+ };
+};
+
+&i2c5 {
+ clock-frequency = <400000>;
+
+ status = "okay";
+
+ eusb5_repeater: redriver@43 {
+ compatible = "nxp,ptn3222";
+ reg = <0x43>;
+ #phy-cells = <0>;
+
+ vdd3v3-supply = <&vreg_l13b_3p0>;
+ vdd1v8-supply = <&vreg_l4b_1p8>;
+
+ reset-gpios = <&tlmm 7 GPIO_ACTIVE_LOW>;
+
+ pinctrl-0 = <&eusb5_reset_n>;
+ pinctrl-names = "default";
+ };
+
+ eusb6_repeater: redriver@4f {
+ compatible = "nxp,ptn3222";
+ reg = <0x4f>;
+ #phy-cells = <0>;
+
+ vdd3v3-supply = <&vreg_l13b_3p0>;
+ vdd1v8-supply = <&vreg_l4b_1p8>;
+
+ reset-gpios = <&tlmm 184 GPIO_ACTIVE_LOW>;
+
+ pinctrl-0 = <&eusb6_reset_n>;
+ pinctrl-names = "default";
+ };
+};
+
+&i2c8 {
+ clock-frequency = <400000>;
+
+ status = "okay";
+
+ touchscreen@38 {
+ compatible = "hid-over-i2c";
+ reg = <0x38>;
+
+ hid-descr-addr = <0x1>;
+ interrupts-extended = <&tlmm 51 IRQ_TYPE_LEVEL_LOW>;
+
+ vdd-supply = <&vreg_misc_3p3>;
+
+ pinctrl-0 = <&ts0_default>;
+ pinctrl-names = "default";
+ };
+};
+
+&i2c9 {
+ clock-frequency = <400000>;
+
+ status = "okay";
+
+ keyboard@3a {
+ compatible = "hid-over-i2c";
+ reg = <0x3a>;
+
+ hid-descr-addr = <0x1>;
+ interrupts-extended = <&tlmm 67 IRQ_TYPE_LEVEL_LOW>;
+
+ vdd-supply = <&vreg_misc_3p3>;
+ vddl-supply = <&vreg_l12b_1p2>;
+
+ pinctrl-0 = <&kybd_default>;
+ pinctrl-names = "default";
+
+ wakeup-source;
+ };
+};
+
+&iris {
+ firmware-name = "qcom/x1e80100/HONOR/MRO-XXX/qcvss8380.mbn";
+
+ status = "okay";
+};
+
+&lpass_tlmm {
+ spkr_01_sd_n_active: spkr-01-sd-n-active-state {
+ pins = "gpio12";
+ function = "gpio";
+ drive-strength = <16>;
+ bias-disable;
+ output-low;
+ };
+
+ spkr_23_sd_n_active: spkr-23-sd-n-active-state {
+ pins = "gpio13";
+ function = "gpio";
+ drive-strength = <16>;
+ bias-disable;
+ output-low;
+ };
+};
+
+&lpass_vamacro {
+ pinctrl-0 = <&dmic01_default>, <&dmic23_default>;
+ pinctrl-names = "default";
+
+ vdd-micb-supply = <&vreg_l1b_1p8>;
+ qcom,dmic-sample-rate = <4800000>;
+};
+
+&mdss {
+ status = "okay";
+};
+
+&mdss_dp0 {
+ status = "okay";
+};
+
+&mdss_dp0_out {
+ link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>;
+};
+
+&mdss_dp1 {
+ status = "okay";
+};
+
+&mdss_dp1_out {
+ link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>;
+};
+
+&mdss_dp2 {
+ status = "okay";
+};
+
+&mdss_dp2_out {
+ link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>;
+};
+
+&pcie4 {
+ pinctrl-0 = <&pcie4_default>;
+ pinctrl-names = "default";
+
+ status = "okay";
+};
+
+&pcie4_phy {
+ vdda-phy-supply = <&vreg_l3i_0p8>;
+ vdda-pll-supply = <&vreg_l3e_1p2>;
+
+ status = "okay";
+};
+
+&pcie4_port0 {
+ reset-gpios = <&tlmm 146 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 148 GPIO_ACTIVE_LOW>;
+
+ wifi@0 {
+ compatible = "pci17cb,1107";
+ reg = <0x10000 0x0 0x0 0x0 0x0>;
+
+ vddaon-supply = <&vreg_pmu_aon_0p59>;
+ vddwlcx-supply = <&vreg_pmu_wlcx_0p8>;
+ vddwlmx-supply = <&vreg_pmu_wlmx_0p85>;
+ vddrfacmn-supply = <&vreg_pmu_rfa_cmn>;
+ vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>;
+ vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>;
+ vddrfa1p8-supply = <&vreg_pmu_rfa_1p8>;
+ vddpcie0p9-supply = <&vreg_pmu_pcie_0p9>;
+ vddpcie1p8-supply = <&vreg_pmu_pcie_1p8>;
+ };
+};
+
+&pm8550ve_8_gpios {
+ misc_3p3_reg_en: misc-3p3-reg-en-state {
+ pins = "gpio6";
+ function = "normal";
+ bias-disable;
+ input-disable;
+ output-enable;
+ drive-push-pull;
+ power-source = <1>; /* 1.8 V */
+ qcom,drive-strength = <PMIC_GPIO_STRENGTH_LOW>;
+ };
+};
+
+&qupv3_0 {
+ status = "okay";
+};
+
+&qupv3_1 {
+ status = "okay";
+};
+
+&qupv3_2 {
+ status = "okay";
+};
+
+&remoteproc_adsp {
+ firmware-name = "qcom/x1e80100/HONOR/MRO-XXX/qcadsp8380.mbn",
+ "qcom/x1e80100/HONOR/MRO-XXX/adsp_dtbs.elf";
+
+ status = "okay";
+};
+
+&remoteproc_cdsp {
+ firmware-name = "qcom/x1e80100/HONOR/MRO-XXX/qccdsp8380.mbn",
+ "qcom/x1e80100/HONOR/MRO-XXX/cdsp_dtbs.elf";
+
+ status = "okay";
+};
+
+&swr0 {
+ status = "okay";
+
+ pinctrl-0 = <&wsa_swr_active>, <&spkr_01_sd_n_active>;
+ pinctrl-names = "default";
+
+ /* WSA8845, Left Woofer */
+ left_woofer: speaker@0,0 {
+ compatible = "sdw20217020400";
+ reg = <0 0>;
+ reset-gpios = <&lpass_tlmm 12 GPIO_ACTIVE_LOW>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "WooferLeft";
+ vdd-1p8-supply = <&vreg_l15b_1p8>;
+ vdd-io-supply = <&vreg_l12b_1p2>;
+ qcom,port-mapping = <1 2 3 7 10 13>;
+ };
+
+ /* WSA8845, Left Tweeter */
+ left_tweeter: speaker@0,1 {
+ compatible = "sdw20217020400";
+ reg = <0 1>;
+ reset-gpios = <&lpass_tlmm 12 GPIO_ACTIVE_LOW>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "TweeterLeft";
+ vdd-1p8-supply = <&vreg_l15b_1p8>;
+ vdd-io-supply = <&vreg_l12b_1p2>;
+ qcom,port-mapping = <4 5 6 7 11 13>;
+ };
+};
+
+&swr1 {
+ status = "okay";
+
+ /* WCD9385 RX */
+ wcd_rx: codec@0,4 {
+ compatible = "sdw20217010d00";
+ reg = <0 4>;
+ qcom,rx-port-mapping = <1 2 3 4 5>;
+ };
+};
+
+&swr2 {
+ status = "okay";
+
+ /* WCD9385 TX */
+ wcd_tx: codec@0,3 {
+ compatible = "sdw20217010d00";
+ reg = <0 3>;
+ qcom,tx-port-mapping = <2 2 3 4>;
+ };
+};
+
+&swr3 {
+ pinctrl-0 = <&wsa2_swr_active>, <&spkr_23_sd_n_active>;
+ pinctrl-names = "default";
+
+ status = "okay";
+
+ /* WSA8845, Right Woofer */
+ right_woofer: speaker@0,0 {
+ compatible = "sdw20217020400";
+ reg = <0 0>;
+ reset-gpios = <&lpass_tlmm 13 GPIO_ACTIVE_LOW>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "WooferRight";
+ vdd-1p8-supply = <&vreg_l15b_1p8>;
+ vdd-io-supply = <&vreg_l12b_1p2>;
+ qcom,port-mapping = <1 2 3 7 10 13>;
+ };
+
+ /* WSA8845, Right Tweeter */
+ right_tweeter: speaker@0,1 {
+ compatible = "sdw20217020400";
+ reg = <0 1>;
+ reset-gpios = <&lpass_tlmm 13 GPIO_ACTIVE_LOW>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "TweeterRight";
+ vdd-1p8-supply = <&vreg_l15b_1p8>;
+ vdd-io-supply = <&vreg_l12b_1p2>;
+ qcom,port-mapping = <4 5 6 7 11 13>;
+ };
+};
+
+&tlmm {
+ gpio-reserved-ranges = <34 2>, /* Unused */
+ <44 4>; /* SPI (TPM) */
+
+ tpad_default: tpad-default-state {
+ pins = "gpio3";
+ function = "gpio";
+ bias-disable;
+ };
+
+ eusb5_reset_n: eusb5-reset-n-state {
+ pins = "gpio7";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ ts0_default: ts0-default-state {
+ reset-n-pins {
+ pins = "gpio48";
+ function = "gpio";
+ drive-strength = <16>;
+ };
+
+ int-n-pins {
+ pins = "gpio51";
+ function = "gpio";
+ bias-disable;
+ };
+ };
+
+ kybd_default: kybd-default-state {
+ pins = "gpio67";
+ function = "gpio";
+ bias-disable;
+ };
+
+ hall_int_n_default: hall-int-n-state {
+ pins = "gpio92";
+ function = "gpio";
+ bias-disable;
+ };
+
+ wcn_wlan_bt_en: wcn-wlan-bt-en-state {
+ pins = "gpio116", "gpio117";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ hdmi_hpd_default: hdmi-hpd-default-state {
+ pins = "gpio126";
+ function = "usb2_dp";
+ bias-disable;
+ };
+
+ pcie4_default: pcie4-default-state {
+ perst-n-pins {
+ pins = "gpio146";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ clkreq-n-pins {
+ pins = "gpio147";
+ function = "pcie4_clk";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ wake-n-pins {
+ pins = "gpio148";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ eusb6_reset_n: eusb6-reset-n-state {
+ pins = "gpio184";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ wcd_default: wcd-reset-n-active-state {
+ pins = "gpio191";
+ function = "gpio";
+ drive-strength = <16>;
+ bias-disable;
+ };
+
+ wcn_sw_en: wcn-sw-en-state {
+ pins = "gpio214";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+};
+
+&uart14 {
+ status = "okay";
+
+ bluetooth {
+ compatible = "qcom,wcn7850-bt";
+ max-speed = <3200000>;
+
+ vddaon-supply = <&vreg_pmu_aon_0p59>;
+ vddrfacmn-supply = <&vreg_pmu_rfa_cmn>;
+ vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>;
+ vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>;
+ vddrfa1p8-supply = <&vreg_pmu_rfa_1p8>;
+ vddwlcx-supply = <&vreg_pmu_wlcx_0p8>;
+ vddwlmx-supply = <&vreg_pmu_wlmx_0p85>;
+ };
+};
+
+&uart21 {
+ compatible = "qcom,geni-debug-uart";
+
+ status = "okay";
+};
+
+&ufs_mem_hc {
+ reset-gpios = <&tlmm 238 GPIO_ACTIVE_LOW>;
+
+ vcc-supply = <&vreg_l17b_2p5>;
+ vcc-max-microamp = <600000>;
+ vccq-supply = <&vreg_l2i_1p2>;
+ vccq-max-microamp = <600000>;
+
+ status = "okay";
+};
+
+&ufs_mem_phy {
+ vdda-phy-supply = <&vreg_l3i_0p8>;
+ vdda-pll-supply = <&vreg_l3e_1p2>;
+
+ status = "okay";
+};
+
+&usb_1_ss0 {
+ dr_mode = "host";
+
+ status = "okay";
+};
+
+&usb_1_ss0_dwc3_hs {
+ remote-endpoint = <&pmic_glink_ss0_hs_in>;
+};
+
+&usb_1_ss0_hsphy {
+ vdd-supply = <&vreg_l3j_0p8>;
+ vdda12-supply = <&vreg_l2j_1p2>;
+
+ status = "okay";
+};
+
+&usb_1_ss0_qmpphy {
+ vdda-phy-supply = <&vreg_l2j_1p2>;
+ vdda-pll-supply = <&vreg_l1j_0p8>;
+
+ status = "okay";
+};
+
+&usb_1_ss0_qmpphy_out {
+ remote-endpoint = <&pmic_glink_ss0_ss_in>;
+};
+
+&usb_1_ss1 {
+ dr_mode = "host";
+
+ status = "okay";
+};
+
+&usb_1_ss1_dwc3_hs {
+ remote-endpoint = <&pmic_glink_ss1_hs_in>;
+};
+
+&usb_1_ss1_hsphy {
+ vdd-supply = <&vreg_l3j_0p8>;
+ vdda12-supply = <&vreg_l2j_1p2>;
+
+ status = "okay";
+};
+
+&usb_1_ss1_qmpphy {
+ vdda-phy-supply = <&vreg_l2j_1p2>;
+ vdda-pll-supply = <&vreg_l2d_0p9>;
+
+ status = "okay";
+};
+
+&usb_1_ss1_qmpphy_out {
+ remote-endpoint = <&pmic_glink_ss1_ss_in>;
+};
+
+&usb_1_ss2_qmpphy {
+ vdda-phy-supply = <&vreg_l2j_1p2>;
+ vdda-pll-supply = <&vreg_l2d_0p9>;
+
+ /delete-property/ mode-switch;
+ /delete-property/ orientation-switch;
+
+ status = "okay";
+
+ ports {
+ port@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /delete-node/ endpoint;
+
+ usb_1_ss2_qmpphy_out_dp: endpoint@0 {
+ reg = <0>;
+
+ data-lanes = <3 2 1 0>;
+ remote-endpoint = <&hdmi_bridge_dp_in>;
+ };
+ };
+ };
+};
+
+/* usb_2 is for camera, USB port on top of the screen */
+&usb_2 {
+ dr_mode = "host";
+
+ status = "okay";
+};
+
+&usb_2_hsphy {
+ vdd-supply = <&vreg_l3j_0p8>;
+ vdda12-supply = <&vreg_l2j_1p2>;
+ phys = <&eusb5_repeater>;
+
+ status = "okay";
+};
+
+/* MP0 goes to the USB-A port (USB3) and FPC */
+&usb_mp {
+ status = "okay";
+};
+
+&usb_mp_hsphy0 {
+ vdd-supply = <&vreg_l2e_0p8>;
+ vdda12-supply = <&vreg_l3e_1p2>;
+
+ status = "okay";
+};
+
+&usb_mp_hsphy1 {
+ vdd-supply = <&vreg_l2e_0p8>;
+ vdda12-supply = <&vreg_l3e_1p2>;
+
+ phys = <&eusb6_repeater>;
+
+ status = "okay";
+};
+
+&usb_mp_qmpphy0 {
+ vdda-phy-supply = <&vreg_l3e_1p2>;
+ vdda-pll-supply = <&vreg_l3c_0p8>;
+
+ status = "okay";
+};
+
+&usb_mp_qmpphy1 {
+ vdda-phy-supply = <&vreg_l3e_1p2>;
+ vdda-pll-supply = <&vreg_l3c_0p8>;
+
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/x1p42100-microsoft-sp12in.dts b/arch/arm64/boot/dts/qcom/x1p42100-microsoft-sp12in.dts
new file mode 100644
index 000000000000..0314b2246cdb
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/x1p42100-microsoft-sp12in.dts
@@ -0,0 +1,1194 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2024, Linaro Limited
+ * Copyright (c) 2025, Jens Glathe
+ * Copyright (c) 2025, Harrison Vanderbyl
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/gpio-keys.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
+#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+#include <dt-bindings/clock/qcom,x1e80100-tcsr.h>
+
+#include "purwa.dtsi"
+#include "hamoa-pmics.dtsi"
+
+/delete-node/ &pmc8380_6;
+/delete-node/ &pmc8380_6_thermal;
+
+/ {
+ model = "Surface Pro 12in 1st Edition";
+ compatible = "microsoft,surface-pro-12in", "qcom,x1p42100";
+ chassis-type = "tablet";
+
+ aliases {
+ serial0 = &uart2;
+ serial1 = &uart14;
+ };
+
+ backlight: backlight {
+ compatible = "pwm-backlight";
+ pwms = <&pmk8550_pwm 0 5000000>;
+
+ power-supply = <&vreg_edp_3p3>;
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+
+ pinctrl-0 = <&hall_int_n_default>, <&vol_up_n_default>, <&vol_down_n_default>;
+ pinctrl-names = "default";
+
+ switch-lid {
+ gpios = <&tlmm 2 GPIO_ACTIVE_LOW>;
+ linux,input-type = <EV_SW>;
+ linux,code = <SW_LID>;
+ wakeup-source;
+ wakeup-event-action = <EV_ACT_DEASSERTED>;
+ };
+
+ key-vol-up {
+ gpios = <&pm8550_gpios 8 GPIO_ACTIVE_LOW>;
+ linux,code = <KEY_VOLUMEUP>;
+ debounce-interval = <15>;
+ linux,can-disable;
+ wakeup-source;
+ };
+
+ key-vol-down {
+ gpios = <&pm8550_gpios 6 GPIO_ACTIVE_LOW>;
+ linux,code = <KEY_VOLUMEDOWN>;
+ debounce-interval = <15>;
+ linux,can-disable;
+ wakeup-source;
+ };
+ };
+
+ pmic-glink {
+ compatible = "qcom,x1e80100-pmic-glink",
+ "qcom,sm8550-pmic-glink",
+ "qcom,pmic-glink";
+ orientation-gpios = <&tlmm 121 GPIO_ACTIVE_HIGH>,
+ <&tlmm 123 GPIO_ACTIVE_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* Right-side upper port */
+ connector@0 {
+ compatible = "usb-c-connector";
+ reg = <0>;
+ power-role = "dual";
+ data-role = "dual";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ pmic_glink_ss0_hs_in: endpoint {
+ remote-endpoint = <&usb_1_ss0_dwc3_hs>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ pmic_glink_ss0_ss_in: endpoint {
+ remote-endpoint = <&usb_1_ss0_qmpphy_out>;
+ };
+ };
+
+ port@2 {
+ reg = <2>;
+
+ pmic_glink_ss0_sbu: endpoint {
+ remote-endpoint = <&usb_1_ss0_sbu_mux>;
+ };
+ };
+ };
+ };
+
+ /* Right-side lower port */
+ connector@1 {
+ compatible = "usb-c-connector";
+ reg = <1>;
+ power-role = "dual";
+ data-role = "dual";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ pmic_glink_ss1_hs_in: endpoint {
+ remote-endpoint = <&usb_1_ss1_dwc3_hs>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ pmic_glink_ss1_ss_in: endpoint {
+ remote-endpoint = <&usb_1_ss1_qmpphy_out>;
+ };
+ };
+
+ port@2 {
+ reg = <2>;
+
+ pmic_glink_ss1_sbu: endpoint {
+ remote-endpoint = <&usb_1_ss1_sbu_mux>;
+ };
+ };
+ };
+ };
+ };
+
+ reserved-memory {
+ linux,cma {
+ compatible = "shared-dma-pool";
+ size = <0x0 0x20000000>;
+ reusable;
+ linux,cma-default;
+ };
+ };
+
+ vreg_edp_3p3: regulator-edp-3p3 {
+ compatible = "regulator-fixed";
+
+ regulator-name = "VREG_EDP_3P3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+
+ gpio = <&tlmm 70 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+
+ pinctrl-0 = <&edp_reg_en>;
+ pinctrl-names = "default";
+
+ regulator-boot-on;
+ vin-supply = <&vreg_panel_en>;
+ };
+
+ vreg_panel_en: regulator-panel-en {
+ compatible = "regulator-fixed";
+
+ regulator-name = "VREG_PANEL_EN";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+
+ gpio = <&tlmm 29 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+
+ regulator-enable-ramp-delay = <150000>;
+
+ pinctrl-0 = <&panel_en>;
+ pinctrl-names = "default";
+
+ regulator-boot-on;
+ };
+
+ vph_pwr: regulator-vph-pwr {
+ compatible = "regulator-fixed";
+
+ regulator-name = "vph_pwr";
+ regulator-min-microvolt = <3700000>;
+ regulator-max-microvolt = <3700000>;
+ };
+
+ vreg_wcn_0p95: regulator-wcn-0p95 {
+ compatible = "regulator-fixed";
+
+ regulator-name = "VREG_WCN_0P95";
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <950000>;
+
+ vin-supply = <&vreg_wcn_3p3>;
+ };
+
+ vreg_wcn_1p9: regulator-wcn-1p9 {
+ compatible = "regulator-fixed";
+
+ regulator-name = "VREG_WCN_1P9";
+ regulator-min-microvolt = <1900000>;
+ regulator-max-microvolt = <1900000>;
+
+ vin-supply = <&vreg_wcn_3p3>;
+ };
+
+ vreg_wcn_3p3: regulator-wcn-3p3 {
+ compatible = "regulator-fixed";
+
+ regulator-name = "VREG_WCN_3P3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+
+ gpio = <&tlmm 214 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+
+ pinctrl-0 = <&wcn_sw_en>;
+ pinctrl-names = "default";
+ };
+
+ sound {
+ compatible = "qcom,x1e80100-sndcard";
+ model = "X1P42100-Microsoft-Surface-Pro-12in";
+ audio-routing = "SpkrLeft IN", "WSA WSA_SPK1 OUT",
+ "SpkrRight IN", "WSA WSA_SPK2 OUT",
+ "VA DMIC0", "vdd-micb",
+ "VA DMIC1", "vdd-micb";
+
+ va-dai-link {
+ link-name = "VA Capture";
+
+ codec {
+ sound-dai = <&lpass_vamacro 0>;
+ };
+
+ cpu {
+ sound-dai = <&q6apmbedai VA_CODEC_DMA_TX_0>;
+ };
+
+ platform {
+ sound-dai = <&q6apm>;
+ };
+ };
+
+ wsa-dai-link {
+ link-name = "WSA Playback";
+
+ codec {
+ sound-dai = <&left_spkr>, <&right_spkr>,
+ <&swr0 0>, <&lpass_wsamacro 0>;
+ };
+
+ cpu {
+ sound-dai = <&q6apmbedai WSA_CODEC_DMA_RX_0>;
+ };
+
+ platform {
+ sound-dai = <&q6apm>;
+ };
+ };
+ };
+
+ wcn7850-pmu {
+ compatible = "qcom,wcn7850-pmu";
+
+ vdd-supply = <&vreg_wcn_0p95>;
+ vddio-supply = <&vreg_l15b_1p8>;
+ vddaon-supply = <&vreg_wcn_0p95>;
+ vdddig-supply = <&vreg_wcn_0p95>;
+ vddrfa1p2-supply = <&vreg_wcn_1p9>;
+ vddrfa1p8-supply = <&vreg_wcn_1p9>;
+
+ wlan-enable-gpios = <&tlmm 117 GPIO_ACTIVE_HIGH>;
+ bt-enable-gpios = <&tlmm 116 GPIO_ACTIVE_HIGH>;
+
+ pinctrl-0 = <&wcn_wlan_bt_en>;
+ pinctrl-names = "default";
+
+ regulators {
+ vreg_pmu_rfa_cmn: ldo0 {
+ regulator-name = "vreg_pmu_rfa_cmn";
+ };
+
+ vreg_pmu_aon_0p59: ldo1 {
+ regulator-name = "vreg_pmu_aon_0p59";
+ };
+
+ vreg_pmu_wlcx_0p8: ldo2 {
+ regulator-name = "vreg_pmu_wlcx_0p8";
+ };
+
+ vreg_pmu_wlmx_0p85: ldo3 {
+ regulator-name = "vreg_pmu_wlmx_0p85";
+ };
+
+ vreg_pmu_btcmx_0p85: ldo4 {
+ regulator-name = "vreg_pmu_btcmx_0p85";
+ };
+
+ vreg_pmu_rfa_0p8: ldo5 {
+ regulator-name = "vreg_pmu_rfa_0p8";
+ };
+
+ vreg_pmu_rfa_1p2: ldo6 {
+ regulator-name = "vreg_pmu_rfa_1p2";
+ };
+
+ vreg_pmu_rfa_1p8: ldo7 {
+ regulator-name = "vreg_pmu_rfa_1p8";
+ };
+
+ vreg_pmu_pcie_0p9: ldo8 {
+ regulator-name = "vreg_pmu_pcie_0p9";
+ };
+
+ vreg_pmu_pcie_1p8: ldo9 {
+ regulator-name = "vreg_pmu_pcie_1p8";
+ };
+ };
+ };
+
+ usb-1-ss0-sbu-mux {
+ compatible = "onnn,fsusb42", "gpio-sbu-mux";
+
+ enable-gpios = <&tlmm 168 GPIO_ACTIVE_LOW>;
+ select-gpios = <&tlmm 167 GPIO_ACTIVE_HIGH>;
+
+ pinctrl-0 = <&usb_1_ss0_sbu_default>;
+ pinctrl-names = "default";
+
+ mode-switch;
+ orientation-switch;
+
+ port {
+ usb_1_ss0_sbu_mux: endpoint {
+ remote-endpoint = <&pmic_glink_ss0_sbu>;
+ };
+ };
+ };
+
+ usb-1-ss1-sbu-mux {
+ compatible = "onnn,fsusb42", "gpio-sbu-mux";
+
+ enable-gpios = <&tlmm 179 GPIO_ACTIVE_LOW>;
+ select-gpios = <&tlmm 178 GPIO_ACTIVE_HIGH>;
+
+ pinctrl-0 = <&usb_1_ss1_sbu_default>;
+ pinctrl-names = "default";
+
+ mode-switch;
+ orientation-switch;
+
+ port {
+ usb_1_ss1_sbu_mux: endpoint {
+ remote-endpoint = <&pmic_glink_ss1_sbu>;
+ };
+ };
+ };
+};
+
+&apps_rsc {
+ regulators-0 {
+ compatible = "qcom,pm8550-rpmh-regulators";
+ qcom,pmic-id = "b";
+
+ vdd-bob1-supply = <&vph_pwr>;
+ vdd-bob2-supply = <&vph_pwr>;
+ vdd-l1-l4-l10-supply = <&vreg_s4c_1p8>;
+ vdd-l2-l13-l14-supply = <&vreg_bob1>;
+ vdd-l5-l16-supply = <&vreg_bob1>;
+ vdd-l6-l7-supply = <&vreg_bob2>;
+ vdd-l8-l9-supply = <&vreg_bob1>;
+ vdd-l12-supply = <&vreg_s5j_1p2>;
+ vdd-l15-supply = <&vreg_s4c_1p8>;
+ vdd-l17-supply = <&vreg_bob2>;
+
+ vreg_bob1: bob1 {
+ regulator-name = "vreg_bob1";
+ regulator-min-microvolt = <3008000>;
+ regulator-max-microvolt = <3960000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_bob2: bob2 {
+ regulator-name = "vreg_bob2";
+ regulator-min-microvolt = <2504000>;
+ regulator-max-microvolt = <3008000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l1b_1p8: ldo1 {
+ regulator-name = "vreg_l1b_1p8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l2b_3p0: ldo2 {
+ regulator-name = "vreg_l2b_3p0";
+ regulator-min-microvolt = <3072000>;
+ regulator-max-microvolt = <3100000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l4b_1p8: ldo4 {
+ regulator-name = "vreg_l4b_1p8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l5b_3p0: ldo5 {
+ regulator-name = "vreg_l5b_3p0";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l6b_1p8: ldo6 {
+ regulator-name = "vreg_l6b_1p8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2960000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l7b_2p8: ldo7 {
+ regulator-name = "vreg_l7b_2p8";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ regulator-always-on;
+ };
+
+ vreg_l8b_3p0: ldo8 {
+ regulator-name = "vreg_l8b_3p0";
+ regulator-min-microvolt = <3072000>;
+ regulator-max-microvolt = <3072000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l9b_2p9: ldo9 {
+ regulator-name = "vreg_l9b_2p9";
+ regulator-min-microvolt = <2960000>;
+ regulator-max-microvolt = <2960000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l10b_1p8: ldo10 {
+ regulator-name = "vreg_l10b_1p8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l12b_1p2: ldo12 {
+ regulator-name = "vreg_l12b_1p2";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l13b_3p0: ldo13 {
+ regulator-name = "vreg_l13b_3p0";
+ regulator-min-microvolt = <3072000>;
+ regulator-max-microvolt = <3100000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l14b_3p0: ldo14 {
+ regulator-name = "vreg_l14b_3p0";
+ regulator-min-microvolt = <3072000>;
+ regulator-max-microvolt = <3072000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l15b_1p8: ldo15 {
+ regulator-name = "vreg_l15b_1p8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l16b_2p9: ldo16 {
+ regulator-name = "vreg_l16b_2p9";
+ regulator-min-microvolt = <2900000>;
+ regulator-max-microvolt = <2912000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ regulator-allow-set-load;
+ regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l17b_2p5: ldo17 {
+ regulator-name = "vreg_l17b_2p5";
+ regulator-min-microvolt = <2504000>;
+ regulator-max-microvolt = <2504000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ regulator-allow-set-load;
+ regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
+ };
+ };
+
+ regulators-1 {
+ compatible = "qcom,pm8550ve-rpmh-regulators";
+ qcom,pmic-id = "c";
+
+ vdd-l1-supply = <&vreg_s5j_1p2>;
+ vdd-s4-supply = <&vph_pwr>;
+
+ vreg_s4c_1p8: smps4 {
+ regulator-name = "vreg_s4c_1p8";
+ regulator-min-microvolt = <1856000>;
+ regulator-max-microvolt = <2000000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l1c_1p2: ldo1 {
+ regulator-name = "vreg_l1c_1p2";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l2c_0p8: ldo2 {
+ regulator-name = "vreg_l2c_0p8";
+ regulator-min-microvolt = <880000>;
+ regulator-max-microvolt = <920000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l3c_0p8: ldo3 {
+ regulator-name = "vreg_l3c_0p8";
+ regulator-min-microvolt = <880000>;
+ regulator-max-microvolt = <920000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+ };
+
+ regulators-2 {
+ compatible = "qcom,pmc8380-rpmh-regulators";
+ qcom,pmic-id = "d";
+
+ vdd-l3-supply = <&vreg_s4c_1p8>;
+ vdd-s1-supply = <&vph_pwr>;
+
+ vreg_l1d_0p8: ldo1 {
+ regulator-name = "vreg_l1d_0p8";
+ regulator-min-microvolt = <880000>;
+ regulator-max-microvolt = <920000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l2d_0p9: ldo2 {
+ regulator-name = "vreg_l2d_0p9";
+ regulator-min-microvolt = <912000>;
+ regulator-max-microvolt = <920000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l3d_1p8: ldo3 {
+ regulator-name = "vreg_l3d_1p8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+ };
+
+ regulators-3 {
+ compatible = "qcom,pmc8380-rpmh-regulators";
+ qcom,pmic-id = "e";
+
+ vdd-l3-supply = <&vreg_s5j_1p2>;
+
+ vreg_l2e_0p8: ldo2 {
+ regulator-name = "vreg_l2e_0p8";
+ regulator-min-microvolt = <880000>;
+ regulator-max-microvolt = <880000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l3e_1p2: ldo3 {
+ regulator-name = "vreg_l3e_1p2";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ regulator-allow-set-load;
+ regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
+ };
+ };
+
+ regulators-6 {
+ compatible = "qcom,pm8550ve-rpmh-regulators";
+ qcom,pmic-id = "i";
+
+ vdd-l1-supply = <&vreg_s4c_1p8>;
+ vdd-l2-supply = <&vreg_s5j_1p2>;
+ vdd-s1-supply = <&vph_pwr>;
+ vdd-s2-supply = <&vph_pwr>;
+
+ vreg_s1i_0p9: smps1 {
+ regulator-name = "vreg_s1i_0p9";
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <920000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_s2i_1p0: smps2 {
+ regulator-name = "vreg_s2i_1p0";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l1i_1p8: ldo1 {
+ regulator-name = "vreg_l1i_1p8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l2i_1p2: ldo2 {
+ regulator-name = "vreg_l2i_1p2";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ regulator-allow-set-load;
+ regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l3i_0p8: ldo3 {
+ regulator-name = "vreg_l3i_0p8";
+ regulator-min-microvolt = <880000>;
+ regulator-max-microvolt = <880000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ regulator-allow-set-load;
+ regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
+ };
+ };
+
+ regulators-7 {
+ compatible = "qcom,pm8550ve-rpmh-regulators";
+ qcom,pmic-id = "j";
+
+ vdd-l2-supply = <&vreg_s5j_1p2>;
+ vdd-s5-supply = <&vph_pwr>;
+
+ vreg_s5j_1p2: smps5 {
+ regulator-name = "vreg_s5j_1p2";
+ regulator-min-microvolt = <1256000>;
+ regulator-max-microvolt = <1304000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l1j_0p8: ldo1 {
+ regulator-name = "vreg_l1j_0p8";
+ regulator-min-microvolt = <880000>;
+ regulator-max-microvolt = <920000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l2j_1p2: ldo2 {
+ regulator-name = "vreg_l2j_1p2";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1256000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ regulator-allow-set-load;
+ regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
+ };
+
+ vreg_l3j_0p8: ldo3 {
+ regulator-name = "vreg_l3j_0p8";
+ regulator-min-microvolt = <880000>;
+ regulator-max-microvolt = <880000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ regulator-allow-set-load;
+ regulator-allowed-modes = <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
+ };
+ };
+};
+
+&gpu {
+ status = "okay";
+};
+
+&gpu_zap_shader {
+ firmware-name = "qcom/x1p42100/Microsoft/Surface12/qcdxkmsucpurwa.mbn";
+};
+
+&i2c8 {
+ clock-frequency = <1000000>;
+
+ status = "okay";
+
+ touchscreen@16 {
+ compatible = "hid-over-i2c";
+ reg = <0x16>;
+
+ hid-descr-addr = <0x1>;
+ interrupts-extended = <&tlmm 38 IRQ_TYPE_LEVEL_LOW>;
+ wakeup-source;
+
+ vddl-supply = <&vreg_l15b_1p8>;
+
+ pinctrl-0 = <&ts0_default>;
+ pinctrl-names = "default";
+ };
+};
+
+&i2c0 {
+ clock-frequency = <400000>;
+
+ status = "okay";
+};
+
+&i2c4 {
+ clock-frequency = <400000>;
+
+ status = "okay";
+
+ /* MAX34417 @12 */
+ /* MAX34417 @14 */
+ /* MAX34417 @16 */
+ /* MAX34417 @18 */
+ /* MAX34417 @1a */
+};
+
+&i2c9 {
+ clock-frequency = <400000>;
+
+ status = "okay";
+
+ /* NFC @28 Business 2109 sku only */
+};
+
+&lpass_tlmm {
+ spkr_01_sd_n_active: spkr-01-sd-n-active-state {
+ pins = "gpio12";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ output-low;
+ };
+};
+
+&lpass_vamacro {
+ qcom,dmic-sample-rate = <4800000>;
+
+ vdd-micb-supply = <&vreg_l1b_1p8>;
+
+ pinctrl-0 = <&dmic01_default>;
+ pinctrl-names = "default";
+};
+
+&mdss {
+ status = "okay";
+};
+
+&mdss_dp0 {
+ status = "okay";
+};
+
+&mdss_dp0_out {
+ link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>;
+};
+
+&mdss_dp1 {
+ status = "okay";
+};
+
+&mdss_dp1_out {
+ link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>;
+};
+
+&mdss_dp3 {
+ /delete-property/ #sound-dai-cells;
+
+ pinctrl-0 = <&edp0_hpd_default>;
+ pinctrl-names = "default";
+
+ status = "okay";
+
+ aux-bus {
+ panel: panel {
+ compatible = "edp-panel";
+
+ backlight = <&backlight>;
+
+ power-supply = <&vreg_edp_3p3>;
+
+ port {
+ edp_panel_in: endpoint {
+ remote-endpoint = <&mdss_dp3_out>;
+ };
+ };
+ };
+ };
+};
+
+&mdss_dp3_out {
+ data-lanes = <0 1 2 3>;
+ link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>;
+
+ remote-endpoint = <&edp_panel_in>;
+};
+
+&mdss_dp3_phy {
+ vdda-phy-supply = <&vreg_l3j_0p8>;
+ vdda-pll-supply = <&vreg_l2j_1p2>;
+
+ status = "okay";
+};
+
+&pcie4 {
+ pinctrl-0 = <&pcie4_default>;
+ pinctrl-names = "default";
+
+ status = "okay";
+};
+
+&pcie4_phy {
+ vdda-phy-supply = <&vreg_l3i_0p8>;
+ vdda-pll-supply = <&vreg_l3e_1p2>;
+
+ status = "okay";
+};
+
+&pcie4_port0 {
+ reset-gpios = <&tlmm 146 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&tlmm 148 GPIO_ACTIVE_LOW>;
+
+ wifi@0 {
+ compatible = "pci17cb,1107";
+ reg = <0x10000 0x0 0x0 0x0 0x0>;
+
+ vddaon-supply = <&vreg_pmu_aon_0p59>;
+ vddwlcx-supply = <&vreg_pmu_wlcx_0p8>;
+ vddwlmx-supply = <&vreg_pmu_wlmx_0p85>;
+ vddrfacmn-supply = <&vreg_pmu_rfa_cmn>;
+ vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>;
+ vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>;
+ vddrfa1p8-supply = <&vreg_pmu_rfa_1p8>;
+ vddpcie0p9-supply = <&vreg_pmu_pcie_0p9>;
+ vddpcie1p8-supply = <&vreg_pmu_pcie_1p8>;
+ };
+};
+
+&pm8550_gpios {
+ vol_up_n_default: vol-up-n-state {
+ pins = "gpio8";
+ function = "normal";
+ power-source = <1>;
+ bias-pull-up;
+ input-enable;
+ };
+
+ vol_down_n_default: vol-down-n-state {
+ pins = "gpio6";
+ function = "normal";
+ power-source = <1>;
+ bias-pull-up;
+ input-enable;
+ };
+};
+
+&pmk8550_pwm {
+ status = "okay";
+};
+
+&qupv3_0 {
+ status = "okay";
+};
+
+&qupv3_1 {
+ status = "okay";
+};
+
+&qupv3_2 {
+ status = "okay";
+};
+
+&remoteproc_adsp {
+ firmware-name = "qcom/x1p42100/Microsoft/Surface12/qcadsp8380.mbn",
+ "qcom/x1p42100/Microsoft/Surface12/adsp_dtbs.elf";
+
+ status = "okay";
+};
+
+&remoteproc_cdsp {
+ firmware-name = "qcom/x1p42100/Microsoft/Surface12/qccdsp8380.mbn",
+ "qcom/x1p42100/Microsoft/Surface12/cdsp_dtbs.elf";
+
+ status = "okay";
+};
+
+&smb2360_0 {
+ status = "okay";
+};
+
+&smb2360_0_eusb2_repeater {
+ vdd18-supply = <&vreg_l3d_1p8>;
+ vdd3-supply = <&vreg_l2b_3p0>;
+};
+
+&smb2360_1 {
+ status = "okay";
+};
+
+&smb2360_1_eusb2_repeater {
+ vdd18-supply = <&vreg_l3d_1p8>;
+ vdd3-supply = <&vreg_l14b_3p0>;
+};
+
+&swr0 {
+ pinctrl-0 = <&wsa_swr_active>, <&spkr_01_sd_n_active>;
+ pinctrl-names = "default";
+
+ status = "okay";
+
+ /* WSA8845, Left speaker */
+ left_spkr: speaker@0,0 {
+ compatible = "sdw20217020400";
+ reg = <0 0>;
+ reset-gpios = <&lpass_tlmm 12 GPIO_ACTIVE_LOW>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "SpkrLeft";
+ vdd-1p8-supply = <&vreg_l15b_1p8>;
+ vdd-io-supply = <&vreg_l12b_1p2>;
+ qcom,port-mapping = <1 2 3 7 10 13>;
+ };
+
+ /* WSA8845, Right speaker */
+ right_spkr: speaker@0,1 {
+ compatible = "sdw20217020400";
+ reg = <0 1>;
+ reset-gpios = <&lpass_tlmm 12 GPIO_ACTIVE_LOW>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "SpkrRight";
+ vdd-1p8-supply = <&vreg_l15b_1p8>;
+ vdd-io-supply = <&vreg_l12b_1p2>;
+ qcom,port-mapping = <4 5 6 7 11 13>;
+ };
+};
+
+&tlmm {
+ gpio-reserved-ranges = <34 2>, /* Unused */
+ <44 4>; /* SPI (TPM) */
+
+ edp_reg_en: edp-reg-en-state {
+ pins = "gpio70";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ hall_int_n_default: hall-int-n-state {
+ pins = "gpio2";
+ function = "gpio";
+ bias-disable;
+ };
+
+ panel_en: panel-en-state {
+ pins = "gpio29";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ pcie4_default: pcie4-default-state {
+ clkreq-n-pins {
+ pins = "gpio147";
+ function = "pcie4_clk";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+
+ perst-n-pins {
+ pins = "gpio146";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ wake-n-pins {
+ pins = "gpio148";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ ssam_state: ssam-state-state {
+ pins = "gpio91";
+ function = "gpio";
+ bias-disable;
+ };
+
+ ts0_default: ts0-default-state {
+ int-n-pins {
+ pins = "gpio38";
+ function = "gpio";
+ bias-disable;
+ };
+
+ reset-n-pins {
+ pins = "gpio48";
+ function = "gpio";
+ output-high;
+ drive-strength = <16>;
+ };
+ };
+
+ wcn_sw_en: wcn-sw-en-state {
+ pins = "gpio214";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ wcn_wlan_bt_en: wcn-wlan-bt-en-state {
+ pins = "gpio116", "gpio117";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ usb_1_ss0_sbu_default: usb-1-ss0-sbu-state {
+ oe-n-pins {
+ pins = "gpio168";
+ function = "gpio";
+ bias-disable;
+ drive-strength = <2>;
+ };
+
+ sel-pins {
+ pins = "gpio167";
+ function = "gpio";
+ bias-disable;
+ drive-strength = <2>;
+ };
+ };
+
+ usb_1_ss1_sbu_default: usb-1-ss1-sbu-state {
+ oe-n-pins {
+ pins = "gpio179";
+ function = "gpio";
+ bias-disable;
+ drive-strength = <2>;
+ };
+
+ sel-pins {
+ pins = "gpio178";
+ function = "gpio";
+ bias-disable;
+ drive-strength = <2>;
+ };
+ };
+};
+
+&uart2 {
+ status = "okay";
+
+ embedded-controller {
+ compatible = "microsoft,surface-sam";
+
+ interrupts-extended = <&tlmm 91 IRQ_TYPE_EDGE_RISING>;
+
+ current-speed = <4000000>;
+
+ pinctrl-0 = <&ssam_state>;
+ pinctrl-names = "default";
+ };
+};
+
+&uart14 {
+ status = "okay";
+
+ bluetooth {
+ compatible = "qcom,wcn7850-bt";
+ max-speed = <3200000>;
+
+ vddaon-supply = <&vreg_pmu_aon_0p59>;
+ vddwlcx-supply = <&vreg_pmu_wlcx_0p8>;
+ vddwlmx-supply = <&vreg_pmu_wlmx_0p85>;
+ vddrfacmn-supply = <&vreg_pmu_rfa_cmn>;
+ vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>;
+ vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>;
+ vddrfa1p8-supply = <&vreg_pmu_rfa_1p8>;
+ };
+};
+
+&ufs_mem_hc {
+ vcc-supply = <&vreg_l17b_2p5>;
+ vcc-max-microamp = <800000>;
+ vccq-supply = <&vreg_l2i_1p2>;
+ vccq-max-microamp = <900000>;
+
+ vdd-hba-supply = <&vreg_l3j_0p8>;
+
+ status = "okay";
+};
+
+&ufs_mem_phy {
+ status = "okay";
+
+ vdda-phy-supply = <&vreg_l3i_0p8>;
+ vdda-pll-supply = <&vreg_l3e_1p2>;
+};
+
+&usb_1_ss0_hsphy {
+ vdd-supply = <&vreg_l3j_0p8>;
+ vdda12-supply = <&vreg_l2j_1p2>;
+
+ phys = <&smb2360_0_eusb2_repeater>;
+
+ status = "okay";
+};
+
+&usb_1_ss0_qmpphy {
+ vdda-phy-supply = <&vreg_l2j_1p2>;
+ vdda-pll-supply = <&vreg_l1j_0p8>;
+
+ status = "okay";
+};
+
+&usb_1_ss0 {
+ dr_mode = "host";
+
+ status = "okay";
+};
+
+&usb_1_ss0_dwc3_hs {
+ remote-endpoint = <&pmic_glink_ss0_hs_in>;
+};
+
+&usb_1_ss0_qmpphy_out {
+ remote-endpoint = <&pmic_glink_ss0_ss_in>;
+};
+
+&usb_1_ss1_hsphy {
+ vdd-supply = <&vreg_l3j_0p8>;
+ vdda12-supply = <&vreg_l2j_1p2>;
+
+ phys = <&smb2360_1_eusb2_repeater>;
+
+ status = "okay";
+};
+
+&usb_1_ss1_qmpphy {
+ vdda-phy-supply = <&vreg_l2j_1p2>;
+ vdda-pll-supply = <&vreg_l2d_0p9>;
+
+ status = "okay";
+};
+
+&usb_1_ss1 {
+ dr_mode = "host";
+
+ status = "okay";
+};
+
+&usb_1_ss1_dwc3_hs {
+ remote-endpoint = <&pmic_glink_ss1_hs_in>;
+};
+
+&usb_1_ss1_qmpphy_out {
+ remote-endpoint = <&pmic_glink_ss1_ss_in>;
+};
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index ad3bd3d9507b..dfc52e32802e 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -521,6 +521,7 @@ CONFIG_WLCORE_SDIO=m
CONFIG_WWAN=m
CONFIG_MHI_WWAN_CTRL=m
CONFIG_MHI_WWAN_MBIM=m
+CONFIG_QCOM_BAM_DMUX=m
CONFIG_INPUT_EVDEV=y
CONFIG_KEYBOARD_ADC=m
CONFIG_KEYBOARD_GPIO=y
diff --git a/arch/arm64/include/asm/pgtable-prot.h b/arch/arm64/include/asm/pgtable-prot.h
index 212ce1b02e15..09d7c00cf405 100644
--- a/arch/arm64/include/asm/pgtable-prot.h
+++ b/arch/arm64/include/asm/pgtable-prot.h
@@ -28,11 +28,11 @@
#define PTE_PRESENT_VALID_KERNEL (PTE_VALID | PTE_MAYBE_NG)
#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_WP
-#define PTE_UFFD_WP (_AT(pteval_t, 1) << 58) /* uffd-wp tracking */
-#define PTE_SWP_UFFD_WP (_AT(pteval_t, 1) << 3) /* only for swp ptes */
+#define PTE_UFFD (_AT(pteval_t, 1) << 58) /* userfaultfd tracking */
+#define PTE_SWP_UFFD (_AT(pteval_t, 1) << 3) /* only for swp ptes */
#else
-#define PTE_UFFD_WP (_AT(pteval_t, 0))
-#define PTE_SWP_UFFD_WP (_AT(pteval_t, 0))
+#define PTE_UFFD (_AT(pteval_t, 0))
+#define PTE_SWP_UFFD (_AT(pteval_t, 0))
#endif /* CONFIG_HAVE_ARCH_USERFAULTFD_WP */
#define _PROT_DEFAULT (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED)
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index ed1cc6dba780..a2681d755358 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -341,19 +341,19 @@ static inline pmd_t pmd_mknoncont(pmd_t pmd)
}
#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_WP
-static inline int pte_uffd_wp(pte_t pte)
+static inline int pte_uffd(pte_t pte)
{
- return !!(pte_val(pte) & PTE_UFFD_WP);
+ return !!(pte_val(pte) & PTE_UFFD);
}
-static inline pte_t pte_mkuffd_wp(pte_t pte)
+static inline pte_t pte_mkuffd(pte_t pte)
{
- return pte_wrprotect(set_pte_bit(pte, __pgprot(PTE_UFFD_WP)));
+ return pte_wrprotect(set_pte_bit(pte, __pgprot(PTE_UFFD)));
}
-static inline pte_t pte_clear_uffd_wp(pte_t pte)
+static inline pte_t pte_clear_uffd(pte_t pte)
{
- return clear_pte_bit(pte, __pgprot(PTE_UFFD_WP));
+ return clear_pte_bit(pte, __pgprot(PTE_UFFD));
}
#endif /* CONFIG_HAVE_ARCH_USERFAULTFD_WP */
@@ -537,26 +537,23 @@ static inline pte_t pte_swp_clear_exclusive(pte_t pte)
}
#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_WP
-static inline pte_t pte_swp_mkuffd_wp(pte_t pte)
+static inline pte_t pte_swp_mkuffd(pte_t pte)
{
- return set_pte_bit(pte, __pgprot(PTE_SWP_UFFD_WP));
+ return set_pte_bit(pte, __pgprot(PTE_SWP_UFFD));
}
-static inline int pte_swp_uffd_wp(pte_t pte)
+static inline int pte_swp_uffd(pte_t pte)
{
- return !!(pte_val(pte) & PTE_SWP_UFFD_WP);
+ return !!(pte_val(pte) & PTE_SWP_UFFD);
}
-static inline pte_t pte_swp_clear_uffd_wp(pte_t pte)
+static inline pte_t pte_swp_clear_uffd(pte_t pte)
{
- return clear_pte_bit(pte, __pgprot(PTE_SWP_UFFD_WP));
+ return clear_pte_bit(pte, __pgprot(PTE_SWP_UFFD));
}
#endif /* CONFIG_HAVE_ARCH_USERFAULTFD_WP */
-#ifdef CONFIG_NUMA_BALANCING
-/*
- * See the comment in include/linux/pgtable.h
- */
+#ifdef CONFIG_ARCH_HAS_PTE_PROTNONE
static inline int pte_protnone(pte_t pte)
{
/*
@@ -575,7 +572,7 @@ static inline int pmd_protnone(pmd_t pmd)
{
return pte_protnone(pmd_pte(pmd));
}
-#endif
+#endif /* CONFIG_ARCH_HAS_PTE_PROTNONE */
#define pmd_present(pmd) pte_present(pmd_pte(pmd))
#define pmd_dirty(pmd) pte_dirty(pmd_pte(pmd))
@@ -593,13 +590,13 @@ static inline int pmd_protnone(pmd_t pmd)
#define pmd_mkvalid_k(pmd) pte_pmd(pte_mkvalid_k(pmd_pte(pmd)))
#define pmd_mkinvalid(pmd) pte_pmd(pte_mkinvalid(pmd_pte(pmd)))
#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_WP
-#define pmd_uffd_wp(pmd) pte_uffd_wp(pmd_pte(pmd))
-#define pmd_mkuffd_wp(pmd) pte_pmd(pte_mkuffd_wp(pmd_pte(pmd)))
-#define pmd_clear_uffd_wp(pmd) pte_pmd(pte_clear_uffd_wp(pmd_pte(pmd)))
-#define pmd_swp_uffd_wp(pmd) pte_swp_uffd_wp(pmd_pte(pmd))
-#define pmd_swp_mkuffd_wp(pmd) pte_pmd(pte_swp_mkuffd_wp(pmd_pte(pmd)))
-#define pmd_swp_clear_uffd_wp(pmd) \
- pte_pmd(pte_swp_clear_uffd_wp(pmd_pte(pmd)))
+#define pmd_uffd(pmd) pte_uffd(pmd_pte(pmd))
+#define pmd_mkuffd(pmd) pte_pmd(pte_mkuffd(pmd_pte(pmd)))
+#define pmd_clear_uffd(pmd) pte_pmd(pte_clear_uffd(pmd_pte(pmd)))
+#define pmd_swp_uffd(pmd) pte_swp_uffd(pmd_pte(pmd))
+#define pmd_swp_mkuffd(pmd) pte_pmd(pte_swp_mkuffd(pmd_pte(pmd)))
+#define pmd_swp_clear_uffd(pmd) \
+ pte_pmd(pte_swp_clear_uffd(pmd_pte(pmd)))
#endif /* CONFIG_HAVE_ARCH_USERFAULTFD_WP */
#define pmd_write(pmd) pte_write(pmd_pte(pmd))
@@ -1515,7 +1512,7 @@ static inline pmd_t pmdp_establish(struct vm_area_struct *vma,
* Encode and decode a swap entry:
* bits 0-1: present (must be zero)
* bits 2: remember PG_anon_exclusive
- * bit 3: remember uffd-wp state
+ * bit 3: remember uffd state
* bits 6-10: swap type
* bit 11: PTE_PRESENT_INVALID (must be zero)
* bits 12-61: swap offset
diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
index c6c611f44f3f..e20acbe5fe7b 100644
--- a/arch/loongarch/Kconfig
+++ b/arch/loongarch/Kconfig
@@ -67,6 +67,7 @@ config LOONGARCH
select ARCH_SUPPORTS_LTO_CLANG
select ARCH_SUPPORTS_LTO_CLANG_THIN
select ARCH_SUPPORTS_MSEAL_SYSTEM_MAPPINGS
+ select ARCH_HAS_PTE_PROTNONE if 64BIT
select ARCH_SUPPORTS_NUMA_BALANCING if NUMA
select ARCH_SUPPORTS_PER_VMA_LOCK
select ARCH_SUPPORTS_RT
diff --git a/arch/loongarch/include/asm/pgtable.h b/arch/loongarch/include/asm/pgtable.h
index 223528c04d73..1952e34bc8ee 100644
--- a/arch/loongarch/include/asm/pgtable.h
+++ b/arch/loongarch/include/asm/pgtable.h
@@ -623,7 +623,7 @@ static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
-#ifdef CONFIG_NUMA_BALANCING
+#ifdef CONFIG_ARCH_HAS_PTE_PROTNONE
static inline long pte_protnone(pte_t pte)
{
return (pte_val(pte) & _PAGE_PROTNONE);
@@ -633,7 +633,7 @@ static inline long pmd_protnone(pmd_t pmd)
{
return (pmd_val(pmd) & _PAGE_PROTNONE);
}
-#endif /* CONFIG_NUMA_BALANCING */
+#endif /* CONFIG_ARCH_HAS_PTE_PROTNONE */
#define pmd_leaf(pmd) ((pmd_val(pmd) & _PAGE_HUGE) != 0)
#define pud_leaf(pud) ((pud_val(pud) & _PAGE_HUGE) != 0)
diff --git a/arch/m68k/coldfire/m523x.c b/arch/m68k/coldfire/m523x.c
index 11d7423ef646..ec04c32bb03c 100644
--- a/arch/m68k/coldfire/m523x.c
+++ b/arch/m68k/coldfire/m523x.c
@@ -79,7 +79,7 @@ static void __init m523x_i2c_init(void)
static void __init m523x_fec_init(void)
{
/* Set multi-function pins to ethernet use */
- mcf_write8(read8(MCFGPIO_PAR_FECI2C) | 0xf0, MCFGPIO_PAR_FECI2C);
+ mcf_write8(mcf_read8(MCFGPIO_PAR_FECI2C) | 0xf0, MCFGPIO_PAR_FECI2C);
}
/***************************************************************************/
diff --git a/arch/m68k/coldfire/m528x.c b/arch/m68k/coldfire/m528x.c
index b244c9ba40a7..3383b1ba106a 100644
--- a/arch/m68k/coldfire/m528x.c
+++ b/arch/m68k/coldfire/m528x.c
@@ -113,11 +113,11 @@ void wildfiremod_halt(void)
mcf_write16(read16(MCFGPIO_PEPAR) & ~(1 << (5 * 2)), MCFGPIO_PEPAR);
/* Make portE.5 an output */
- mcf_write8(read8(MCFGPIO_PDDR_E) | (1 << 5), MCFGPIO_PDDR_E);
+ mcf_write8(mcf_read8(MCFGPIO_PDDR_E) | (1 << 5), MCFGPIO_PDDR_E);
/* Now toggle portE.5 from low to high */
- mcf_write8(read8(MCFGPIO_PODR_E) & ~(1 << 5), MCFGPIO_PODR_E);
- mcf_write8(read8(MCFGPIO_PODR_E) | (1 << 5), MCFGPIO_PODR_E);
+ mcf_write8(mcf_read8(MCFGPIO_PODR_E) & ~(1 << 5), MCFGPIO_PODR_E);
+ mcf_write8(mcf_read8(MCFGPIO_PODR_E) | (1 << 5), MCFGPIO_PODR_E);
printk(KERN_EMERG "Failed to hibernate. Halting!\n");
}
diff --git a/arch/m68k/configs/m5235evb_defconfig b/arch/m68k/configs/m5235evb_defconfig
new file mode 100644
index 000000000000..fcac4ccd332d
--- /dev/null
+++ b/arch/m68k/configs/m5235evb_defconfig
@@ -0,0 +1,52 @@
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_EXPERT=y
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
+# CONFIG_AIO is not set
+# CONFIG_KALLSYMS is not set
+# CONFIG_MMU is not set
+CONFIG_M523x=y
+CONFIG_M5235EVB=y
+CONFIG_RAMBASE=0x00000000
+CONFIG_RAMSIZE=0x01000000
+CONFIG_VECTORBASE=0x00000000
+CONFIG_IPSBAR=0x40000000
+CONFIG_KERNELBASE=0x00020000
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_BINFMT_FLAT=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_FW_LOADER is not set
+CONFIG_MTD=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_RAM=y
+CONFIG_MTD_UCLINUX=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_NETDEVICES=y
+CONFIG_FEC=y
+# CONFIG_INPUT is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_UNIX98_PTYS is not set
+CONFIG_SERIAL_MCF=y
+CONFIG_SERIAL_MCF_CONSOLE=y
+# CONFIG_HWMON is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_EXT2_FS=y
+# CONFIG_FILE_LOCKING is not set
+# CONFIG_DNOTIFY is not set
+CONFIG_ROMFS_FS=y
+CONFIG_ROMFS_BACKED_BY_MTD=y
+# CONFIG_NETWORK_FILESYSTEMS is not set
+# CONFIG_SLUB_DEBUG is not set
+CONFIG_BOOTPARAM=y
+CONFIG_BOOTPARAM_STRING="root=/dev/mtdblock0"
diff --git a/arch/m68k/configs/m5282evb_defconfig b/arch/m68k/configs/m5282evb_defconfig
new file mode 100644
index 000000000000..85040dc3e45e
--- /dev/null
+++ b/arch/m68k/configs/m5282evb_defconfig
@@ -0,0 +1,51 @@
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_EXPERT=y
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
+# CONFIG_AIO is not set
+# CONFIG_KALLSYMS is not set
+# CONFIG_MMU is not set
+CONFIG_M528x=y
+CONFIG_RAMBASE=0x00000000
+CONFIG_RAMSIZE=0x00800000
+CONFIG_VECTORBASE=0x00000000
+CONFIG_IPSBAR=0x40000000
+CONFIG_KERNELBASE=0x00020000
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_BINFMT_FLAT=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_FW_LOADER is not set
+CONFIG_MTD=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_RAM=y
+CONFIG_MTD_UCLINUX=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_NETDEVICES=y
+CONFIG_FEC=y
+# CONFIG_INPUT is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_UNIX98_PTYS is not set
+CONFIG_SERIAL_MCF=y
+CONFIG_SERIAL_MCF_CONSOLE=y
+# CONFIG_HWMON is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_EXT2_FS=y
+# CONFIG_FILE_LOCKING is not set
+# CONFIG_DNOTIFY is not set
+CONFIG_ROMFS_FS=y
+CONFIG_ROMFS_BACKED_BY_MTD=y
+# CONFIG_NETWORK_FILESYSTEMS is not set
+# CONFIG_SLUB_DEBUG is not set
+CONFIG_BOOTPARAM=y
+CONFIG_BOOTPARAM_STRING="root=/dev/mtdblock0"
diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h
index 800ff3cc5f71..f4db7d7fbd5c 100644
--- a/arch/powerpc/include/asm/book3s/64/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/64/pgtable.h
@@ -490,13 +490,13 @@ static inline pte_t pte_clear_soft_dirty(pte_t pte)
}
#endif /* CONFIG_HAVE_ARCH_SOFT_DIRTY */
-#ifdef CONFIG_NUMA_BALANCING
+#ifdef CONFIG_ARCH_HAS_PTE_PROTNONE
static inline int pte_protnone(pte_t pte)
{
return (pte_raw(pte) & cpu_to_be64(_PAGE_PRESENT | _PAGE_PTE | _PAGE_RWX)) ==
cpu_to_be64(_PAGE_PRESENT | _PAGE_PTE);
}
-#endif /* CONFIG_NUMA_BALANCING */
+#endif /* CONFIG_ARCH_HAS_PTE_PROTNONE */
static inline bool pte_hw_valid(pte_t pte)
{
@@ -1067,12 +1067,12 @@ static inline pte_t *pmdp_ptep(pmd_t *pmd)
#endif
#endif /* CONFIG_HAVE_ARCH_SOFT_DIRTY */
-#ifdef CONFIG_NUMA_BALANCING
+#ifdef CONFIG_ARCH_HAS_PTE_PROTNONE
static inline int pmd_protnone(pmd_t pmd)
{
return pte_protnone(pmd_pte(pmd));
}
-#endif /* CONFIG_NUMA_BALANCING */
+#endif /* CONFIG_ARCH_HAS_PTE_PROTNONE */
#define pmd_write(pmd) pte_write(pmd_pte(pmd))
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index 9f6847b53e37..f0adbf7ecb7f 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -87,6 +87,7 @@ config PPC_BOOK3S_64
select ARCH_ENABLE_HUGEPAGE_MIGRATION if HUGETLB_PAGE && MIGRATION
select ARCH_ENABLE_SPLIT_PMD_PTLOCK
select ARCH_SUPPORTS_HUGETLBFS
+ select ARCH_HAS_PTE_PROTNONE
select ARCH_SUPPORTS_NUMA_BALANCING
select HAVE_MOVE_PMD
select HAVE_MOVE_PUD
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 2e1821f86af5..bf12b0fe35c2 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -23,7 +23,6 @@ config RISCV
select ARCH_ENABLE_MEMORY_HOTPLUG if SPARSEMEM_VMEMMAP
select ARCH_ENABLE_SPLIT_PMD_PTLOCK if PGTABLE_LEVELS > 2
select ARCH_HAS_PMD_SOFTLEAVES if TRANSPARENT_HUGEPAGE
- select ARCH_HAS_ACPI_TABLE_UPGRADE if ACPI
select ARCH_HAS_BINFMT_FLAT
select ARCH_HAS_CC_CAN_LINK
select ARCH_HAS_CURRENT_STACK_POINTER
@@ -72,6 +71,7 @@ config RISCV
select ARCH_SUPPORTS_MSEAL_SYSTEM_MAPPINGS if 64BIT && MMU
select ARCH_SUPPORTS_PAGE_TABLE_CHECK if MMU
select ARCH_SUPPORTS_PER_VMA_LOCK if MMU
+ select ARCH_HAS_PTE_PROTNONE if MMU
select ARCH_SUPPORTS_RT
select ARCH_SUPPORTS_SHADOW_CALL_STACK if HAVE_SHADOW_CALL_STACK
select ARCH_SUPPORTS_SCHED_MC if SMP
diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
index c174ac0ec46b..429e07589306 100644
--- a/arch/riscv/Kconfig.socs
+++ b/arch/riscv/Kconfig.socs
@@ -84,6 +84,12 @@ config ARCH_THEAD
help
This enables support for the RISC-V based T-HEAD SoCs.
+config ARCH_ULTRARISC
+ bool "UltraRISC RISC-V SoCs"
+ help
+ This enables support for UltraRISC SoC platform hardware,
+ including boards based on the UR-DP1000.
+
config ARCH_VIRT
bool "QEMU Virt Machine"
select POWER_RESET
diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig
index 472e03eaebb0..04ae305d5511 100644
--- a/arch/riscv/configs/defconfig
+++ b/arch/riscv/configs/defconfig
@@ -33,6 +33,7 @@ CONFIG_SOC_STARFIVE=y
CONFIG_ARCH_SUNXI=y
CONFIG_ARCH_TENSTORRENT=y
CONFIG_ARCH_THEAD=y
+CONFIG_ARCH_ULTRARISC=y
CONFIG_ARCH_VIRT=y
CONFIG_ARCH_CANAAN=y
CONFIG_SMP=y
diff --git a/arch/riscv/include/asm/acpi.h b/arch/riscv/include/asm/acpi.h
index d59bd06347cc..f598520ac903 100644
--- a/arch/riscv/include/asm/acpi.h
+++ b/arch/riscv/include/asm/acpi.h
@@ -67,6 +67,7 @@ int acpi_get_riscv_isa(struct acpi_table_header *table,
void acpi_get_cbo_block_size(struct acpi_table_header *table, u32 *cbom_size,
u32 *cboz_size, u32 *cbop_size);
+acpi_handle acpi_get_riscv_gsi_handle(u32 gsi);
#else
static inline void acpi_init_rintc_map(void) { }
static inline struct acpi_madt_rintc *acpi_cpu_get_madt_rintc(int cpu)
@@ -92,6 +93,4 @@ void acpi_map_cpus_to_nodes(void);
static inline void acpi_map_cpus_to_nodes(void) { }
#endif /* CONFIG_ACPI_NUMA */
-#define ACPI_TABLE_UPGRADE_MAX_PHYS MEMBLOCK_ALLOC_ACCESSIBLE
-
#endif /*_ASM_ACPI_H*/
diff --git a/arch/riscv/include/asm/pgtable-bits.h b/arch/riscv/include/asm/pgtable-bits.h
index b422d9691e60..d5a86b4df3ce 100644
--- a/arch/riscv/include/asm/pgtable-bits.h
+++ b/arch/riscv/include/asm/pgtable-bits.h
@@ -40,20 +40,20 @@
#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_WP
-/* ext_svrsw60t59b: Bit(60) for uffd-wp tracking */
-#define _PAGE_UFFD_WP \
+/* ext_svrsw60t59b: Bit(60) for userfaultfd tracking */
+#define _PAGE_UFFD \
((riscv_has_extension_unlikely(RISCV_ISA_EXT_SVRSW60T59B)) ? \
(1UL << 60) : 0)
/*
* Bit 4 is not involved into swap entry computation, so we
- * can borrow it for swap page uffd-wp tracking.
+ * can borrow it for swap page userfaultfd tracking.
*/
-#define _PAGE_SWP_UFFD_WP \
+#define _PAGE_SWP_UFFD \
((riscv_has_extension_unlikely(RISCV_ISA_EXT_SVRSW60T59B)) ? \
_PAGE_USER : 0)
#else
-#define _PAGE_UFFD_WP 0
-#define _PAGE_SWP_UFFD_WP 0
+#define _PAGE_UFFD 0
+#define _PAGE_SWP_UFFD 0
#endif
#define _PAGE_TABLE _PAGE_PRESENT
diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
index 4904a56fefa6..4e1e71e4a3da 100644
--- a/arch/riscv/include/asm/pgtable.h
+++ b/arch/riscv/include/asm/pgtable.h
@@ -410,37 +410,37 @@ static inline pte_t pte_wrprotect(pte_t pte)
}
#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_WP
-#define pgtable_supports_uffd_wp() \
+#define pgtable_supports_uffd() \
riscv_has_extension_unlikely(RISCV_ISA_EXT_SVRSW60T59B)
-static inline bool pte_uffd_wp(pte_t pte)
+static inline bool pte_uffd(pte_t pte)
{
- return !!(pte_val(pte) & _PAGE_UFFD_WP);
+ return !!(pte_val(pte) & _PAGE_UFFD);
}
-static inline pte_t pte_mkuffd_wp(pte_t pte)
+static inline pte_t pte_mkuffd(pte_t pte)
{
- return pte_wrprotect(__pte(pte_val(pte) | _PAGE_UFFD_WP));
+ return pte_wrprotect(__pte(pte_val(pte) | _PAGE_UFFD));
}
-static inline pte_t pte_clear_uffd_wp(pte_t pte)
+static inline pte_t pte_clear_uffd(pte_t pte)
{
- return __pte(pte_val(pte) & ~(_PAGE_UFFD_WP));
+ return __pte(pte_val(pte) & ~(_PAGE_UFFD));
}
-static inline bool pte_swp_uffd_wp(pte_t pte)
+static inline bool pte_swp_uffd(pte_t pte)
{
- return !!(pte_val(pte) & _PAGE_SWP_UFFD_WP);
+ return !!(pte_val(pte) & _PAGE_SWP_UFFD);
}
-static inline pte_t pte_swp_mkuffd_wp(pte_t pte)
+static inline pte_t pte_swp_mkuffd(pte_t pte)
{
- return __pte(pte_val(pte) | _PAGE_SWP_UFFD_WP);
+ return __pte(pte_val(pte) | _PAGE_SWP_UFFD);
}
-static inline pte_t pte_swp_clear_uffd_wp(pte_t pte)
+static inline pte_t pte_swp_clear_uffd(pte_t pte)
{
- return __pte(pte_val(pte) & ~(_PAGE_SWP_UFFD_WP));
+ return __pte(pte_val(pte) & ~(_PAGE_SWP_UFFD));
}
#endif /* CONFIG_HAVE_ARCH_USERFAULTFD_WP */
@@ -534,10 +534,7 @@ static inline pte_t pte_swp_clear_soft_dirty(pte_t pte)
PAGE_SIZE)
#endif
-#ifdef CONFIG_NUMA_BALANCING
-/*
- * See the comment in include/asm-generic/pgtable.h
- */
+#ifdef CONFIG_ARCH_HAS_PTE_PROTNONE
static inline int pte_protnone(pte_t pte)
{
return (pte_val(pte) & (_PAGE_PRESENT | _PAGE_PROT_NONE)) == _PAGE_PROT_NONE;
@@ -547,7 +544,7 @@ static inline int pmd_protnone(pmd_t pmd)
{
return pte_protnone(pmd_pte(pmd));
}
-#endif
+#endif /* CONFIG_ARCH_HAS_PTE_PROTNONE */
/* Modify page protection bits */
static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
@@ -899,34 +896,34 @@ static inline pud_t pud_mkspecial(pud_t pud)
#endif
#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_WP
-static inline bool pmd_uffd_wp(pmd_t pmd)
+static inline bool pmd_uffd(pmd_t pmd)
{
- return pte_uffd_wp(pmd_pte(pmd));
+ return pte_uffd(pmd_pte(pmd));
}
-static inline pmd_t pmd_mkuffd_wp(pmd_t pmd)
+static inline pmd_t pmd_mkuffd(pmd_t pmd)
{
- return pte_pmd(pte_mkuffd_wp(pmd_pte(pmd)));
+ return pte_pmd(pte_mkuffd(pmd_pte(pmd)));
}
-static inline pmd_t pmd_clear_uffd_wp(pmd_t pmd)
+static inline pmd_t pmd_clear_uffd(pmd_t pmd)
{
- return pte_pmd(pte_clear_uffd_wp(pmd_pte(pmd)));
+ return pte_pmd(pte_clear_uffd(pmd_pte(pmd)));
}
-static inline bool pmd_swp_uffd_wp(pmd_t pmd)
+static inline bool pmd_swp_uffd(pmd_t pmd)
{
- return pte_swp_uffd_wp(pmd_pte(pmd));
+ return pte_swp_uffd(pmd_pte(pmd));
}
-static inline pmd_t pmd_swp_mkuffd_wp(pmd_t pmd)
+static inline pmd_t pmd_swp_mkuffd(pmd_t pmd)
{
- return pte_pmd(pte_swp_mkuffd_wp(pmd_pte(pmd)));
+ return pte_pmd(pte_swp_mkuffd(pmd_pte(pmd)));
}
-static inline pmd_t pmd_swp_clear_uffd_wp(pmd_t pmd)
+static inline pmd_t pmd_swp_clear_uffd(pmd_t pmd)
{
- return pte_pmd(pte_swp_clear_uffd_wp(pmd_pte(pmd)));
+ return pte_pmd(pte_swp_clear_uffd(pmd_pte(pmd)));
}
#endif /* CONFIG_HAVE_ARCH_USERFAULTFD_WP */
@@ -1177,7 +1174,7 @@ static inline pud_t pud_modify(pud_t pud, pgprot_t newprot)
* bit 0: _PAGE_PRESENT (zero)
* bit 1 to 2: (zero)
* bit 3: _PAGE_SWP_SOFT_DIRTY
- * bit 4: _PAGE_SWP_UFFD_WP
+ * bit 4: _PAGE_SWP_UFFD
* bit 5: _PAGE_PROT_NONE (zero)
* bit 6: exclusive marker
* bits 7 to 11: swap type
diff --git a/arch/riscv/kernel/acpi.c b/arch/riscv/kernel/acpi.c
index efd52a5d05b5..068e0b404b6f 100644
--- a/arch/riscv/kernel/acpi.c
+++ b/arch/riscv/kernel/acpi.c
@@ -353,8 +353,3 @@ int acpi_get_cpu_uid(unsigned int cpu, u32 *uid)
return 0;
}
EXPORT_SYMBOL_GPL(acpi_get_cpu_uid);
-
-void __init arch_reserve_mem_area(acpi_physical_address addr, size_t size)
-{
- memblock_mark_nomap(addr, size);
-}
diff --git a/arch/riscv/kernel/efi.c b/arch/riscv/kernel/efi.c
index 2d3cc57b4535..b64bf1624a05 100644
--- a/arch/riscv/kernel/efi.c
+++ b/arch/riscv/kernel/efi.c
@@ -95,8 +95,3 @@ int __init efi_set_mapping_permissions(struct mm_struct *mm,
md->num_pages << EFI_PAGE_SHIFT,
set_permissions, md);
}
-
-bool efi_poweroff_required(void)
-{
- return efi_enabled(EFI_RUNTIME_SERVICES);
-}
diff --git a/arch/riscv/kernel/reset.c b/arch/riscv/kernel/reset.c
index 541e2162c85a..912288572226 100644
--- a/arch/riscv/kernel/reset.c
+++ b/arch/riscv/kernel/reset.c
@@ -3,7 +3,6 @@
* Copyright (C) 2012 Regents of the University of California
*/
-#include <linux/efi.h>
#include <linux/reboot.h>
#include <linux/pm.h>
@@ -18,12 +17,6 @@ EXPORT_SYMBOL(pm_power_off);
void machine_restart(char *cmd)
{
- /*
- * UpdateCapsule() depends on the system being reset via ResetSystem().
- */
- if (efi_enabled(EFI_RUNTIME_SERVICES))
- efi_reboot(reboot_mode, NULL);
-
do_kernel_restart(cmd);
while (1);
}
diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c
index a32344bb220d..52d1d2b8f338 100644
--- a/arch/riscv/kernel/setup.c
+++ b/arch/riscv/kernel/setup.c
@@ -321,8 +321,6 @@ void __init setup_arch(char **cmdline_p)
efi_init();
paging_init();
- acpi_table_upgrade();
-
/* Parse the ACPI tables for possible boot-time configuration */
acpi_boot_table_init();
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 6b317717bf48..1911144e9128 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -20,6 +20,9 @@ config ARCH_HAS_ILOG2_U64
config ARCH_PROC_KCORE_TEXT
def_bool y
+config ARCH_HAS_CPU_RELAX
+ def_bool y
+
config GENERIC_HWEIGHT
def_bool !HAVE_MARCH_Z196_FEATURES
@@ -148,6 +151,7 @@ config S390
select ARCH_SUPPORTS_HUGETLBFS
select ARCH_SUPPORTS_INT128 if CC_HAS_INT128 && CC_IS_CLANG
select ARCH_SUPPORTS_MSEAL_SYSTEM_MAPPINGS
+ select ARCH_HAS_PTE_PROTNONE
select ARCH_SUPPORTS_NUMA_BALANCING
select ARCH_SUPPORTS_PAGE_TABLE_CHECK
select ARCH_SUPPORTS_PER_VMA_LOCK
@@ -705,6 +709,8 @@ config KERNEL_IMAGE_BASE
endmenu
+source "drivers/cpuidle/Kconfig"
+
menu "Memory setup"
config ARCH_SPARSEMEM_ENABLE
diff --git a/arch/s390/configs/debug_defconfig b/arch/s390/configs/debug_defconfig
index 54637be87fb7..007668f95028 100644
--- a/arch/s390/configs/debug_defconfig
+++ b/arch/s390/configs/debug_defconfig
@@ -29,6 +29,8 @@ CONFIG_CGROUP_PIDS=y
CONFIG_CGROUP_RDMA=y
CONFIG_CGROUP_FREEZER=y
CONFIG_CGROUP_HUGETLB=y
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_TEO=y
CONFIG_CPUSETS=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CGROUP_CPUACCT=y
diff --git a/arch/s390/configs/defconfig b/arch/s390/configs/defconfig
index 5f5114a253cf..6f5722634b4d 100644
--- a/arch/s390/configs/defconfig
+++ b/arch/s390/configs/defconfig
@@ -27,6 +27,8 @@ CONFIG_CGROUP_PIDS=y
CONFIG_CGROUP_RDMA=y
CONFIG_CGROUP_FREEZER=y
CONFIG_CGROUP_HUGETLB=y
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_TEO=y
CONFIG_CPUSETS=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CGROUP_CPUACCT=y
diff --git a/arch/s390/include/asm/hugetlb.h b/arch/s390/include/asm/hugetlb.h
index e33a5b587ee4..aea754b67c89 100644
--- a/arch/s390/include/asm/hugetlb.h
+++ b/arch/s390/include/asm/hugetlb.h
@@ -42,9 +42,9 @@ static inline void huge_pte_clear(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, unsigned long sz)
{
if ((pte_val(ptep_get(ptep)) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3)
- set_pte(ptep, __pte(_REGION3_ENTRY_EMPTY));
+ set_pud((pud_t *)ptep, __pud(_REGION3_ENTRY_EMPTY));
else
- set_pte(ptep, __pte(_SEGMENT_ENTRY_EMPTY));
+ set_pmd((pmd_t *)ptep, __pmd(_SEGMENT_ENTRY_EMPTY));
}
#define __HAVE_ARCH_HUGE_PTEP_CLEAR_FLUSH
@@ -77,20 +77,20 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
__set_huge_pte_at(mm, addr, ptep, pte_wrprotect(pte));
}
-#define __HAVE_ARCH_HUGE_PTE_MKUFFD_WP
-static inline pte_t huge_pte_mkuffd_wp(pte_t pte)
+#define __HAVE_ARCH_HUGE_PTE_MKUFFD
+static inline pte_t huge_pte_mkuffd(pte_t pte)
{
return pte;
}
-#define __HAVE_ARCH_HUGE_PTE_CLEAR_UFFD_WP
-static inline pte_t huge_pte_clear_uffd_wp(pte_t pte)
+#define __HAVE_ARCH_HUGE_PTE_CLEAR_UFFD
+static inline pte_t huge_pte_clear_uffd(pte_t pte)
{
return pte;
}
-#define __HAVE_ARCH_HUGE_PTE_UFFD_WP
-static inline int huge_pte_uffd_wp(pte_t pte)
+#define __HAVE_ARCH_HUGE_PTE_UFFD
+static inline int huge_pte_uffd(pte_t pte)
{
return 0;
}
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 645fa2d99c6a..e882663a58e7 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -842,7 +842,7 @@ static inline int pte_same(pte_t a, pte_t b)
return pte_val(a) == pte_val(b);
}
-#ifdef CONFIG_NUMA_BALANCING
+#ifdef CONFIG_ARCH_HAS_PTE_PROTNONE
static inline int pte_protnone(pte_t pte)
{
return pte_present(pte) && !(pte_val(pte) & _PAGE_READ);
@@ -853,7 +853,7 @@ static inline int pmd_protnone(pmd_t pmd)
/* pmd_leaf(pmd) implies pmd_present(pmd) */
return pmd_leaf(pmd) && !(pmd_val(pmd) & _SEGMENT_ENTRY_READ);
}
-#endif
+#endif /* CONFIG_ARCH_HAS_PTE_PROTNONE */
static inline bool pte_swp_exclusive(pte_t pte)
{
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h
index ecd3341686eb..be8369115f6d 100644
--- a/arch/s390/include/asm/processor.h
+++ b/arch/s390/include/asm/processor.h
@@ -14,12 +14,10 @@
#include <linux/bits.h>
-#define CIF_NOHZ_DELAY 2 /* delay HZ disable for a tick */
#define CIF_ENABLED_WAIT 5 /* in enabled wait state */
#define CIF_MCCK_GUEST 6 /* machine check happening in guest */
#define CIF_DEDICATED_CPU 7 /* this CPU is dedicated */
-#define _CIF_NOHZ_DELAY BIT(CIF_NOHZ_DELAY)
#define _CIF_ENABLED_WAIT BIT(CIF_ENABLED_WAIT)
#define _CIF_MCCK_GUEST BIT(CIF_MCCK_GUEST)
#define _CIF_DEDICATED_CPU BIT(CIF_DEDICATED_CPU)
@@ -97,8 +95,6 @@ static __always_inline bool test_cpu_flag_of(int flag, int cpu)
return test_bit(flag, &per_cpu(pcpu_devices, cpu).flags);
}
-#define arch_needs_cpu() test_cpu_flag(CIF_NOHZ_DELAY)
-
static inline void get_cpu_id(struct cpuid *ptr)
{
asm volatile("stidp %0" : "=Q" (*ptr));
diff --git a/arch/s390/include/asm/thread_info.h b/arch/s390/include/asm/thread_info.h
index 6a548a819400..2554cef3a6a5 100644
--- a/arch/s390/include/asm/thread_info.h
+++ b/arch/s390/include/asm/thread_info.h
@@ -61,6 +61,7 @@ void arch_setup_new_exec(void);
*/
#define HAVE_TIF_NEED_RESCHED_LAZY
#define HAVE_TIF_RESTORE_SIGMASK
+#define HAVE_TIF_POLLING_NRFLAG
#include <asm-generic/thread_info_tif.h>
diff --git a/arch/s390/kernel/diag/diag310.c b/arch/s390/kernel/diag/diag310.c
index f411562aa7f6..c68ec9d28513 100644
--- a/arch/s390/kernel/diag/diag310.c
+++ b/arch/s390/kernel/diag/diag310.c
@@ -190,17 +190,18 @@ static int memtop_get_stride_len(unsigned long *res)
static int memtop_get_page_count(unsigned long *res, unsigned long level)
{
static unsigned long memtop_pages[DIAG310_LEVELMAX];
- unsigned long pages;
+ unsigned long pages, idx;
int rc;
if (level > DIAG310_LEVELMAX || level < DIAG310_LEVELMIN)
return -EINVAL;
- pages = READ_ONCE(memtop_pages[level - 1]);
+ idx = array_index_nospec(level - 1, ARRAY_SIZE(memtop_pages));
+ pages = READ_ONCE(memtop_pages[idx]);
if (!pages) {
rc = diag310_get_memtop_size(&pages, level);
if (rc)
return rc;
- WRITE_ONCE(memtop_pages[level - 1], pages);
+ WRITE_ONCE(memtop_pages[idx], pages);
}
*res = pages;
return 0;
diff --git a/arch/s390/kernel/idle.c b/arch/s390/kernel/idle.c
index 08f3520c6785..dd12efb58201 100644
--- a/arch/s390/kernel/idle.c
+++ b/arch/s390/kernel/idle.c
@@ -136,7 +136,6 @@ void noinstr arch_cpu_idle(void)
/* Wait for external, I/O or machine check interrupt. */
psw_mask = PSW_KERNEL_BITS | PSW_MASK_WAIT |
PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK;
- clear_cpu_flag(CIF_NOHZ_DELAY);
set_cpu_flag(CIF_ENABLED_WAIT);
if (smp_cpu_mtid)
stcctm(MT_DIAG, smp_cpu_mtid, (u64 *)&idle->mt_cycles_enter);
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c
index 04d528639b94..c923496aa7b4 100644
--- a/arch/s390/kernel/irq.c
+++ b/arch/s390/kernel/irq.c
@@ -166,7 +166,6 @@ void noinstr do_io_irq(struct pt_regs *regs)
if (from_idle)
account_idle_time_irq();
- set_cpu_flag(CIF_NOHZ_DELAY);
do {
regs->tpi_info = get_lowcore()->tpi_info;
if (get_lowcore()->tpi_info.adapter_IO)
@@ -369,9 +368,6 @@ static irqreturn_t do_ext_interrupt(int irq, void *dummy)
int index;
ext_code.int_code = regs->int_code;
- if (ext_code.code != EXT_IRQ_CLK_COMP)
- set_cpu_flag(CIF_NOHZ_DELAY);
-
index = ext_hash(ext_code.code);
rcu_read_lock();
hlist_for_each_entry_rcu(p, &ext_int_hash[index], entry) {
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 0ba7f89b8161..4cc2c119318d 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -909,7 +909,6 @@ int __cpu_disable(void)
cregs[6].val &= ~0xff000000UL; /* disable all I/O interrupts */
cregs[14].val &= ~0x1f000000UL; /* disable most machine checks */
__local_ctl_load(0, 15, cregs);
- clear_cpu_flag(CIF_NOHZ_DELAY);
return 0;
}
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
index 564403496a7c..fcd8c1122ef5 100644
--- a/arch/s390/kernel/traps.c
+++ b/arch/s390/kernel/traps.c
@@ -9,7 +9,9 @@
* Copyright (C) 1991, 1992 Linus Torvalds
*/
+#include <linux/capability.h>
#include <linux/cpufeature.h>
+#include <linux/debugfs.h>
#include <linux/kprobes.h>
#include <linux/kdebug.h>
#include <linux/randomize_kstack.h>
@@ -33,6 +35,12 @@
#include <asm/fault.h>
#include "entry.h"
+struct pgm_stat {
+ unsigned int count[128];
+};
+
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct pgm_stat, pgm_stat);
+
static inline void __user *get_trap_ip(struct pt_regs *regs)
{
unsigned long address;
@@ -332,6 +340,7 @@ void noinstr __do_pgm_check(struct pt_regs *regs)
struct lowcore *lc = get_lowcore();
bool percpu_needs_fixup;
irqentry_state_t state;
+ struct pgm_stat *stat;
unsigned int trapnr;
union teid teid;
@@ -339,6 +348,10 @@ void noinstr __do_pgm_check(struct pt_regs *regs)
regs->int_code = lc->pgm_int_code;
regs->int_parm_long = teid.val;
regs->monitor_code = lc->monitor_code;
+
+ trapnr = regs->int_code & PGM_INT_CODE_MASK;
+ stat = this_cpu_ptr(&pgm_stat);
+ stat->count[trapnr]++;
/*
* In case of a guest fault, short-circuit the fault handler and return.
* This way the sie64a() function will return 0; fault address and
@@ -383,7 +396,6 @@ void noinstr __do_pgm_check(struct pt_regs *regs)
if (!irqs_disabled_flags(regs->psw.mask))
trace_hardirqs_on();
__arch_local_irq_ssm(regs->psw.mask & ~PSW_MASK_PER);
- trapnr = regs->int_code & PGM_INT_CODE_MASK;
if (trapnr)
pgm_check_table[trapnr](regs);
out:
@@ -393,6 +405,33 @@ out:
percpu_exit(regs, percpu_needs_fixup);
}
+static int pgm_check_stat_show(struct seq_file *p, void *v)
+{
+ int i, cpu;
+
+ cpus_read_lock();
+ seq_puts(p, " ");
+ for_each_online_cpu(cpu)
+ seq_printf(p, "CPU%-8d", cpu);
+ seq_putc(p, '\n');
+ for (i = 0; i < 128; i++) {
+ seq_printf(p, "%02x: ", i);
+ for_each_online_cpu(cpu)
+ seq_printf(p, "%10u ", per_cpu(pgm_stat, cpu).count[i]);
+ seq_putc(p, '\n');
+ }
+ cpus_read_unlock();
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(pgm_check_stat);
+
+static int __init debugfs_pgm_check_init(void)
+{
+ debugfs_create_file("exceptions", 0400, arch_debugfs_dir, NULL, &pgm_check_stat_fops);
+ return 0;
+}
+late_initcall(debugfs_pgm_check_init);
+
/*
* The program check table contains exactly 128 (0x00-0x7f) entries. Each
* line defines the function to be called corresponding to the program check
diff --git a/arch/s390/kernel/vdso/note.S b/arch/s390/kernel/vdso/note.S
index db19d0680a0a..d215781f26b5 100644
--- a/arch/s390/kernel/vdso/note.S
+++ b/arch/s390/kernel/vdso/note.S
@@ -4,6 +4,7 @@
* Here we can supply some information useful to userland.
*/
+#include <linux/build-salt.h>
#include <linux/uts.h>
#include <linux/version.h>
#include <linux/elfnote.h>
@@ -11,3 +12,5 @@
ELFNOTE_START(Linux, 0, "a")
.long LINUX_VERSION_CODE
ELFNOTE_END
+
+BUILD_SALT
diff --git a/arch/s390/kvm/dat.c b/arch/s390/kvm/dat.c
index 5f1960ec982d..ed4259d17629 100644
--- a/arch/s390/kvm/dat.c
+++ b/arch/s390/kvm/dat.c
@@ -570,6 +570,8 @@ static long dat_crste_walk_range(gfn_t start, gfn_t end, struct crst_table *tabl
else if (walk->ops->pte_entry)
rc = dat_pte_walk_range(max(start, cur), min(end, next),
dereference_pmd(crste.pmd), walk);
+ if (rc)
+ break;
}
}
return rc;
diff --git a/arch/s390/kvm/gmap.c b/arch/s390/kvm/gmap.c
index 298fbaecec28..8abb4f55b306 100644
--- a/arch/s390/kvm/gmap.c
+++ b/arch/s390/kvm/gmap.c
@@ -1374,8 +1374,13 @@ struct gmap *gmap_create_shadow(struct kvm_s390_mmu_cache *mc, struct gmap *pare
/* Only allow one real-space gmap shadow. */
list_for_each_entry(sg, &parent->children, list) {
if (sg->guest_asce.r) {
- scoped_guard(write_lock, &parent->kvm->mmu_lock)
+ if (write_trylock(&parent->kvm->mmu_lock)) {
gmap_unshadow(sg);
+ write_unlock(&parent->kvm->mmu_lock);
+ } else {
+ gmap_put(new);
+ return ERR_PTR(-EAGAIN);
+ }
break;
}
}
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 23c817595e28..150b5dd2170e 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -1280,8 +1280,10 @@ static int kvm_s390_vm_stop_migration(struct kvm *kvm)
* PGSTEs might have cmma_d set.
*/
WRITE_ONCE(kvm->arch.migration_mode, 0);
- if (kvm->arch.use_cmma)
- kvm_s390_sync_request_broadcast(kvm, KVM_REQ_STOP_MIGRATION);
+ if (!kvm->arch.use_cmma)
+ return 0;
+
+ kvm_s390_sync_request_broadcast(kvm, KVM_REQ_STOP_MIGRATION);
/* Clear cmma_d on all existing PGSTEs and set cmma_dirty_pages to 0. */
gmap_set_cmma_all_clean(kvm->arch.gmap);
atomic64_set(&kvm->arch.cmma_dirty_pages, 0);
diff --git a/arch/s390/kvm/pci.c b/arch/s390/kvm/pci.c
index 686113be0530..720bb58cabe2 100644
--- a/arch/s390/kvm/pci.c
+++ b/arch/s390/kvm/pci.c
@@ -300,9 +300,14 @@ static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
gaite->gisc = fib->fmt0.isc;
gaite->count++;
- gaite->aisbo = fib->fmt0.aisbo;
- gaite->aisb = virt_to_phys(page_address(aisb_page) + (fib->fmt0.aisb &
- ~PAGE_MASK));
+ if (fib->fmt0.sum == 1) {
+ gaite->aisbo = fib->fmt0.aisbo;
+ gaite->aisb = virt_to_phys(page_address(aisb_page) +
+ (fib->fmt0.aisb & ~PAGE_MASK));
+ } else {
+ gaite->aisbo = 0;
+ gaite->aisb = 0;
+ }
aift->kzdev[zdev->aisb] = zdev->kzdev;
spin_unlock_irq(&aift->gait_lock);
diff --git a/arch/s390/mm/hugetlbpage.c b/arch/s390/mm/hugetlbpage.c
index db35d8fe8609..f84aa9265430 100644
--- a/arch/s390/mm/hugetlbpage.c
+++ b/arch/s390/mm/hugetlbpage.c
@@ -147,10 +147,12 @@ void __set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
if (likely(pte_present(pte)))
rste |= _REGION3_ENTRY_LARGE;
rste |= _REGION_ENTRY_TYPE_R3;
- } else if (likely(pte_present(pte)))
- rste |= _SEGMENT_ENTRY_LARGE;
-
- set_pte(ptep, __pte(rste));
+ set_pud((pud_t *)ptep, __pud(rste));
+ } else {
+ if (likely(pte_present(pte)))
+ rste |= _SEGMENT_ENTRY_LARGE;
+ set_pmd((pmd_t *)ptep, __pmd(rste));
+ }
}
void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
diff --git a/arch/s390/mm/mmap.c b/arch/s390/mm/mmap.c
index 2a222a7e14f4..ef7bfc87758c 100644
--- a/arch/s390/mm/mmap.c
+++ b/arch/s390/mm/mmap.c
@@ -64,7 +64,7 @@ static inline unsigned long mmap_base(unsigned long rnd,
return PAGE_ALIGN(STACK_TOP - gap - rnd);
}
-static int get_align_mask(struct file *filp, unsigned long flags)
+static unsigned long get_align_mask(struct file *filp, unsigned long flags)
{
if (filp && is_file_hugepages(filp))
return huge_page_mask_align(filp);
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index b5571667a89b..a614f6b2f7df 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -124,6 +124,7 @@ config X86
select ARCH_SUPPORTS_DEBUG_PAGEALLOC
select ARCH_SUPPORTS_HUGETLBFS
select ARCH_SUPPORTS_PAGE_TABLE_CHECK if X86_64
+ select ARCH_HAS_PTE_PROTNONE if X86_64
select ARCH_SUPPORTS_NUMA_BALANCING if X86_64
select ARCH_SUPPORTS_KMAP_LOCAL_FORCE_MAP if NR_CPUS <= 4096
select ARCH_SUPPORTS_CFI if X86_64
diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
index d9dab940ff62..1aca51390f73 100644
--- a/arch/x86/boot/compressed/head_64.S
+++ b/arch/x86/boot/compressed/head_64.S
@@ -172,19 +172,23 @@ SYM_FUNC_START(startup_32)
/*
* Build early 4G boot pagetable
*/
- /*
- * If SEV is active then set the encryption mask in the page tables.
- * This will ensure that when the kernel is copied and decompressed
- * it will be done so encrypted.
- */
xorl %edx, %edx
#ifdef CONFIG_AMD_MEM_ENCRYPT
call get_sev_encryption_bit
xorl %edx, %edx
testl %eax, %eax
jz 1f
- subl $32, %eax /* Encryption bit is always above bit 31 */
- bts %eax, %edx /* Set encryption mask for page tables */
+
+ /* Encryption bit is always above bit 31 */
+ subl $32, %eax
+
+ /*
+ * If SEV is active then set the encryption mask in the page tables.
+ * This will ensure that when the kernel is copied and decompressed it
+ * will be done so encrypted.
+ */
+ bts %eax, %edx
+
/*
* Set MSR_AMD64_SEV_ENABLED_BIT in sev_status so that
* startup32_check_sev_cbit() will do a check. sev_enable() will
diff --git a/arch/x86/events/amd/core.c b/arch/x86/events/amd/core.c
index 11f499cc2dc3..49b6b8fce566 100644
--- a/arch/x86/events/amd/core.c
+++ b/arch/x86/events/amd/core.c
@@ -754,13 +754,11 @@ static void amd_pmu_enable_event(struct perf_event *event)
x86_pmu_enable_event(event);
}
-static void amd_pmu_enable_all(int added)
+static void __amd_pmu_enable_all(void)
{
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
int idx;
- amd_brs_enable_all();
-
for_each_set_bit(idx, x86_pmu.cntr_mask, X86_PMC_IDX_MAX) {
/* only activate events which are marked as active */
if (!test_bit(idx, cpuc->active_mask))
@@ -775,6 +773,12 @@ static void amd_pmu_enable_all(int added)
}
}
+static void amd_pmu_enable_all(int added)
+{
+ amd_brs_enable_all();
+ __amd_pmu_enable_all();
+}
+
static void amd_pmu_v2_enable_event(struct perf_event *event)
{
struct hw_perf_event *hwc = &event->hw;
@@ -1561,7 +1565,7 @@ static inline void amd_pmu_reload_virt(void)
* set global enable bits once again
*/
amd_pmu_v2_disable_all();
- amd_pmu_enable_all(0);
+ __amd_pmu_enable_all();
amd_pmu_v2_enable_all(0);
return;
}
diff --git a/arch/x86/include/asm/kvm-x86-nested-ops.h b/arch/x86/include/asm/kvm-x86-nested-ops.h
new file mode 100644
index 000000000000..4b1be5bcecaa
--- /dev/null
+++ b/arch/x86/include/asm/kvm-x86-nested-ops.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#if !defined(KVM_X86_NESTED_OP) || \
+ !defined(KVM_X86_NESTED_OP_OPTIONAL) || \
+ !defined(KVM_X86_NESTED_OP_OPTIONAL_RET0)
+#error Missing one or more KVM_X86_NESTED_OP #defines
+#else
+/*
+ * KVM_X86_NESTED_OP() and KVM_X86_NESTED_OP_OPTIONAL() are used to help
+ * generate both DECLARE/DEFINE_STATIC_CALL() invocations and
+ * "static_call_update()" calls.
+ *
+ * KVM_X86_NESTED_OP_OPTIONAL() can be used for those functions that can have
+ * a NULL definition. KVM_X86_NESTED_OP_OPTIONAL_RET0() can be used likewise
+ * to make a definition optional, but in this case the default will
+ * be __static_call_return0.
+ */
+KVM_X86_NESTED_OP(leave_nested)
+KVM_X86_NESTED_OP(is_exception_vmexit)
+KVM_X86_NESTED_OP(check_events)
+KVM_X86_NESTED_OP_OPTIONAL_RET0(has_events)
+KVM_X86_NESTED_OP(triple_fault)
+KVM_X86_NESTED_OP(get_state)
+KVM_X86_NESTED_OP(set_state)
+KVM_X86_NESTED_OP(get_nested_state_pages)
+KVM_X86_NESTED_OP_OPTIONAL_RET0(write_log_dirty)
+KVM_X86_NESTED_OP(translate_nested_gpa)
+#ifdef CONFIG_KVM_HYPERV
+KVM_X86_NESTED_OP_OPTIONAL(enable_evmcs)
+KVM_X86_NESTED_OP_OPTIONAL_RET0(get_evmcs_version)
+KVM_X86_NESTED_OP(hv_inject_synthetic_vmexit_post_tlb_flush)
+#endif
+#endif
+
+#undef KVM_X86_NESTED_OP
+#undef KVM_X86_NESTED_OP_OPTIONAL
+#undef KVM_X86_NESTED_OP_OPTIONAL_RET0
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index b517257a6315..974a506538aa 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -125,24 +125,6 @@
#define KVM_REQ_UPDATE_PROTECTED_GUEST_STATE \
KVM_ARCH_REQ_FLAGS(34, KVM_REQUEST_WAIT)
-#define CR0_RESERVED_BITS \
- (~(unsigned long)(X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS \
- | X86_CR0_ET | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM \
- | X86_CR0_NW | X86_CR0_CD | X86_CR0_PG))
-
-#define CR4_RESERVED_BITS \
- (~(unsigned long)(X86_CR4_VME | X86_CR4_PVI | X86_CR4_TSD | X86_CR4_DE\
- | X86_CR4_PSE | X86_CR4_PAE | X86_CR4_MCE \
- | X86_CR4_PGE | X86_CR4_PCE | X86_CR4_OSFXSR | X86_CR4_PCIDE \
- | X86_CR4_OSXSAVE | X86_CR4_SMEP | X86_CR4_FSGSBASE \
- | X86_CR4_OSXMMEXCPT | X86_CR4_LA57 | X86_CR4_VMXE \
- | X86_CR4_SMAP | X86_CR4_PKE | X86_CR4_UMIP \
- | X86_CR4_LAM_SUP | X86_CR4_CET))
-
-#define CR8_RESERVED_BITS (~(unsigned long)X86_CR8_TPR)
-
-
-
#define INVALID_PAGE (~(hpa_t)0)
#define VALID_PAGE(x) ((x) != INVALID_PAGE)
@@ -230,37 +212,6 @@ enum x86_intercept_stage;
#define KVM_NR_DB_REGS 4
-#define DR6_BUS_LOCK (1 << 11)
-#define DR6_BD (1 << 13)
-#define DR6_BS (1 << 14)
-#define DR6_BT (1 << 15)
-#define DR6_RTM (1 << 16)
-/*
- * DR6_ACTIVE_LOW combines fixed-1 and active-low bits.
- * We can regard all the bits in DR6_FIXED_1 as active_low bits;
- * they will never be 0 for now, but when they are defined
- * in the future it will require no code change.
- *
- * DR6_ACTIVE_LOW is also used as the init/reset value for DR6.
- */
-#define DR6_ACTIVE_LOW 0xffff0ff0
-#define DR6_VOLATILE 0x0001e80f
-#define DR6_FIXED_1 (DR6_ACTIVE_LOW & ~DR6_VOLATILE)
-
-#define DR7_BP_EN_MASK 0x000000ff
-#define DR7_GE (1 << 9)
-#define DR7_GD (1 << 13)
-#define DR7_VOLATILE 0xffff2bff
-
-#define KVM_GUESTDBG_VALID_MASK \
- (KVM_GUESTDBG_ENABLE | \
- KVM_GUESTDBG_SINGLESTEP | \
- KVM_GUESTDBG_USE_HW_BP | \
- KVM_GUESTDBG_USE_SW_BP | \
- KVM_GUESTDBG_INJECT_BP | \
- KVM_GUESTDBG_INJECT_DB | \
- KVM_GUESTDBG_BLOCKIRQ)
-
#define PFERR_PRESENT_MASK BIT(0)
#define PFERR_WRITE_MASK BIT(1)
#define PFERR_USER_MASK BIT(2)
@@ -290,19 +241,11 @@ enum x86_intercept_stage;
#define PFERR_PRIVATE_ACCESS BIT_ULL(49)
#define PFERR_SYNTHETIC_MASK (PFERR_IMPLICIT_ACCESS | PFERR_PRIVATE_ACCESS)
-/* apic attention bits */
-#define KVM_APIC_CHECK_VAPIC 0
-/*
- * The following bit is set with PV-EOI, unset on EOI.
- * We detect PV-EOI changes by guest by comparing
- * this bit with PV-EOI in guest memory.
- * See the implementation in apic_update_pv_eoi.
- */
-#define KVM_APIC_PV_EOI_PENDING 1
-
struct kvm_kernel_irqfd;
struct kvm_kernel_irq_routing_entry;
+struct kvm_apic_map;
+
struct kvm_x86_msr_filter;
struct kvm_x86_pmu_event_filter;
@@ -705,95 +648,6 @@ struct kvm_mtrr {
u64 deftype;
};
-/* Hyper-V SynIC timer */
-struct kvm_vcpu_hv_stimer {
- struct hrtimer timer;
- int index;
- union hv_stimer_config config;
- u64 count;
- u64 exp_time;
- struct hv_message msg;
- bool msg_pending;
-};
-
-/* Hyper-V synthetic interrupt controller (SynIC)*/
-struct kvm_vcpu_hv_synic {
- u64 version;
- u64 control;
- u64 msg_page;
- u64 evt_page;
- atomic64_t sint[HV_SYNIC_SINT_COUNT];
- atomic_t sint_to_gsi[HV_SYNIC_SINT_COUNT];
- DECLARE_BITMAP(auto_eoi_bitmap, 256);
- DECLARE_BITMAP(vec_bitmap, 256);
- bool active;
- bool dont_zero_synic_pages;
-};
-
-/* The maximum number of entries on the TLB flush fifo. */
-#define KVM_HV_TLB_FLUSH_FIFO_SIZE (16)
-/*
- * Note: the following 'magic' entry is made up by KVM to avoid putting
- * anything besides GVA on the TLB flush fifo. It is theoretically possible
- * to observe a request to flush 4095 PFNs starting from 0xfffffffffffff000
- * which will look identical. KVM's action to 'flush everything' instead of
- * flushing these particular addresses is, however, fully legitimate as
- * flushing more than requested is always OK.
- */
-#define KVM_HV_TLB_FLUSHALL_ENTRY ((u64)-1)
-
-enum hv_tlb_flush_fifos {
- HV_L1_TLB_FLUSH_FIFO,
- HV_L2_TLB_FLUSH_FIFO,
- HV_NR_TLB_FLUSH_FIFOS,
-};
-
-struct kvm_vcpu_hv_tlb_flush_fifo {
- spinlock_t write_lock;
- DECLARE_KFIFO(entries, u64, KVM_HV_TLB_FLUSH_FIFO_SIZE);
-};
-
-/* Hyper-V per vcpu emulation context */
-struct kvm_vcpu_hv {
- struct kvm_vcpu *vcpu;
- u32 vp_index;
- u64 hv_vapic;
- s64 runtime_offset;
- struct kvm_vcpu_hv_synic synic;
- struct kvm_hyperv_exit exit;
- struct kvm_vcpu_hv_stimer stimer[HV_SYNIC_STIMER_COUNT];
- DECLARE_BITMAP(stimer_pending_bitmap, HV_SYNIC_STIMER_COUNT);
- bool enforce_cpuid;
- struct {
- u32 features_eax; /* HYPERV_CPUID_FEATURES.EAX */
- u32 features_ebx; /* HYPERV_CPUID_FEATURES.EBX */
- u32 features_edx; /* HYPERV_CPUID_FEATURES.EDX */
- u32 enlightenments_eax; /* HYPERV_CPUID_ENLIGHTMENT_INFO.EAX */
- u32 enlightenments_ebx; /* HYPERV_CPUID_ENLIGHTMENT_INFO.EBX */
- u32 syndbg_cap_eax; /* HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES.EAX */
- u32 nested_eax; /* HYPERV_CPUID_NESTED_FEATURES.EAX */
- u32 nested_ebx; /* HYPERV_CPUID_NESTED_FEATURES.EBX */
- } cpuid_cache;
-
- struct kvm_vcpu_hv_tlb_flush_fifo tlb_flush_fifo[HV_NR_TLB_FLUSH_FIFOS];
-
- /*
- * Preallocated buffers for handling hypercalls that pass sparse vCPU
- * sets (for high vCPU counts, they're too large to comfortably fit on
- * the stack).
- */
- u64 sparse_banks[HV_MAX_SPARSE_VCPU_BANKS];
- DECLARE_BITMAP(vcpu_mask, KVM_MAX_VCPUS);
-
- struct hv_vp_assist_page vp_assist_page;
-
- struct {
- u64 pa_page_gpa;
- u64 vm_id;
- u32 vp_id;
- } nested;
-};
-
struct kvm_hypervisor_cpuid {
u32 base;
u32 limit;
@@ -824,6 +678,8 @@ struct kvm_vcpu_xen {
};
#endif
+struct kvm_vcpu_hv;
+
struct kvm_queued_exception {
bool pending;
bool injected;
@@ -1181,39 +1037,6 @@ struct kvm_arch_memory_slot {
unsigned short *gfn_write_track;
};
-/*
- * Track the mode of the optimized logical map, as the rules for decoding the
- * destination vary per mode. Enabling the optimized logical map requires all
- * software-enabled local APIs to be in the same mode, each addressable APIC to
- * be mapped to only one MDA, and each MDA to map to at most one APIC.
- */
-enum kvm_apic_logical_mode {
- /* All local APICs are software disabled. */
- KVM_APIC_MODE_SW_DISABLED,
- /* All software enabled local APICs in xAPIC cluster addressing mode. */
- KVM_APIC_MODE_XAPIC_CLUSTER,
- /* All software enabled local APICs in xAPIC flat addressing mode. */
- KVM_APIC_MODE_XAPIC_FLAT,
- /* All software enabled local APICs in x2APIC mode. */
- KVM_APIC_MODE_X2APIC,
- /*
- * Optimized map disabled, e.g. not all local APICs in the same logical
- * mode, same logical ID assigned to multiple APICs, etc.
- */
- KVM_APIC_MODE_MAP_DISABLED,
-};
-
-struct kvm_apic_map {
- struct rcu_head rcu;
- enum kvm_apic_logical_mode logical_mode;
- u32 max_apic_id;
- union {
- struct kvm_lapic *xapic_flat_map[8];
- struct kvm_lapic *xapic_cluster_map[16][4];
- };
- struct kvm_lapic *phys_map[];
-};
-
/* Hyper-V synthetic debugger (SynDbg)*/
struct kvm_hv_syndbg {
struct {
@@ -1842,8 +1665,6 @@ struct kvm_x86_ops {
void (*update_cpu_dirty_logging)(struct kvm_vcpu *vcpu);
- const struct kvm_x86_nested_ops *nested_ops;
-
void (*vcpu_blocking)(struct kvm_vcpu *vcpu);
void (*vcpu_unblocking)(struct kvm_vcpu *vcpu);
@@ -1906,6 +1727,8 @@ struct kvm_x86_ops {
};
struct kvm_x86_nested_ops {
+ bool enabled;
+
void (*leave_nested)(struct kvm_vcpu *vcpu);
bool (*is_exception_vmexit)(struct kvm_vcpu *vcpu, u8 vector,
u32 error_code);
@@ -1937,6 +1760,7 @@ struct kvm_x86_init_ops {
struct kvm_x86_ops *runtime_ops;
struct kvm_pmu_ops *pmu_ops;
+ struct kvm_x86_nested_ops *nested_ops;
};
struct kvm_arch_async_pf {
@@ -1952,6 +1776,7 @@ extern bool __read_mostly enable_apicv;
extern bool __read_mostly enable_ipiv;
extern bool __read_mostly enable_device_posted_irqs;
extern struct kvm_x86_ops kvm_x86_ops;
+extern struct kvm_x86_nested_ops kvm_nested_ops __read_mostly;
#define kvm_x86_call(func) static_call(kvm_x86_##func)
@@ -1961,6 +1786,14 @@ extern struct kvm_x86_ops kvm_x86_ops;
#define KVM_X86_OP_OPTIONAL_RET0 KVM_X86_OP
#include <asm/kvm-x86-ops.h>
+#define kvm_nested_call(func) static_call(kvm_x86_nested_##func)
+
+#define KVM_X86_NESTED_OP(func) \
+ DECLARE_STATIC_CALL(kvm_x86_nested_##func, *(((struct kvm_x86_nested_ops *)0)->func));
+#define KVM_X86_NESTED_OP_OPTIONAL KVM_X86_NESTED_OP
+#define KVM_X86_NESTED_OP_OPTIONAL_RET0 KVM_X86_NESTED_OP
+#include <asm/kvm-x86-nested-ops.h>
+
#define __KVM_HAVE_ARCH_VM_ALLOC
static inline struct kvm *kvm_arch_alloc_vm(void)
{
@@ -2019,13 +1852,6 @@ static inline unsigned long read_msr(unsigned long msr)
}
#endif
-enum {
- TASK_SWITCH_CALL = 0,
- TASK_SWITCH_IRET = 1,
- TASK_SWITCH_JMP = 2,
- TASK_SWITCH_GATE = 3,
-};
-
#define HF_GUEST_MASK (1 << 0) /* VCPU is in guest-mode */
#ifdef CONFIG_KVM_SMM
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
index 5ce8251bd098..9c80b54f986b 100644
--- a/arch/x86/include/asm/pgtable.h
+++ b/arch/x86/include/asm/pgtable.h
@@ -411,19 +411,19 @@ static inline pte_t pte_wrprotect(pte_t pte)
}
#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_WP
-static inline int pte_uffd_wp(pte_t pte)
+static inline int pte_uffd(pte_t pte)
{
- return pte_flags(pte) & _PAGE_UFFD_WP;
+ return pte_flags(pte) & _PAGE_UFFD;
}
-static inline pte_t pte_mkuffd_wp(pte_t pte)
+static inline pte_t pte_mkuffd(pte_t pte)
{
- return pte_wrprotect(pte_set_flags(pte, _PAGE_UFFD_WP));
+ return pte_wrprotect(pte_set_flags(pte, _PAGE_UFFD));
}
-static inline pte_t pte_clear_uffd_wp(pte_t pte)
+static inline pte_t pte_clear_uffd(pte_t pte)
{
- return pte_clear_flags(pte, _PAGE_UFFD_WP);
+ return pte_clear_flags(pte, _PAGE_UFFD);
}
#endif /* CONFIG_HAVE_ARCH_USERFAULTFD_WP */
@@ -526,19 +526,19 @@ static inline pmd_t pmd_wrprotect(pmd_t pmd)
}
#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_WP
-static inline int pmd_uffd_wp(pmd_t pmd)
+static inline int pmd_uffd(pmd_t pmd)
{
- return pmd_flags(pmd) & _PAGE_UFFD_WP;
+ return pmd_flags(pmd) & _PAGE_UFFD;
}
-static inline pmd_t pmd_mkuffd_wp(pmd_t pmd)
+static inline pmd_t pmd_mkuffd(pmd_t pmd)
{
- return pmd_wrprotect(pmd_set_flags(pmd, _PAGE_UFFD_WP));
+ return pmd_wrprotect(pmd_set_flags(pmd, _PAGE_UFFD));
}
-static inline pmd_t pmd_clear_uffd_wp(pmd_t pmd)
+static inline pmd_t pmd_clear_uffd(pmd_t pmd)
{
- return pmd_clear_flags(pmd, _PAGE_UFFD_WP);
+ return pmd_clear_flags(pmd, _PAGE_UFFD);
}
#endif /* CONFIG_HAVE_ARCH_USERFAULTFD_WP */
@@ -985,11 +985,7 @@ static inline int pmd_present(pmd_t pmd)
return pmd_flags(pmd) & (_PAGE_PRESENT | _PAGE_PROTNONE | _PAGE_PSE);
}
-#ifdef CONFIG_NUMA_BALANCING
-/*
- * These work without NUMA balancing but the kernel does not care. See the
- * comment in include/linux/pgtable.h
- */
+#ifdef CONFIG_ARCH_HAS_PTE_PROTNONE
static inline int pte_protnone(pte_t pte)
{
return (pte_flags(pte) & (_PAGE_PROTNONE | _PAGE_PRESENT))
@@ -1001,7 +997,7 @@ static inline int pmd_protnone(pmd_t pmd)
return (pmd_flags(pmd) & (_PAGE_PROTNONE | _PAGE_PRESENT))
== _PAGE_PROTNONE;
}
-#endif /* CONFIG_NUMA_BALANCING */
+#endif /* CONFIG_ARCH_HAS_PTE_PROTNONE */
static inline int pmd_none(pmd_t pmd)
{
@@ -1564,34 +1560,34 @@ static inline pmd_t pmd_swp_clear_soft_dirty(pmd_t pmd)
#endif
#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_WP
-static inline pte_t pte_swp_mkuffd_wp(pte_t pte)
+static inline pte_t pte_swp_mkuffd(pte_t pte)
{
- return pte_set_flags(pte, _PAGE_SWP_UFFD_WP);
+ return pte_set_flags(pte, _PAGE_SWP_UFFD);
}
-static inline int pte_swp_uffd_wp(pte_t pte)
+static inline int pte_swp_uffd(pte_t pte)
{
- return pte_flags(pte) & _PAGE_SWP_UFFD_WP;
+ return pte_flags(pte) & _PAGE_SWP_UFFD;
}
-static inline pte_t pte_swp_clear_uffd_wp(pte_t pte)
+static inline pte_t pte_swp_clear_uffd(pte_t pte)
{
- return pte_clear_flags(pte, _PAGE_SWP_UFFD_WP);
+ return pte_clear_flags(pte, _PAGE_SWP_UFFD);
}
-static inline pmd_t pmd_swp_mkuffd_wp(pmd_t pmd)
+static inline pmd_t pmd_swp_mkuffd(pmd_t pmd)
{
- return pmd_set_flags(pmd, _PAGE_SWP_UFFD_WP);
+ return pmd_set_flags(pmd, _PAGE_SWP_UFFD);
}
-static inline int pmd_swp_uffd_wp(pmd_t pmd)
+static inline int pmd_swp_uffd(pmd_t pmd)
{
- return pmd_flags(pmd) & _PAGE_SWP_UFFD_WP;
+ return pmd_flags(pmd) & _PAGE_SWP_UFFD;
}
-static inline pmd_t pmd_swp_clear_uffd_wp(pmd_t pmd)
+static inline pmd_t pmd_swp_clear_uffd(pmd_t pmd)
{
- return pmd_clear_flags(pmd, _PAGE_SWP_UFFD_WP);
+ return pmd_clear_flags(pmd, _PAGE_SWP_UFFD);
}
#endif /* CONFIG_HAVE_ARCH_USERFAULTFD_WP */
diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h
index 2ec250ba467e..af08d98be930 100644
--- a/arch/x86/include/asm/pgtable_types.h
+++ b/arch/x86/include/asm/pgtable_types.h
@@ -31,7 +31,7 @@
#define _PAGE_BIT_SPECIAL _PAGE_BIT_SOFTW1
#define _PAGE_BIT_CPA_TEST _PAGE_BIT_SOFTW1
-#define _PAGE_BIT_UFFD_WP _PAGE_BIT_SOFTW2 /* userfaultfd wrprotected */
+#define _PAGE_BIT_UFFD _PAGE_BIT_SOFTW2 /* userfaultfd tracking */
#define _PAGE_BIT_SOFT_DIRTY _PAGE_BIT_SOFTW3 /* software dirty tracking */
#define _PAGE_BIT_KERNEL_4K _PAGE_BIT_SOFTW3 /* page must not be converted to large */
@@ -39,7 +39,7 @@
#define _PAGE_BIT_SAVED_DIRTY _PAGE_BIT_SOFTW5 /* Saved Dirty bit (leaf) */
#define _PAGE_BIT_NOPTISHADOW _PAGE_BIT_SOFTW5 /* No PTI shadow (root PGD) */
#else
-/* Shared with _PAGE_BIT_UFFD_WP which is not supported on 32 bit */
+/* Shared with _PAGE_BIT_UFFD which is not supported on 32 bit */
#define _PAGE_BIT_SAVED_DIRTY _PAGE_BIT_SOFTW2 /* Saved Dirty bit (leaf) */
#define _PAGE_BIT_NOPTISHADOW _PAGE_BIT_SOFTW2 /* No PTI shadow (root PGD) */
#endif
@@ -111,11 +111,11 @@
#endif
#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_WP
-#define _PAGE_UFFD_WP (_AT(pteval_t, 1) << _PAGE_BIT_UFFD_WP)
-#define _PAGE_SWP_UFFD_WP _PAGE_USER
+#define _PAGE_UFFD (_AT(pteval_t, 1) << _PAGE_BIT_UFFD)
+#define _PAGE_SWP_UFFD _PAGE_USER
#else
-#define _PAGE_UFFD_WP (_AT(pteval_t, 0))
-#define _PAGE_SWP_UFFD_WP (_AT(pteval_t, 0))
+#define _PAGE_UFFD (_AT(pteval_t, 0))
+#define _PAGE_SWP_UFFD (_AT(pteval_t, 0))
#endif
#if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE)
@@ -129,7 +129,7 @@
/*
* The hardware requires shadow stack to be Write=0,Dirty=1. However,
* there are valid cases where the kernel might create read-only PTEs that
- * are dirty (e.g., fork(), mprotect(), uffd-wp(), soft-dirty tracking). In
+ * are dirty (e.g., fork(), mprotect(), userfaultfd, soft-dirty tracking). In
* this case, the _PAGE_SAVED_DIRTY bit is used instead of the HW-dirty bit,
* to avoid creating a wrong "shadow stack" PTEs. Such PTEs have
* (Write=0,SavedDirty=1,Dirty=0) set.
@@ -151,7 +151,7 @@
#define _COMMON_PAGE_CHG_MASK (PTE_PFN_MASK | _PAGE_PCD | _PAGE_PWT | \
_PAGE_SPECIAL | _PAGE_ACCESSED | \
_PAGE_DIRTY_BITS | _PAGE_SOFT_DIRTY | \
- _PAGE_CC | _PAGE_UFFD_WP)
+ _PAGE_CC | _PAGE_UFFD)
#define _PAGE_CHG_MASK (_COMMON_PAGE_CHG_MASK | _PAGE_PAT)
#define _HPAGE_CHG_MASK (_COMMON_PAGE_CHG_MASK | _PAGE_PSE | _PAGE_PAT_LARGE)
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
index 81e113eb7c7c..d4a6422f04eb 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -65,9 +65,15 @@ const_cpu_current_top_of_stack = cpu_current_top_of_stack;
__end_rodata_hpage_align = .; \
__end_rodata_aligned = .;
+#if defined(CONFIG_MITIGATION_PAGE_TABLE_ISOLATION) || defined(CONFIG_MITIGATION_SRSO)
#define ALIGN_ENTRY_TEXT_BEGIN . = ALIGN(PMD_SIZE);
#define ALIGN_ENTRY_TEXT_END . = ALIGN(PMD_SIZE);
#else
+#define ALIGN_ENTRY_TEXT_BEGIN
+#define ALIGN_ENTRY_TEXT_END
+#endif
+
+#else
#define X86_ALIGN_RODATA_BEGIN
#define X86_ALIGN_RODATA_END \
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index b66800e867f9..6da6e9189a3e 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -370,7 +370,7 @@ static u32 cpuid_get_reg_unsafe(struct kvm_cpuid_entry2 *entry, u32 reg)
}
}
-static int cpuid_func_emulated(struct kvm_cpuid_entry2 *entry, u32 func,
+static int cpuid_func_emulated(struct kvm_cpuid_entry2 *entry, u32 func, u32 index,
bool include_partially_emulated);
void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
@@ -400,7 +400,7 @@ void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
if (!entry)
continue;
- cpuid_func_emulated(&emulated, cpuid.function, true);
+ cpuid_func_emulated(&emulated, cpuid.function, cpuid.index, true);
/*
* A vCPU has a feature if it's supported by KVM and is enabled
@@ -1369,11 +1369,15 @@ static struct kvm_cpuid_entry2 *do_host_cpuid(struct kvm_cpuid_array *array,
return entry;
}
-static int cpuid_func_emulated(struct kvm_cpuid_entry2 *entry, u32 func,
+static int cpuid_func_emulated(struct kvm_cpuid_entry2 *entry, u32 func, u32 index,
bool include_partially_emulated)
{
memset(entry, 0, sizeof(*entry));
+ /* KVM doesn't currently emulate any non-zero indices. */
+ if (cpuid_function_is_indexed(func) && index)
+ return 0;
+
entry->function = func;
entry->index = 0;
entry->flags = 0;
@@ -1411,7 +1415,7 @@ static int __do_cpuid_func_emulated(struct kvm_cpuid_array *array, u32 func)
if (array->nent >= array->maxnent)
return -E2BIG;
- array->nent += cpuid_func_emulated(&array->entries[array->nent], func, false);
+ array->nent += cpuid_func_emulated(&array->entries[array->nent], func, 0, false);
return 0;
}
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index b566ab5c7515..8071b372d233 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -3298,8 +3298,12 @@ static int em_dr_write(struct x86_emulate_ctxt *ctxt)
else
val = ctxt->src.val & ~0U;
- /* #UD condition is already handled. */
- if (ctxt->ops->set_dr(ctxt, ctxt->modrm_reg, val) < 0)
+ /*
+ * A #GP due to an illegal value should be impossible at this point, as
+ * such #GPs have priority over MOV DR intercepts on SVM, i.e. KVM must
+ * manually check the value *before* emulating the write.
+ */
+ if (WARN_ON_ONCE(ctxt->ops->set_dr(ctxt, ctxt->modrm_reg, val)))
return emulate_gp(ctxt, 0);
/* Disable writeback. */
@@ -3834,31 +3838,53 @@ static int check_cr_access(struct x86_emulate_ctxt *ctxt)
static int check_dr_read(struct x86_emulate_ctxt *ctxt)
{
+ bool is_intel = ctxt->ops->guest_cpuid_is_intel_compatible(ctxt);
int dr = ctxt->modrm_reg;
- u64 cr4;
if (dr > 7)
return emulate_ud(ctxt);
- cr4 = ctxt->ops->get_cr(ctxt, 4);
- if ((cr4 & X86_CR4_DE) && (dr == 4 || dr == 5))
+ if ((dr == 4 || dr == 5) && (ctxt->ops->get_cr(ctxt, 4) & X86_CR4_DE))
return emulate_ud(ctxt);
+ /* Intel CPUs prioritize the DR7.GD=1 #DB over the CPL>0 #GP. */
+ if (!is_intel && ctxt->ops->cpl(ctxt))
+ return emulate_gp(ctxt, 0);
+
if (ctxt->ops->get_effective_dr7(ctxt) & DR7_GD)
return emulate_db(ctxt, DR6_BD);
+ if (is_intel && ctxt->ops->cpl(ctxt))
+ return emulate_gp(ctxt, 0);
+
return X86EMUL_CONTINUE;
}
static int check_dr_write(struct x86_emulate_ctxt *ctxt)
{
u64 new_val = ctxt->src.val64;
- int dr = ctxt->modrm_reg;
+ int rc;
- if ((dr == 6 || dr == 7) && (new_val & 0xffffffff00000000ULL))
- return emulate_gp(ctxt, 0);
+ rc = check_dr_read(ctxt);
+ if (rc != X86EMUL_CONTINUE)
+ return rc;
- return check_dr_read(ctxt);
+ switch (ctxt->modrm_reg) {
+ case 4:
+ case 6:
+ if (!kvm_dr6_valid(new_val))
+ return emulate_gp(ctxt, 0);
+ break;
+ case 5:
+ case 7:
+ if (!kvm_dr7_valid(new_val))
+ return emulate_gp(ctxt, 0);
+ break;
+ default:
+ break;
+ }
+
+ return X86EMUL_CONTINUE;
}
static int check_svme(struct x86_emulate_ctxt *ctxt)
@@ -4367,11 +4393,10 @@ static const struct opcode twobyte_table[256] = {
D(ImplicitOps | ModRM | SrcMem | NoAccess), /* NOP + 7 * reserved NOP */
/* 0x20 - 0x2F */
DIP(ModRM | DstMem | Priv | Op3264 | NoMod, cr_read, check_cr_access),
- DIP(ModRM | DstMem | Priv | Op3264 | NoMod, dr_read, check_dr_read),
+ DIP(ModRM | DstMem | Op3264 | NoMod, dr_read, check_dr_read),
IIP(ModRM | SrcMem | Priv | Op3264 | NoMod, em_cr_write, cr_write,
check_cr_access),
- IIP(ModRM | SrcMem | Priv | Op3264 | NoMod, em_dr_write, dr_write,
- check_dr_write),
+ IIP(ModRM | SrcMem | Op3264 | NoMod, em_dr_write, dr_write, check_dr_write),
N, N, N, N,
GP(ModRM | DstReg | SrcMem | Mov | Sse | Avx, &pfx_0f_28_0f_29),
GP(ModRM | DstMem | SrcReg | Mov | Sse | Avx, &pfx_0f_28_0f_29),
diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c
index 1ee0d23f8949..39b58f56308b 100644
--- a/arch/x86/kvm/hyperv.c
+++ b/arch/x86/kvm/hyperv.c
@@ -206,14 +206,20 @@ static struct kvm_vcpu *get_vcpu_by_vpidx(struct kvm *kvm, u32 vpidx)
static struct kvm_vcpu_hv_synic *synic_get(struct kvm *kvm, u32 vpidx)
{
- struct kvm_vcpu *vcpu;
struct kvm_vcpu_hv_synic *synic;
+ struct kvm_vcpu_hv *hv_vcpu;
+ struct kvm_vcpu *vcpu;
vcpu = get_vcpu_by_vpidx(kvm, vpidx);
- if (!vcpu || !to_hv_vcpu(vcpu))
+ if (!vcpu)
return NULL;
- synic = to_hv_synic(vcpu);
- return (synic->active) ? synic : NULL;
+
+ hv_vcpu = to_hv_vcpu_safe(vcpu);
+ if (!hv_vcpu)
+ return NULL;
+
+ synic = &hv_vcpu->synic;
+ return READ_ONCE(synic->active) ? synic : NULL;
}
static void kvm_hv_notify_acked_sint(struct kvm_vcpu *vcpu, u32 sint)
@@ -593,8 +599,7 @@ static void stimer_mark_pending(struct kvm_vcpu_hv_stimer *stimer,
{
struct kvm_vcpu *vcpu = hv_stimer_to_vcpu(stimer);
- set_bit(stimer->index,
- to_hv_vcpu(vcpu)->stimer_pending_bitmap);
+ set_bit(stimer->index, vcpu->arch.hyperv->stimer_pending_bitmap);
kvm_make_request(KVM_REQ_HV_STIMER, vcpu);
if (vcpu_kick)
kvm_vcpu_kick(vcpu);
@@ -608,8 +613,7 @@ static void stimer_cleanup(struct kvm_vcpu_hv_stimer *stimer)
stimer->index);
hrtimer_cancel(&stimer->timer);
- clear_bit(stimer->index,
- to_hv_vcpu(vcpu)->stimer_pending_bitmap);
+ clear_bit(stimer->index, vcpu->arch.hyperv->stimer_pending_bitmap);
stimer->msg_pending = false;
stimer->exp_time = 0;
}
@@ -972,7 +976,6 @@ int kvm_hv_vcpu_init(struct kvm_vcpu *vcpu)
if (!hv_vcpu)
return -ENOMEM;
- vcpu->arch.hyperv = hv_vcpu;
hv_vcpu->vcpu = vcpu;
synic_init(&hv_vcpu->synic);
@@ -988,6 +991,14 @@ int kvm_hv_vcpu_init(struct kvm_vcpu *vcpu)
spin_lock_init(&hv_vcpu->tlb_flush_fifo[i].write_lock);
}
+ /*
+ * Ensure the structure is fully initialized before it's visible to
+ * other tasks, as much of the state can be legally accessed without
+ * holding vcpu->mutex.
+ *
+ * Pairs with the smp_load_acquire() in to_hv_vcpu_safe().
+ */
+ smp_store_release(&vcpu->arch.hyperv, hv_vcpu);
return 0;
}
@@ -1002,7 +1013,7 @@ int kvm_hv_activate_synic(struct kvm_vcpu *vcpu, bool dont_zero_synic_pages)
synic = to_hv_synic(vcpu);
- synic->active = true;
+ WRITE_ONCE(synic->active, true);
synic->dont_zero_synic_pages = dont_zero_synic_pages;
synic->control = HV_SYNIC_CONTROL_ENABLE;
return 0;
@@ -1935,14 +1946,14 @@ static int kvm_hv_get_tlb_flush_entries(struct kvm *kvm, struct kvm_hv_hcall *hc
return kvm_hv_get_hc_data(kvm, hc, hc->rep_cnt, hc->rep_cnt, entries);
}
-static void hv_tlb_flush_enqueue(struct kvm_vcpu *vcpu,
- struct kvm_vcpu_hv_tlb_flush_fifo *tlb_flush_fifo,
- u64 *entries, int count)
+static void hv_tlb_flush_enqueue(struct kvm_vcpu *vcpu, u64 *entries, int count,
+ bool is_guest_mode)
{
- struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);
+ struct kvm_vcpu_hv_tlb_flush_fifo *tlb_flush_fifo;
u64 flush_all_entry = KVM_HV_TLB_FLUSHALL_ENTRY;
- if (!hv_vcpu)
+ tlb_flush_fifo = kvm_hv_get_tlb_flush_fifo(vcpu, is_guest_mode);
+ if (!tlb_flush_fifo)
return;
spin_lock(&tlb_flush_fifo->write_lock);
@@ -1970,15 +1981,16 @@ out_unlock:
int kvm_hv_vcpu_flush_tlb(struct kvm_vcpu *vcpu)
{
struct kvm_vcpu_hv_tlb_flush_fifo *tlb_flush_fifo;
- struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);
u64 entries[KVM_HV_TLB_FLUSH_FIFO_SIZE];
int i, j, count;
gva_t gva;
- if (!tdp_enabled || !hv_vcpu)
+ if (!tdp_enabled)
return -EINVAL;
tlb_flush_fifo = kvm_hv_get_tlb_flush_fifo(vcpu, is_guest_mode(vcpu));
+ if (!tlb_flush_fifo)
+ return -EINVAL;
count = kfifo_out(&tlb_flush_fifo->entries, entries, KVM_HV_TLB_FLUSH_FIFO_SIZE);
@@ -2017,7 +2029,6 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc)
struct kvm *kvm = vcpu->kvm;
struct hv_tlb_flush_ex flush_ex;
struct hv_tlb_flush flush;
- struct kvm_vcpu_hv_tlb_flush_fifo *tlb_flush_fifo;
/*
* Normally, there can be no more than 'KVM_HV_TLB_FLUSH_FIFO_SIZE'
* entries on the TLB flush fifo. The last entry, however, needs to be
@@ -2144,11 +2155,8 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc)
* analyze it here, flush TLB regardless of the specified address space.
*/
if (all_cpus && !is_guest_mode(vcpu)) {
- kvm_for_each_vcpu(i, v, kvm) {
- tlb_flush_fifo = kvm_hv_get_tlb_flush_fifo(v, false);
- hv_tlb_flush_enqueue(v, tlb_flush_fifo,
- tlb_flush_entries, hc->rep_cnt);
- }
+ kvm_for_each_vcpu(i, v, kvm)
+ hv_tlb_flush_enqueue(v, tlb_flush_entries, hc->rep_cnt, false);
kvm_make_all_cpus_request(kvm, KVM_REQ_HV_TLB_FLUSH);
} else if (!is_guest_mode(vcpu)) {
@@ -2158,9 +2166,7 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc)
v = kvm_get_vcpu(kvm, i);
if (!v)
continue;
- tlb_flush_fifo = kvm_hv_get_tlb_flush_fifo(v, false);
- hv_tlb_flush_enqueue(v, tlb_flush_fifo,
- tlb_flush_entries, hc->rep_cnt);
+ hv_tlb_flush_enqueue(v, tlb_flush_entries, hc->rep_cnt, false);
}
kvm_make_vcpus_request_mask(kvm, KVM_REQ_HV_TLB_FLUSH, vcpu_mask);
@@ -2170,7 +2176,7 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc)
bitmap_zero(vcpu_mask, KVM_MAX_VCPUS);
kvm_for_each_vcpu(i, v, kvm) {
- hv_v = to_hv_vcpu(v);
+ hv_v = to_hv_vcpu_safe(v);
/*
* The following check races with nested vCPUs entering/exiting
@@ -2191,9 +2197,7 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc)
continue;
__set_bit(i, vcpu_mask);
- tlb_flush_fifo = kvm_hv_get_tlb_flush_fifo(v, true);
- hv_tlb_flush_enqueue(v, tlb_flush_fifo,
- tlb_flush_entries, hc->rep_cnt);
+ hv_tlb_flush_enqueue(v, tlb_flush_entries, hc->rep_cnt, true);
}
kvm_make_vcpus_request_mask(kvm, KVM_REQ_HV_TLB_FLUSH, vcpu_mask);
@@ -2406,7 +2410,7 @@ static int kvm_hv_hypercall_complete(struct kvm_vcpu *vcpu, u64 result)
ret = kvm_skip_emulated_instruction(vcpu);
if (tlb_lock_count)
- kvm_x86_ops.nested_ops->hv_inject_synthetic_vmexit_post_tlb_flush(vcpu);
+ kvm_nested_call(hv_inject_synthetic_vmexit_post_tlb_flush)(vcpu);
return ret;
}
@@ -2787,8 +2791,8 @@ int kvm_get_hv_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid,
};
int i, nent = ARRAY_SIZE(cpuid_entries);
- if (kvm_x86_ops.nested_ops->get_evmcs_version)
- evmcs_ver = kvm_x86_ops.nested_ops->get_evmcs_version(vcpu);
+ if (kvm_nested_ops.enabled)
+ evmcs_ver = kvm_nested_call(get_evmcs_version)(vcpu);
if (cpuid->nent < nent)
return -E2BIG;
diff --git a/arch/x86/kvm/hyperv.h b/arch/x86/kvm/hyperv.h
index 1c8f7aaab063..622a6553e9ac 100644
--- a/arch/x86/kvm/hyperv.h
+++ b/arch/x86/kvm/hyperv.h
@@ -27,6 +27,96 @@
#ifdef CONFIG_KVM_HYPERV
+
+/* Hyper-V SynIC timer */
+struct kvm_vcpu_hv_stimer {
+ struct hrtimer timer;
+ int index;
+ union hv_stimer_config config;
+ u64 count;
+ u64 exp_time;
+ struct hv_message msg;
+ bool msg_pending;
+};
+
+/* Hyper-V synthetic interrupt controller (SynIC)*/
+struct kvm_vcpu_hv_synic {
+ u64 version;
+ u64 control;
+ u64 msg_page;
+ u64 evt_page;
+ atomic64_t sint[HV_SYNIC_SINT_COUNT];
+ atomic_t sint_to_gsi[HV_SYNIC_SINT_COUNT];
+ DECLARE_BITMAP(auto_eoi_bitmap, 256);
+ DECLARE_BITMAP(vec_bitmap, 256);
+ bool active;
+ bool dont_zero_synic_pages;
+};
+
+/* The maximum number of entries on the TLB flush fifo. */
+#define KVM_HV_TLB_FLUSH_FIFO_SIZE (16)
+/*
+ * Note: the following 'magic' entry is made up by KVM to avoid putting
+ * anything besides GVA on the TLB flush fifo. It is theoretically possible
+ * to observe a request to flush 4095 PFNs starting from 0xfffffffffffff000
+ * which will look identical. KVM's action to 'flush everything' instead of
+ * flushing these particular addresses is, however, fully legitimate as
+ * flushing more than requested is always OK.
+ */
+#define KVM_HV_TLB_FLUSHALL_ENTRY ((u64)-1)
+
+enum hv_tlb_flush_fifos {
+ HV_L1_TLB_FLUSH_FIFO,
+ HV_L2_TLB_FLUSH_FIFO,
+ HV_NR_TLB_FLUSH_FIFOS,
+};
+
+struct kvm_vcpu_hv_tlb_flush_fifo {
+ spinlock_t write_lock;
+ DECLARE_KFIFO(entries, u64, KVM_HV_TLB_FLUSH_FIFO_SIZE);
+};
+
+/* Hyper-V per vcpu emulation context */
+struct kvm_vcpu_hv {
+ struct kvm_vcpu *vcpu;
+ u32 vp_index;
+ u64 hv_vapic;
+ s64 runtime_offset;
+ struct kvm_vcpu_hv_synic synic;
+ struct kvm_hyperv_exit exit;
+ struct kvm_vcpu_hv_stimer stimer[HV_SYNIC_STIMER_COUNT];
+ DECLARE_BITMAP(stimer_pending_bitmap, HV_SYNIC_STIMER_COUNT);
+ bool enforce_cpuid;
+ struct {
+ u32 features_eax; /* HYPERV_CPUID_FEATURES.EAX */
+ u32 features_ebx; /* HYPERV_CPUID_FEATURES.EBX */
+ u32 features_edx; /* HYPERV_CPUID_FEATURES.EDX */
+ u32 enlightenments_eax; /* HYPERV_CPUID_ENLIGHTMENT_INFO.EAX */
+ u32 enlightenments_ebx; /* HYPERV_CPUID_ENLIGHTMENT_INFO.EBX */
+ u32 syndbg_cap_eax; /* HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES.EAX */
+ u32 nested_eax; /* HYPERV_CPUID_NESTED_FEATURES.EAX */
+ u32 nested_ebx; /* HYPERV_CPUID_NESTED_FEATURES.EBX */
+ } cpuid_cache;
+
+ struct kvm_vcpu_hv_tlb_flush_fifo tlb_flush_fifo[HV_NR_TLB_FLUSH_FIFOS];
+
+ /*
+ * Preallocated buffers for handling hypercalls that pass sparse vCPU
+ * sets (for high vCPU counts, they're too large to comfortably fit on
+ * the stack).
+ */
+ u64 sparse_banks[HV_MAX_SPARSE_VCPU_BANKS];
+ DECLARE_BITMAP(vcpu_mask, KVM_MAX_VCPUS);
+
+ struct hv_vp_assist_page vp_assist_page;
+
+ struct {
+ u64 pa_page_gpa;
+ u64 vm_id;
+ u32 vp_id;
+ } nested;
+};
+
/* "Hv#1" signature */
#define HYPERV_CPUID_SIGNATURE_EAX 0x31237648
@@ -62,8 +152,22 @@ static inline struct kvm_hv *to_kvm_hv(struct kvm *kvm)
return &kvm->arch.hyperv;
}
+static inline struct kvm_vcpu_hv *to_hv_vcpu_safe(struct kvm_vcpu *vcpu)
+{
+ /*
+ * Ensure the HyperV structure is fully initialized when accessing it
+ * without holding vcpu->mutex (or some other guarantee that KVM can't
+ * concurrently instantiate the structure).
+ *
+ * Pairs with the smp_store_release() in kvm_hv_vcpu_init().
+ */
+ return smp_load_acquire(&vcpu->arch.hyperv);
+}
+
static inline struct kvm_vcpu_hv *to_hv_vcpu(struct kvm_vcpu *vcpu)
{
+ kvm_lockdep_assert_vcpu_is_locked_or_unreachable(vcpu);
+
return vcpu->arch.hyperv;
}
@@ -88,7 +192,7 @@ static inline struct kvm_hv_syndbg *to_hv_syndbg(struct kvm_vcpu *vcpu)
static inline u32 kvm_hv_get_vpindex(struct kvm_vcpu *vcpu)
{
- struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);
+ struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu_safe(vcpu);
return hv_vcpu ? hv_vcpu->vp_index : vcpu->vcpu_idx;
}
@@ -142,7 +246,7 @@ static inline struct kvm_vcpu *hv_stimer_to_vcpu(struct kvm_vcpu_hv_stimer *stim
static inline bool kvm_hv_has_stimer_pending(struct kvm_vcpu *vcpu)
{
- struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);
+ struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu_safe(vcpu);
if (!hv_vcpu)
return false;
@@ -198,10 +302,13 @@ int kvm_get_hv_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid,
static inline struct kvm_vcpu_hv_tlb_flush_fifo *kvm_hv_get_tlb_flush_fifo(struct kvm_vcpu *vcpu,
bool is_guest_mode)
{
- struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);
+ struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu_safe(vcpu);
int i = is_guest_mode ? HV_L2_TLB_FLUSH_FIFO :
HV_L1_TLB_FLUSH_FIFO;
+ if (!hv_vcpu)
+ return NULL;
+
return &hv_vcpu->tlb_flush_fifo[i];
}
@@ -209,10 +316,12 @@ static inline void kvm_hv_vcpu_purge_flush_tlb(struct kvm_vcpu *vcpu)
{
struct kvm_vcpu_hv_tlb_flush_fifo *tlb_flush_fifo;
- if (!to_hv_vcpu(vcpu) || !kvm_check_request(KVM_REQ_HV_TLB_FLUSH, vcpu))
+ if (!kvm_check_request(KVM_REQ_HV_TLB_FLUSH, vcpu))
return;
tlb_flush_fifo = kvm_hv_get_tlb_flush_fifo(vcpu, is_guest_mode(vcpu));
+ if (!tlb_flush_fifo)
+ return;
kfifo_reset_out(&tlb_flush_fifo->entries);
}
diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c
index 727245a6ab34..871977288272 100644
--- a/arch/x86/kvm/irq.c
+++ b/arch/x86/kvm/irq.c
@@ -495,8 +495,10 @@ int kvm_arch_irq_bypass_add_producer(struct irq_bypass_consumer *cons,
if (irqfd->irq_entry.type == KVM_IRQ_ROUTING_MSI) {
ret = kvm_pi_update_irte(irqfd, &irqfd->irq_entry);
- if (ret)
+ if (ret) {
kvm->arch.nr_possible_bypass_irqs--;
+ irqfd->producer = NULL;
+ }
}
spin_unlock_irq(&kvm->irqfds.lock);
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 6f30bbdddb5a..62169ef5f354 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -75,6 +75,16 @@ module_param(lapic_timer_advance, bool, 0444);
/* step-by-step approximation to mitigate fluctuation */
#define LAPIC_TIMER_ADVANCE_ADJUST_STEP 8
+/* apic attention bits */
+#define KVM_APIC_CHECK_VAPIC 0
+/*
+ * The following bit is set with PV-EOI, unset on EOI.
+ * We detect PV-EOI changes by guest by comparing
+ * this bit with PV-EOI in guest memory.
+ * See the implementation in apic_update_pv_eoi.
+ */
+#define KVM_APIC_PV_EOI_PENDING 1
+
static bool __read_mostly vector_hashing_enabled = true;
module_param_named(vector_hashing, vector_hashing_enabled, bool, 0444);
@@ -3371,6 +3381,12 @@ static void apic_sync_pv_eoi_from_guest(struct kvm_vcpu *vcpu,
struct kvm_lapic *apic)
{
int vector;
+
+ if (unlikely(!pv_eoi_enabled(vcpu))) {
+ __clear_bit(KVM_APIC_PV_EOI_PENDING, &vcpu->arch.apic_attention);
+ return;
+ }
+
/*
* PV EOI state is derived from KVM_APIC_PV_EOI_PENDING in host
* and KVM_PV_EOI_ENABLED in guest memory as follows:
@@ -3382,8 +3398,6 @@ static void apic_sync_pv_eoi_from_guest(struct kvm_vcpu *vcpu,
* KVM_APIC_PV_EOI_PENDING is set, KVM_PV_EOI_ENABLED is unset:
* -> host enabled PV EOI, guest executed EOI.
*/
- BUG_ON(!pv_eoi_enabled(vcpu));
-
if (pv_eoi_test_and_clr_pending(vcpu))
return;
vector = apic_set_eoi(apic);
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
index 58dbb94f980d..bd1098c89d99 100644
--- a/arch/x86/kvm/lapic.h
+++ b/arch/x86/kvm/lapic.h
@@ -32,6 +32,39 @@ enum lapic_mode {
LAPIC_MODE_X2APIC = MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE,
};
+/*
+ * Track the mode of the optimized logical map, as the rules for decoding the
+ * destination vary per mode. Enabling the optimized logical map requires all
+ * software-enabled local APIs to be in the same mode, each addressable APIC to
+ * be mapped to only one MDA, and each MDA to map to at most one APIC.
+ */
+enum kvm_apic_logical_mode {
+ /* All local APICs are software disabled. */
+ KVM_APIC_MODE_SW_DISABLED,
+ /* All software enabled local APICs in xAPIC cluster addressing mode. */
+ KVM_APIC_MODE_XAPIC_CLUSTER,
+ /* All software enabled local APICs in xAPIC flat addressing mode. */
+ KVM_APIC_MODE_XAPIC_FLAT,
+ /* All software enabled local APICs in x2APIC mode. */
+ KVM_APIC_MODE_X2APIC,
+ /*
+ * Optimized map disabled, e.g. not all local APICs in the same logical
+ * mode, same logical ID assigned to multiple APICs, etc.
+ */
+ KVM_APIC_MODE_MAP_DISABLED,
+};
+
+struct kvm_apic_map {
+ struct rcu_head rcu;
+ enum kvm_apic_logical_mode logical_mode;
+ u32 max_apic_id;
+ union {
+ struct kvm_lapic *xapic_flat_map[8];
+ struct kvm_lapic *xapic_cluster_map[16][4];
+ };
+ struct kvm_lapic *phys_map[];
+};
+
enum lapic_lvt_entry {
LVT_TIMER,
LVT_THERMAL_MONITOR,
diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h
index c9f628b97dae..2ae7f9ed4cf8 100644
--- a/arch/x86/kvm/mmu.h
+++ b/arch/x86/kvm/mmu.h
@@ -6,14 +6,14 @@
#include "regs.h"
#include "cpuid.h"
-extern bool tdp_enabled;
+extern bool __read_mostly tdp_enabled;
#ifdef CONFIG_X86_64
-extern bool tdp_mmu_enabled;
+extern bool __read_mostly tdp_mmu_enabled;
#else
#define tdp_mmu_enabled false
#endif
extern bool __read_mostly enable_mmio_caching;
-extern bool eager_page_split;
+extern bool __read_mostly eager_page_split;
#define KVM_MEMSLOT_PAGES_TO_MMU_PAGES_RATIO 50
#define KVM_MIN_ALLOC_MMU_PAGES 64UL
@@ -385,9 +385,8 @@ static inline gpa_t kvm_translate_gpa(struct kvm_vcpu *vcpu,
{
if (!mmu_is_nested(vcpu) || w == &vcpu->arch.ngpa_walk)
return gpa;
- return kvm_x86_ops.nested_ops->translate_nested_gpa(vcpu, gpa, access,
- exception,
- pte_access);
+ return kvm_nested_call(translate_nested_gpa)(vcpu, gpa, access,
+ exception, pte_access);
}
static inline bool kvm_has_mirrored_tdp(const struct kvm *kvm)
diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
index dda1fd266d33..b6b656a72a93 100644
--- a/arch/x86/kvm/mmu/mmu.c
+++ b/arch/x86/kvm/mmu/mmu.c
@@ -105,7 +105,7 @@ module_param_named(flush_on_reuse, force_flush_and_sync_on_reuse, bool, 0644);
* 2. while doing 1. it walks guest-physical to host-physical
* If the hardware supports that we don't need to do shadow paging.
*/
-bool tdp_enabled = false;
+bool __read_mostly tdp_enabled = false;
static bool __ro_after_init tdp_mmu_allowed;
diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h
index e73fc09ec4db..4ee7b03e762d 100644
--- a/arch/x86/kvm/mmu/paging_tmpl.h
+++ b/arch/x86/kvm/mmu/paging_tmpl.h
@@ -235,7 +235,7 @@ static int FNAME(update_accessed_dirty_bits)(struct kvm_vcpu *vcpu,
!(pte & PT_GUEST_DIRTY_MASK)) {
trace_kvm_mmu_set_dirty_bit(table_gfn, index, sizeof(pte));
#if PTTYPE == PTTYPE_EPT
- if (kvm_x86_ops.nested_ops->write_log_dirty(vcpu, addr))
+ if (kvm_nested_call(write_log_dirty)(vcpu, addr))
return -EINVAL;
#endif
pte |= PT_GUEST_DIRTY_MASK;
diff --git a/arch/x86/kvm/msrs.h b/arch/x86/kvm/msrs.h
index b698983e37fb..9c5c6b33e58f 100644
--- a/arch/x86/kvm/msrs.h
+++ b/arch/x86/kvm/msrs.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef ARCH_X86_KVM_MSR_H
-#define ARCH_X86_KVM_MSR_H
+#ifndef ARCH_X86_KVM_MSRS_H
+#define ARCH_X86_KVM_MSRS_H
#include <linux/kvm_host.h>
#include <linux/user-return-notifier.h>
diff --git a/arch/x86/kvm/regs.h b/arch/x86/kvm/regs.h
index 94fd86728fed..447f0ec3e63e 100644
--- a/arch/x86/kvm/regs.h
+++ b/arch/x86/kvm/regs.h
@@ -16,6 +16,44 @@
static_assert(!(KVM_POSSIBLE_CR0_GUEST_BITS & X86_CR0_PDPTR_BITS));
+#define CR0_RESERVED_BITS \
+ (~(unsigned long)(X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS \
+ | X86_CR0_ET | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM \
+ | X86_CR0_NW | X86_CR0_CD | X86_CR0_PG))
+
+#define CR4_RESERVED_BITS \
+ (~(unsigned long)(X86_CR4_VME | X86_CR4_PVI | X86_CR4_TSD | X86_CR4_DE\
+ | X86_CR4_PSE | X86_CR4_PAE | X86_CR4_MCE \
+ | X86_CR4_PGE | X86_CR4_PCE | X86_CR4_OSFXSR | X86_CR4_PCIDE \
+ | X86_CR4_OSXSAVE | X86_CR4_SMEP | X86_CR4_FSGSBASE \
+ | X86_CR4_OSXMMEXCPT | X86_CR4_LA57 | X86_CR4_VMXE \
+ | X86_CR4_SMAP | X86_CR4_PKE | X86_CR4_UMIP \
+ | X86_CR4_LAM_SUP | X86_CR4_CET))
+
+#define CR8_RESERVED_BITS (~(unsigned long)X86_CR8_TPR)
+
+#define DR6_BUS_LOCK (1 << 11)
+#define DR6_BD (1 << 13)
+#define DR6_BS (1 << 14)
+#define DR6_BT (1 << 15)
+#define DR6_RTM (1 << 16)
+/*
+ * DR6_ACTIVE_LOW combines fixed-1 and active-low bits.
+ * We can regard all the bits in DR6_FIXED_1 as active_low bits;
+ * they will never be 0 for now, but when they are defined
+ * in the future it will require no code change.
+ *
+ * DR6_ACTIVE_LOW is also used as the init/reset value for DR6.
+ */
+#define DR6_ACTIVE_LOW 0xffff0ff0
+#define DR6_VOLATILE 0x0001e80f
+#define DR6_FIXED_1 (DR6_ACTIVE_LOW & ~DR6_VOLATILE)
+
+#define DR7_BP_EN_MASK 0x000000ff
+#define DR7_GE (1 << 9)
+#define DR7_GD (1 << 13)
+#define DR7_VOLATILE 0xffff2bff
+
void kvm_post_set_cr0(struct kvm_vcpu *vcpu, unsigned long old_cr0, unsigned long cr0);
void kvm_post_set_cr4(struct kvm_vcpu *vcpu, unsigned long old_cr4, unsigned long cr4);
int kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c
index 58e493a80cb0..c5b1d294b15a 100644
--- a/arch/x86/kvm/svm/avic.c
+++ b/arch/x86/kvm/svm/avic.c
@@ -293,13 +293,10 @@ static int avic_get_physical_id_table_order(struct kvm *kvm)
return get_order((__avic_get_max_physical_id(kvm, NULL) + 1) * sizeof(u64));
}
-int avic_alloc_physical_id_table(struct kvm *kvm)
+static int avic_alloc_physical_id_table(struct kvm *kvm)
{
struct kvm_svm *kvm_svm = to_kvm_svm(kvm);
- if (!irqchip_in_kernel(kvm) || !enable_apicv)
- return 0;
-
if (kvm_svm->avic_physical_id_table)
return 0;
@@ -311,39 +308,32 @@ int avic_alloc_physical_id_table(struct kvm *kvm)
return 0;
}
-void avic_vm_destroy(struct kvm *kvm)
+static int avic_alloc_logical_id_table(struct kvm *kvm)
{
- unsigned long flags;
struct kvm_svm *kvm_svm = to_kvm_svm(kvm);
- if (!enable_apicv)
- return;
+ if (kvm_svm->avic_logical_id_table)
+ return 0;
- free_page((unsigned long)kvm_svm->avic_logical_id_table);
- free_pages((unsigned long)kvm_svm->avic_physical_id_table,
- avic_get_physical_id_table_order(kvm));
+ kvm_svm->avic_logical_id_table = (void *)get_zeroed_page(GFP_KERNEL_ACCOUNT);
+ if (!kvm_svm->avic_logical_id_table)
+ return -ENOMEM;
- spin_lock_irqsave(&svm_vm_data_hash_lock, flags);
- hash_del(&kvm_svm->hnode);
- spin_unlock_irqrestore(&svm_vm_data_hash_lock, flags);
+ return 0;
}
-int avic_vm_init(struct kvm *kvm)
+static void avic_add_vm_to_ga_log_list(struct kvm *kvm)
{
- unsigned long flags;
- int err = -ENOMEM;
struct kvm_svm *kvm_svm = to_kvm_svm(kvm);
struct kvm_svm *k2;
u32 vm_id;
- if (!enable_apicv)
- return 0;
+ lockdep_assert_held(&kvm->lock);
- kvm_svm->avic_logical_id_table = (void *)get_zeroed_page(GFP_KERNEL_ACCOUNT);
- if (!kvm_svm->avic_logical_id_table)
- goto free_avic;
+ if (kvm_svm->avic_vm_id)
+ return;
- spin_lock_irqsave(&svm_vm_data_hash_lock, flags);
+ guard(spinlock_irqsave)(&svm_vm_data_hash_lock);
again:
vm_id = next_vm_id = (next_vm_id + 1) & AVIC_VM_ID_MASK;
if (vm_id == 0) { /* id is 1-based, zero is not okay */
@@ -359,13 +349,53 @@ int avic_vm_init(struct kvm *kvm)
}
kvm_svm->avic_vm_id = vm_id;
hash_add(svm_vm_data_hash, &kvm_svm->hnode, kvm_svm->avic_vm_id);
- spin_unlock_irqrestore(&svm_vm_data_hash_lock, flags);
+}
+
+int avic_vcpu_precreate(struct kvm *kvm)
+{
+ int r;
+
+ if (!irqchip_in_kernel(kvm) || WARN_ON_ONCE(!enable_apicv))
+ return 0;
+
+ /*
+ * Don't unwind on failure, all actions must be idempotent with respect
+ * to creating multiple vCPUs, i.e. must persist until the VM is destroyed.
+ */
+ r = avic_alloc_physical_id_table(kvm);
+ if (r)
+ return r;
+
+ r = avic_alloc_logical_id_table(kvm);
+ if (r)
+ return r;
+ avic_add_vm_to_ga_log_list(kvm);
return 0;
+}
+
+void avic_vm_pre_destroy(struct kvm *kvm)
+{
+ struct kvm_svm *kvm_svm = to_kvm_svm(kvm);
+
+ if (WARN_ON_ONCE(!enable_apicv) || !kvm_svm->avic_vm_id)
+ return;
+
+ guard(spinlock_irqsave)(&svm_vm_data_hash_lock);
-free_avic:
- avic_vm_destroy(kvm);
- return err;
+ hash_del(&kvm_svm->hnode);
+}
+
+void avic_vm_destroy(struct kvm *kvm)
+{
+ struct kvm_svm *kvm_svm = to_kvm_svm(kvm);
+
+ if (!enable_apicv)
+ return;
+
+ free_page((unsigned long)kvm_svm->avic_logical_id_table);
+ free_pages((unsigned long)kvm_svm->avic_physical_id_table,
+ avic_get_physical_id_table_order(kvm));
}
static phys_addr_t avic_get_backing_page_address(struct vcpu_svm *svm)
diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
index ba985a02208a..5e3e280cd483 100644
--- a/arch/x86/kvm/svm/nested.c
+++ b/arch/x86/kvm/svm/nested.c
@@ -2101,7 +2101,6 @@ static int svm_set_nested_state(struct kvm_vcpu *vcpu,
kvm_make_request(KVM_REQ_APICV_UPDATE, vcpu);
kvm_make_request(KVM_REQ_GET_NESTED_STATE_PAGES, vcpu);
- ret = 0;
out_free:
kfree(save);
kfree(ctl);
@@ -2162,7 +2161,7 @@ static gpa_t svm_translate_nested_gpa(struct kvm_vcpu *vcpu, gpa_t gpa,
return w->gva_to_gpa(vcpu, w, gpa, access, exception);
}
-struct kvm_x86_nested_ops svm_nested_ops = {
+struct kvm_x86_nested_ops svm_nested_ops __initdata = {
.leave_nested = svm_leave_nested,
.translate_nested_gpa = svm_translate_nested_gpa,
.is_exception_vmexit = nested_svm_is_exception_vmexit,
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index 427229347876..d968976ed1f6 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -2129,8 +2129,10 @@ int sev_vm_move_enc_context_from(struct kvm *kvm, unsigned int source_fd)
if (ret)
return ret;
+ /* Do not allow SNP VM migration until additional state transfer is implemented */
if (kvm->arch.vm_type != source_kvm->arch.vm_type ||
- sev_guest(kvm) || !sev_guest(source_kvm)) {
+ sev_guest(kvm) || !sev_guest(source_kvm) ||
+ sev_snp_guest(source_kvm)) {
ret = -EINVAL;
goto out_unlock;
}
@@ -2331,9 +2333,6 @@ static int sev_gmem_post_populate(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn,
int level;
int ret;
- if (WARN_ON_ONCE(sev_populate_args->type != KVM_SEV_SNP_PAGE_TYPE_ZERO && !src_page))
- return -EINVAL;
-
ret = snp_lookup_rmpentry((u64)pfn, &assigned, &level);
if (ret || assigned) {
pr_debug("%s: Failed to ensure GFN 0x%llx RMP entry is initial shared state, ret: %d assigned: %d\n",
@@ -2422,10 +2421,12 @@ static int snp_launch_update(struct kvm *kvm, struct kvm_sev_cmd *argp)
params.type != KVM_SEV_SNP_PAGE_TYPE_CPUID))
return -EINVAL;
- src = params.type == KVM_SEV_SNP_PAGE_TYPE_ZERO ? NULL : u64_to_user_ptr(params.uaddr);
-
- if (!PAGE_ALIGNED(src))
+ if (params.type == KVM_SEV_SNP_PAGE_TYPE_ZERO)
+ src = NULL;
+ else if (!params.uaddr || !PAGE_ALIGNED(params.uaddr))
return -EINVAL;
+ else
+ src = u64_to_user_ptr(params.uaddr);
npages = params.len / PAGE_SIZE;
@@ -2851,8 +2852,10 @@ int sev_vm_copy_enc_context_from(struct kvm *kvm, unsigned int source_fd)
* disallow out-of-band SEV/SEV-ES init if the target is already an
* SEV guest, or if vCPUs have been created. KVM relies on vCPUs being
* created after SEV/SEV-ES initialization, e.g. to init intercepts.
+ * Also do not allow SNP VM mirroring until additional state transfer is implemented.
*/
if (sev_guest(kvm) || !sev_guest(source_kvm) ||
+ sev_snp_guest(source_kvm) ||
is_mirroring_enc_context(source_kvm) || kvm->created_vcpus) {
ret = -EINVAL;
goto e_unlock;
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 3deba9ab0acb..7cdd64023411 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -1306,11 +1306,6 @@ void svm_switch_vmcb(struct vcpu_svm *svm, struct kvm_vmcb_info *target_vmcb)
svm->vmcb = target_vmcb->ptr;
}
-static int svm_vcpu_precreate(struct kvm *kvm)
-{
- return avic_alloc_physical_id_table(kvm);
-}
-
static int svm_vcpu_create(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm;
@@ -5302,12 +5297,6 @@ static int svm_vm_init(struct kvm *kvm)
if (!pause_filter_count || !pause_filter_thresh)
kvm_disable_exits(kvm, KVM_X86_DISABLE_EXITS_PAUSE);
- if (enable_apicv) {
- int ret = avic_vm_init(kvm);
- if (ret)
- return ret;
- }
-
svm_srso_vm_init();
return 0;
}
@@ -5333,13 +5322,14 @@ struct kvm_x86_ops svm_x86_ops __initdata = {
.emergency_disable_virtualization_cpu = svm_emergency_disable_virtualization_cpu,
.has_emulated_msr = svm_has_emulated_msr,
- .vcpu_precreate = svm_vcpu_precreate,
+ .vcpu_precreate = avic_vcpu_precreate,
.vcpu_create = svm_vcpu_create,
.vcpu_free = svm_vcpu_free,
.vcpu_reset = svm_vcpu_reset,
.vm_size = sizeof(struct kvm_svm),
.vm_init = svm_vm_init,
+ .vm_pre_destroy = avic_vm_pre_destroy,
.vm_destroy = svm_vm_destroy,
.prepare_switch_to_guest = svm_prepare_switch_to_guest,
@@ -5426,8 +5416,6 @@ struct kvm_x86_ops svm_x86_ops __initdata = {
.check_intercept = svm_check_intercept,
.handle_exit_irqoff = svm_handle_exit_irqoff,
- .nested_ops = &svm_nested_ops,
-
.deliver_interrupt = svm_deliver_interrupt,
.pi_update_irte = avic_pi_update_irte,
.setup_mce = svm_setup_mce,
@@ -5646,6 +5634,7 @@ static __init int svm_hardware_setup(void)
if (r)
return r;
}
+ svm_nested_ops.enabled = nested;
/*
* KVM's MMU doesn't support using 2-level paging for itself, and thus
@@ -5712,6 +5701,8 @@ static __init int svm_hardware_setup(void)
enable_apicv = avic_hardware_setup();
if (!enable_apicv) {
enable_ipiv = false;
+ svm_x86_ops.vcpu_precreate = NULL;
+ svm_x86_ops.vm_pre_destroy = NULL;
svm_x86_ops.vcpu_blocking = NULL;
svm_x86_ops.vcpu_unblocking = NULL;
svm_x86_ops.vcpu_get_apicv_inhibit_reasons = NULL;
@@ -5772,6 +5763,7 @@ static struct kvm_x86_init_ops svm_init_ops __initdata = {
.runtime_ops = &svm_x86_ops,
.pmu_ops = &amd_pmu_ops,
+ .nested_ops = &svm_nested_ops,
};
static void __svm_exit(void)
diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
index 716be21fba33..03e2b793979d 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -945,9 +945,9 @@ extern struct kvm_x86_nested_ops svm_nested_ops;
bool __init avic_hardware_setup(void);
void avic_hardware_unsetup(void);
-int avic_alloc_physical_id_table(struct kvm *kvm);
+int avic_vcpu_precreate(struct kvm *kvm);
+void avic_vm_pre_destroy(struct kvm *kvm);
void avic_vm_destroy(struct kvm *kvm);
-int avic_vm_init(struct kvm *kvm);
void avic_init_vmcb(struct vcpu_svm *svm, struct vmcb *vmcb);
int avic_incomplete_ipi_interception(struct kvm_vcpu *vcpu);
int avic_unaccelerated_access_interception(struct kvm_vcpu *vcpu);
diff --git a/arch/x86/kvm/tss.h b/arch/x86/kvm/tss.h
index 117bf8bec07d..55ced8975840 100644
--- a/arch/x86/kvm/tss.h
+++ b/arch/x86/kvm/tss.h
@@ -2,6 +2,10 @@
#ifndef __TSS_SEGMENT_H
#define __TSS_SEGMENT_H
+#include <linux/build_bug.h>
+#include <linux/stddef.h>
+#include <linux/types.h>
+
struct tss_segment_32 {
u32 prev_task_link;
u32 esp0;
@@ -64,4 +68,7 @@ struct tss_segment_16 {
#define RMODE_TSS_SIZE \
(TSS_BASE_SIZE + TSS_REDIRECTION_SIZE + TSS_IOPB_SIZE + 1)
+static_assert(offsetof(struct tss_segment_32, io_map) == TSS_IOPB_BASE_OFFSET);
+static_assert(sizeof(struct tss_segment_32) == TSS_BASE_SIZE);
+
#endif
diff --git a/arch/x86/kvm/vmx/main.c b/arch/x86/kvm/vmx/main.c
index 83d9921277ea..04f986e3d439 100644
--- a/arch/x86/kvm/vmx/main.c
+++ b/arch/x86/kvm/vmx/main.c
@@ -995,8 +995,6 @@ struct kvm_x86_ops vt_x86_ops __initdata = {
.update_cpu_dirty_logging = vt_op(update_cpu_dirty_logging),
- .nested_ops = &vmx_nested_ops,
-
.pi_update_irte = vmx_pi_update_irte,
.pi_start_bypass = vmx_pi_start_bypass,
@@ -1038,6 +1036,7 @@ struct kvm_x86_init_ops vt_init_ops __initdata = {
.runtime_ops = &vt_x86_ops,
.pmu_ops = &intel_pmu_ops,
+ .nested_ops = &vmx_nested_ops,
};
static void __exit vt_exit(void)
diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index 0635e92471c8..b5460de4b1a7 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -581,6 +581,9 @@ static int nested_vmx_check_msr_bitmap_controls(struct kvm_vcpu *vcpu,
static int nested_vmx_check_tpr_shadow_controls(struct kvm_vcpu *vcpu,
struct vmcs12 *vmcs12)
{
+ gpa_t vtpr_gpa = vmcs12->virtual_apic_page_addr + APIC_TASKPRI;
+ u32 vtpr;
+
if (!nested_cpu_has(vmcs12, CPU_BASED_TPR_SHADOW))
return 0;
@@ -590,6 +593,32 @@ static int nested_vmx_check_tpr_shadow_controls(struct kvm_vcpu *vcpu,
if (CC(!nested_cpu_has_vid(vmcs12) && vmcs12->tpr_threshold >> 4))
return -EINVAL;
+ /*
+ * Do the illegal vTPR vs. TPR Threshold consistency check if and only
+ * if KVM is configured to WARN on missed consistency checks, otherwise
+ * it's a waste of time. KVM needs to rely on hardware to fully detect
+ * an illegal combination due to the vTPR being writable by L1 at all
+ * times (it's an in-memory value, not a VMCS field). I.e. even if the
+ * check passes now, it might fail at the actual VM-Enter.
+ *
+ * If reading guest memory fails, skip the check as KVM's de facto ABI
+ * for VMX instruction accesses to non-existent memory is to provide
+ * PCI Bus Error semantics (reads return 0xFFs), in which case the vTPR
+ * is guaranteed to greater than or equal to the threshold.
+ *
+ * Note! Deliberately use the VM-scoped API when reading guest memory,
+ * to ensure the read doesn't hit SMRAM when restoring L2 state on RSM,
+ * and only perform the check when in KVM_RUN, to avoid a false failure
+ * if userspace hasn't yet configured memslots during state restore.
+ */
+ if (warn_on_missed_cc && vcpu->wants_to_run &&
+ nested_cpu_has(vmcs12, CPU_BASED_TPR_SHADOW) &&
+ !nested_cpu_has_vid(vmcs12) &&
+ !nested_cpu_has2(vmcs12, SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES) &&
+ !kvm_read_guest(vcpu->kvm, vtpr_gpa, &vtpr, sizeof(vtpr)) &&
+ CC((vmcs12->tpr_threshold & GENMASK(3, 0)) > ((vtpr >> 4) & GENMASK(3, 0))))
+ return -EINVAL;
+
return 0;
}
@@ -1289,6 +1318,9 @@ static void nested_vmx_transition_tlb_flush(struct kvm_vcpu *vcpu,
* is the VPID incorporated into the MMU context. I.e. KVM must assume
* that the new vpid12 has never been used and thus represents a new
* guest ASID that cannot have entries in the TLB.
+ *
+ * Note, last_vpid is initialized as 0, so the first nested VM-Enter
+ * after VMXON will always flush the TLB to avoid using stale entries.
*/
if (is_vmenter && vmcs12->virtual_processor_id != vmx->nested.last_vpid) {
vmx->nested.last_vpid = vmcs12->virtual_processor_id;
@@ -3103,38 +3135,6 @@ static int nested_vmx_check_controls(struct kvm_vcpu *vcpu,
return 0;
}
-static int nested_vmx_check_controls_late(struct kvm_vcpu *vcpu,
- struct vmcs12 *vmcs12)
-{
- void *vapic = to_vmx(vcpu)->nested.virtual_apic_map.hva;
- u32 vtpr = vapic ? (*(u32 *)(vapic + APIC_TASKPRI)) >> 4 : 0;
-
- /*
- * Don't bother with the consistency checks if KVM isn't configured to
- * WARN on missed consistency checks, as KVM needs to rely on hardware
- * to fully detect an illegal vTPR vs. TRP Threshold combination due to
- * the vTPR being writable by L1 at all times (it's an in-memory value,
- * not a VMCS field). I.e. even if the check passes now, it might fail
- * at the actual VM-Enter.
- *
- * Keying off the module param also allows treating an invalid vAPIC
- * mapping as a consistency check failure without increasing the risk
- * of breaking a "real" VM.
- */
- if (!warn_on_missed_cc)
- return 0;
-
- if ((exec_controls_get(to_vmx(vcpu)) & CPU_BASED_TPR_SHADOW) &&
- nested_cpu_has(vmcs12, CPU_BASED_TPR_SHADOW) &&
- !nested_cpu_has_vid(vmcs12) &&
- !nested_cpu_has2(vmcs12, SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES) &&
- (CC(!vapic) ||
- CC((vmcs12->tpr_threshold & GENMASK(3, 0)) > (vtpr & GENMASK(3, 0)))))
- return -EINVAL;
-
- return 0;
-}
-
static int nested_vmx_check_address_space_size(struct kvm_vcpu *vcpu,
struct vmcs12 *vmcs12)
{
@@ -3660,19 +3660,14 @@ enum nvmx_vmentry_status nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu,
&vmx->nested.pre_vmenter_ssp_tbl);
/*
- * Overwrite vmcs01.GUEST_CR3 with L1's CR3 if EPT is disabled. In the
- * event of a "late" VM-Fail, i.e. a VM-Fail detected by hardware but
- * not KVM, KVM must unwind its software model to the pre-VM-Entry host
- * state. When EPT is disabled, GUEST_CR3 holds KVM's shadow CR3, not
- * L1's "real" CR3, which causes nested_vmx_restore_host_state() to
- * corrupt vcpu->arch.cr3. Stuffing vmcs01.GUEST_CR3 results in the
- * unwind naturally setting arch.cr3 to the correct value. Smashing
- * vmcs01.GUEST_CR3 is safe because nested VM-Exits, and the unwind,
- * reset KVM's MMU, i.e. vmcs01.GUEST_CR3 is guaranteed to be
- * overwritten with a shadow CR3 prior to re-entering L1.
+ * Stash L1's CR3, so that in the event of a "late" VM-Fail, i.e. a
+ * VM-Fail detected by hardware but not KVM, KVM can unwind its
+ * software model to the pre-VM-Entry host state. When EPT is
+ * disabled, GUEST_CR3 holds KVM's shadow CR3, not L1's "real" CR3,
+ * and so simply restoring from vmcs01.GUEST_CR3 would corrupt
+ * vcpu->arch.cr3.
*/
- if (!enable_ept)
- vmcs_writel(GUEST_CR3, vcpu->arch.cr3);
+ vmx->nested.pre_vmenter_cr3 = kvm_read_cr3(vcpu);
vmx_switch_vmcs(vcpu, &vmx->nested.vmcs02);
@@ -3684,11 +3679,6 @@ enum nvmx_vmentry_status nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu,
return NVMX_VMENTRY_KVM_INTERNAL_ERROR;
}
- if (nested_vmx_check_controls_late(vcpu, vmcs12)) {
- vmx_switch_vmcs(vcpu, &vmx->vmcs01);
- return NVMX_VMENTRY_VMFAIL;
- }
-
if (nested_vmx_check_guest_state(vcpu, vmcs12,
&entry_failure_code)) {
exit_reason.basic = EXIT_REASON_INVALID_STATE;
@@ -4989,7 +4979,7 @@ static void nested_vmx_restore_host_state(struct kvm_vcpu *vcpu)
vmx_set_cr4(vcpu, vmcs_readl(CR4_READ_SHADOW));
nested_ept_uninit_mmu_context(vcpu);
- vcpu->arch.cr3 = vmcs_readl(GUEST_CR3);
+ vcpu->arch.cr3 = vmx->nested.pre_vmenter_cr3;
kvm_register_mark_available(vcpu, VCPU_REG_CR3);
/*
@@ -5435,6 +5425,13 @@ static int enter_vmx_operation(struct kvm_vcpu *vcpu)
vmx->nested.vpid02 = allocate_vpid();
+ /*
+ * Clear last_vpid to ensure that the VPID is flushed on the first
+ * nested VM-Enter. Otherwise, stale TLB entries from a previous life of
+ * the VPID (e.g. different vCPU or even different VM) could be used.
+ */
+ vmx->nested.last_vpid = 0;
+
vmx->nested.vmcs02_initialized = false;
vmx->nested.vmxon = true;
@@ -6062,8 +6059,8 @@ static int handle_invvpid(struct kvm_vcpu *vcpu)
u64 vpid;
u64 gla;
} operand;
- u16 vpid02;
int r, gpr_index;
+ int cpu;
if (!(vmx->nested.msrs.secondary_ctls_high &
SECONDARY_EXEC_ENABLE_VPID) ||
@@ -6097,42 +6094,34 @@ static int handle_invvpid(struct kvm_vcpu *vcpu)
return kvm_handle_memory_failure(vcpu, r, &e);
if (operand.vpid >> 16)
- return nested_vmx_fail(vcpu,
- VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
+ return nested_vmx_fail(vcpu, VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
+
+ if (type != VMX_VPID_EXTENT_ALL_CONTEXT && !operand.vpid)
+ return nested_vmx_fail(vcpu, VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
+
+ /* LAM doesn't apply to addresses that are inputs to TLB invalidation. */
+ if (type == VMX_VPID_EXTENT_INDIVIDUAL_ADDR &&
+ is_noncanonical_invlpg_address(operand.gla, vcpu))
+ return nested_vmx_fail(vcpu, VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
/*
* Always flush the effective vpid02, i.e. never flush the current VPID
* and never explicitly flush vpid01. INVVPID targets a VPID, not a
* VMCS, and so whether or not the current vmcs12 has VPID enabled is
* irrelevant (and there may not be a loaded vmcs12).
+ *
+ * If vmcs02 was last loaded on a different pCPU, then defer the flush
+ * by invalidating the nested VPID tracking to ensure that KVM performs
+ * the invalidation on the correct pCPU.
*/
- vpid02 = nested_get_vpid02(vcpu);
- switch (type) {
- case VMX_VPID_EXTENT_INDIVIDUAL_ADDR:
- /*
- * LAM doesn't apply to addresses that are inputs to TLB
- * invalidation.
- */
- if (!operand.vpid ||
- is_noncanonical_invlpg_address(operand.gla, vcpu))
- return nested_vmx_fail(vcpu,
- VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
- vpid_sync_vcpu_addr(vpid02, operand.gla);
- break;
- case VMX_VPID_EXTENT_SINGLE_CONTEXT:
- case VMX_VPID_EXTENT_SINGLE_NON_GLOBAL:
- if (!operand.vpid)
- return nested_vmx_fail(vcpu,
- VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
- vpid_sync_context(vpid02);
- break;
- case VMX_VPID_EXTENT_ALL_CONTEXT:
- vpid_sync_context(vpid02);
- break;
- default:
- WARN_ON_ONCE(1);
- return kvm_skip_emulated_instruction(vcpu);
- }
+ cpu = get_cpu();
+ if (cpu != vmx->nested.vmcs02.cpu)
+ vmx->nested.last_vpid = 0;
+ else if (type == VMX_VPID_EXTENT_INDIVIDUAL_ADDR)
+ vpid_sync_vcpu_addr(nested_get_vpid02(vcpu), operand.gla);
+ else
+ vpid_sync_context(nested_get_vpid02(vcpu));
+ put_cpu();
/*
* Sync the shadow page tables if EPT is disabled, L1 is invalidating
@@ -7484,7 +7473,7 @@ static gpa_t vmx_translate_nested_gpa(struct kvm_vcpu *vcpu, gpa_t gpa,
return w->gva_to_gpa(vcpu, w, gpa, access, exception);
}
-struct kvm_x86_nested_ops vmx_nested_ops = {
+struct kvm_x86_nested_ops vmx_nested_ops __initdata = {
.leave_nested = vmx_leave_nested,
.translate_nested_gpa = vmx_translate_nested_gpa,
.is_exception_vmexit = nested_vmx_is_exception_vmexit,
diff --git a/arch/x86/kvm/vmx/nested.h b/arch/x86/kvm/vmx/nested.h
index 6d6cd5904ddf..c6de848bd9ce 100644
--- a/arch/x86/kvm/vmx/nested.h
+++ b/arch/x86/kvm/vmx/nested.h
@@ -57,16 +57,14 @@ bool nested_vmx_check_io_bitmaps(struct kvm_vcpu *vcpu, unsigned int port,
static inline struct vmcs12 *get_vmcs12(struct kvm_vcpu *vcpu)
{
- lockdep_assert_once(lockdep_is_held(&vcpu->mutex) ||
- !refcount_read(&vcpu->kvm->users_count));
+ kvm_lockdep_assert_vcpu_is_locked_or_unreachable(vcpu);
return to_vmx(vcpu)->nested.cached_vmcs12;
}
static inline struct vmcs12 *get_shadow_vmcs12(struct kvm_vcpu *vcpu)
{
- lockdep_assert_once(lockdep_is_held(&vcpu->mutex) ||
- !refcount_read(&vcpu->kvm->users_count));
+ kvm_lockdep_assert_vcpu_is_locked_or_unreachable(vcpu);
return to_vmx(vcpu)->nested.cached_shadow_vmcs12;
}
diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
index 989ab29b8c6f..6ff1469e91cc 100644
--- a/arch/x86/kvm/vmx/tdx.c
+++ b/arch/x86/kvm/vmx/tdx.c
@@ -3188,9 +3188,6 @@ static int tdx_gmem_post_populate(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn,
if (KVM_BUG_ON(kvm_tdx->page_add_src, kvm))
return -EIO;
- if (!src_page)
- return -EOPNOTSUPP;
-
kvm_tdx->page_add_src = src_page;
ret = kvm_tdp_mmu_map_private_pfn(arg->vcpu, gfn, pfn);
kvm_tdx->page_add_src = NULL;
@@ -3237,8 +3234,8 @@ static int tdx_vcpu_init_mem_region(struct kvm_vcpu *vcpu, struct kvm_tdx_cmd *c
if (copy_from_user(&region, u64_to_user_ptr(cmd->data), sizeof(region)))
return -EFAULT;
- if (!PAGE_ALIGNED(region.source_addr) || !PAGE_ALIGNED(region.gpa) ||
- !region.nr_pages ||
+ if (!PAGE_ALIGNED(region.source_addr) || !region.source_addr ||
+ !PAGE_ALIGNED(region.gpa) || !region.nr_pages ||
region.gpa + (region.nr_pages << PAGE_SHIFT) <= region.gpa ||
!vt_is_tdx_private_gpa(kvm, region.gpa) ||
!vt_is_tdx_private_gpa(kvm, region.gpa + (region.nr_pages << PAGE_SHIFT) - 1))
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 8b33feaa617a..a05d8ecbce99 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -2159,7 +2159,7 @@ int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
!guest_has_spec_ctrl_msr(vcpu))
return 1;
- msr_info->data = to_vmx(vcpu)->spec_ctrl;
+ msr_info->data = vmx->spec_ctrl;
break;
case MSR_IA32_SYSENTER_CS:
msr_info->data = vmcs_read32(GUEST_SYSENTER_CS);
@@ -2191,7 +2191,7 @@ int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
if (!msr_info->host_initiated &&
!guest_cpu_cap_has(vcpu, X86_FEATURE_SGX_LC))
return 1;
- msr_info->data = to_vmx(vcpu)->msr_ia32_sgxlepubkeyhash
+ msr_info->data = vmx->msr_ia32_sgxlepubkeyhash
[msr_info->index - MSR_IA32_SGXLEPUBKEYHASH0];
break;
case KVM_FIRST_EMULATED_VMX_MSR ... KVM_LAST_EMULATED_VMX_MSR:
@@ -2404,7 +2404,7 @@ int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
vmx_guest_debugctl_write(vcpu, data);
- if (intel_pmu_lbr_is_enabled(vcpu) && !to_vmx(vcpu)->lbr_desc.event &&
+ if (intel_pmu_lbr_is_enabled(vcpu) && !vmx->lbr_desc.event &&
(data & DEBUGCTLMSR_LBR))
intel_pmu_create_guest_lbr_event(vcpu);
return 0;
@@ -2483,7 +2483,7 @@ int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
break;
case MSR_IA32_MCG_EXT_CTL:
if ((!msr_info->host_initiated &&
- !(to_vmx(vcpu)->msr_ia32_feature_control &
+ !(vmx->msr_ia32_feature_control &
FEAT_CTL_LMCE_ENABLED)) ||
(data & ~MCG_EXT_CTL_LMCE_EN))
return 1;
@@ -3678,13 +3678,14 @@ void vmx_get_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg)
u64 vmx_get_segment_base(struct kvm_vcpu *vcpu, int seg)
{
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
struct kvm_segment s;
- if (to_vmx(vcpu)->rmode.vm86_active) {
+ if (vmx->rmode.vm86_active) {
vmx_get_segment(vcpu, &s, seg);
return s.base;
}
- return vmx_read_guest_seg_base(to_vmx(vcpu), seg);
+ return vmx_read_guest_seg_base(vmx, seg);
}
static int __vmx_get_cpl(struct kvm_vcpu *vcpu, bool no_cache)
@@ -5762,9 +5763,6 @@ static int handle_dr(struct kvm_vcpu *vcpu)
if (!kvm_require_dr(vcpu, dr))
return 1;
- if (vmx_get_cpl(vcpu) > 0)
- goto out;
-
dr7 = vmcs_readl(GUEST_DR7);
if (dr7 & DR7_GD) {
/*
@@ -5785,6 +5783,9 @@ static int handle_dr(struct kvm_vcpu *vcpu)
}
}
+ if (vmx_get_cpl(vcpu) > 0)
+ goto out;
+
if (vcpu->guest_debug == 0) {
exec_controls_clearbit(to_vmx(vcpu), CPU_BASED_MOV_DR_EXITING);
@@ -8786,6 +8787,7 @@ __init int vmx_hardware_setup(void)
if (r)
return r;
}
+ vmx_nested_ops.enabled = nested;
kvm_set_posted_intr_wakeup_handler(pi_wakeup_handler);
diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h
index de9de0d2016c..dc8517f15bc4 100644
--- a/arch/x86/kvm/vmx/vmx.h
+++ b/arch/x86/kvm/vmx/vmx.h
@@ -160,6 +160,13 @@ struct nested_vmx {
bool preemption_timer_expired;
/*
+ * Used to restore L1's CR3 if hardware detects a VM-Fail Consistency
+ * Check that KVM does not, in which case KVM needs to unwind CR3 back
+ * to its pre-VM-Enter state, NOT to vmcs01.HOST_CR3.
+ */
+ unsigned long pre_vmenter_cr3;
+
+ /*
* Used to snapshot MSRs that are conditionally loaded on VM-Enter in
* order to propagate the guest's pre-VM-Enter value into vmcs02. For
* emulation of VMLAUNCH/VMRESUME, the snapshot will be of L1's value.
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 8e1837ba5fa3..598a9706a145 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -115,6 +115,15 @@ EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_host);
#define KVM_CAP_PMU_VALID_MASK KVM_PMU_CAP_DISABLE
+#define KVM_GUESTDBG_VALID_MASK \
+ (KVM_GUESTDBG_ENABLE | \
+ KVM_GUESTDBG_SINGLESTEP | \
+ KVM_GUESTDBG_USE_HW_BP | \
+ KVM_GUESTDBG_USE_SW_BP | \
+ KVM_GUESTDBG_INJECT_BP | \
+ KVM_GUESTDBG_INJECT_DB | \
+ KVM_GUESTDBG_BLOCKIRQ)
+
#define KVM_X2APIC_API_VALID_FLAGS (KVM_X2APIC_API_USE_32BIT_IDS | \
KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK | \
KVM_X2APIC_ENABLE_SUPPRESS_EOI_BROADCAST | \
@@ -154,6 +163,7 @@ static int sync_regs(struct kvm_vcpu *vcpu);
static DEFINE_MUTEX(vendor_module_lock);
struct kvm_x86_ops kvm_x86_ops __read_mostly;
+struct kvm_x86_nested_ops kvm_nested_ops __read_mostly;
#define KVM_X86_OP(func) \
DEFINE_STATIC_CALL_NULL(kvm_x86_##func, \
@@ -165,6 +175,13 @@ EXPORT_STATIC_CALL_GPL(kvm_x86_get_cs_db_l_bits);
EXPORT_STATIC_CALL_GPL(kvm_x86_cache_reg);
EXPORT_STATIC_CALL_GPL(kvm_x86_get_cpl);
+#define KVM_X86_NESTED_OP(func) \
+ DEFINE_STATIC_CALL_NULL(kvm_x86_nested_##func, \
+ *(((struct kvm_x86_nested_ops *)0)->func));
+#define KVM_X86_NESTED_OP_OPTIONAL KVM_X86_NESTED_OP
+#define KVM_X86_NESTED_OP_OPTIONAL_RET0 KVM_X86_NESTED_OP
+#include <asm/kvm-x86-nested-ops.h>
+
unsigned int min_timer_period_us = 200;
module_param(min_timer_period_us, uint, 0644);
@@ -454,7 +471,7 @@ static void kvm_multiple_exception(struct kvm_vcpu *vcpu, unsigned int nr,
* wants to intercept the exception.
*/
if (is_guest_mode(vcpu) &&
- kvm_x86_ops.nested_ops->is_exception_vmexit(vcpu, nr, error_code)) {
+ kvm_nested_call(is_exception_vmexit)(vcpu, nr, error_code)) {
kvm_queue_exception_vmexit(vcpu, nr, has_error, error_code,
has_payload, payload);
return;
@@ -2346,15 +2363,14 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
r &= ~KVM_X2APIC_ENABLE_SUPPRESS_EOI_BROADCAST;
break;
case KVM_CAP_NESTED_STATE:
- r = kvm_x86_ops.nested_ops->get_state ?
- kvm_x86_ops.nested_ops->get_state(NULL, NULL, 0) : 0;
+ r = kvm_nested_ops.enabled ? kvm_nested_call(get_state)(NULL, NULL, 0) : 0;
break;
#ifdef CONFIG_KVM_HYPERV
case KVM_CAP_HYPERV_DIRECT_TLBFLUSH:
r = kvm_x86_ops.enable_l2_tlb_flush != NULL;
break;
case KVM_CAP_HYPERV_ENLIGHTENED_VMCS:
- r = kvm_x86_ops.nested_ops->enable_evmcs != NULL;
+ r = kvm_nested_ops.enabled && kvm_nested_ops.enable_evmcs != NULL;
break;
#endif
case KVM_CAP_SMALLER_MAXPHYADDR:
@@ -3366,9 +3382,10 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
uint16_t vmcs_version;
void __user *user_ptr;
- if (!kvm_x86_ops.nested_ops->enable_evmcs)
+ if (!kvm_nested_ops.enabled ||
+ !kvm_nested_ops.enable_evmcs)
return -ENOTTY;
- r = kvm_x86_ops.nested_ops->enable_evmcs(vcpu, &vmcs_version);
+ r = kvm_nested_call(enable_evmcs)(vcpu, &vmcs_version);
if (!r) {
user_ptr = (void __user *)(uintptr_t)cap->args[0];
if (copy_to_user(user_ptr, &vmcs_version,
@@ -3732,7 +3749,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
u32 user_data_size;
r = -EINVAL;
- if (!kvm_x86_ops.nested_ops->get_state)
+ if (!kvm_nested_ops.enabled)
break;
BUILD_BUG_ON(sizeof(user_data_size) != sizeof(user_kvm_nested_state->size));
@@ -3740,8 +3757,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
if (get_user(user_data_size, &user_kvm_nested_state->size))
break;
- r = kvm_x86_ops.nested_ops->get_state(vcpu, user_kvm_nested_state,
- user_data_size);
+ r = kvm_nested_call(get_state)(vcpu, user_kvm_nested_state, user_data_size);
if (r < 0)
break;
@@ -3762,7 +3778,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
int idx;
r = -EINVAL;
- if (!kvm_x86_ops.nested_ops->set_state)
+ if (!kvm_nested_ops.enabled)
break;
r = -EFAULT;
@@ -3785,7 +3801,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
break;
idx = srcu_read_lock(&vcpu->kvm->srcu);
- r = kvm_x86_ops.nested_ops->set_state(vcpu, user_kvm_nested_state, &kvm_state);
+ r = kvm_nested_call(set_state)(vcpu, user_kvm_nested_state, &kvm_state);
srcu_read_unlock(&vcpu->kvm->srcu, idx);
break;
}
@@ -6903,6 +6919,22 @@ static void kvm_setup_efer_caps(void)
kvm_enable_efer_bits(EFER_AUTOIBRS);
}
+static void kvm_nested_ops_update(const struct kvm_x86_nested_ops *nested_ops)
+{
+ memcpy(&kvm_nested_ops, nested_ops, sizeof(kvm_nested_ops));
+
+#define __KVM_X86_NESTED_OP(func) \
+ static_call_update(kvm_x86_nested_##func, kvm_nested_ops.func);
+#define KVM_X86_NESTED_OP(func) \
+ WARN_ON(!kvm_nested_ops.func); __KVM_X86_NESTED_OP(func)
+#define KVM_X86_NESTED_OP_OPTIONAL __KVM_X86_NESTED_OP
+#define KVM_X86_NESTED_OP_OPTIONAL_RET0(func) \
+ static_call_update(kvm_x86_nested_##func, (void *)kvm_nested_ops.func ? : \
+ (void *)__static_call_return0);
+#include <asm/kvm-x86-nested-ops.h>
+#undef __KVM_X86_NESTED_OP
+}
+
static inline void kvm_ops_update(struct kvm_x86_init_ops *ops)
{
memcpy(&kvm_x86_ops, ops->runtime_ops, sizeof(kvm_x86_ops));
@@ -6918,6 +6950,8 @@ static inline void kvm_ops_update(struct kvm_x86_init_ops *ops)
#include <asm/kvm-x86-ops.h>
#undef __KVM_X86_OP
+ kvm_nested_ops_update(ops->nested_ops);
+
kvm_pmu_ops_update(ops->pmu_ops);
}
@@ -7454,11 +7488,11 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu)
int kvm_check_nested_events(struct kvm_vcpu *vcpu)
{
if (kvm_test_request(KVM_REQ_TRIPLE_FAULT, vcpu)) {
- kvm_x86_ops.nested_ops->triple_fault(vcpu);
+ kvm_nested_call(triple_fault)(vcpu);
return 1;
}
- return kvm_x86_ops.nested_ops->check_events(vcpu);
+ return kvm_nested_call(check_events)(vcpu);
}
static void kvm_inject_exception(struct kvm_vcpu *vcpu)
@@ -7696,9 +7730,7 @@ static int kvm_check_and_inject_events(struct kvm_vcpu *vcpu,
kvm_x86_call(enable_irq_window)(vcpu);
}
- if (is_guest_mode(vcpu) &&
- kvm_x86_ops.nested_ops->has_events &&
- kvm_x86_ops.nested_ops->has_events(vcpu, true))
+ if (is_guest_mode(vcpu) && kvm_nested_call(has_events)(vcpu, true))
*req_immediate_exit = true;
/*
@@ -8021,7 +8053,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
}
if (kvm_check_request(KVM_REQ_GET_NESTED_STATE_PAGES, vcpu)) {
- if (unlikely(!kvm_x86_ops.nested_ops->get_nested_state_pages(vcpu))) {
+ if (unlikely(!kvm_nested_call(get_nested_state_pages)(vcpu))) {
r = 0;
goto out;
}
@@ -8073,7 +8105,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
}
if (kvm_test_request(KVM_REQ_TRIPLE_FAULT, vcpu)) {
if (is_guest_mode(vcpu))
- kvm_x86_ops.nested_ops->triple_fault(vcpu);
+ kvm_nested_call(triple_fault)(vcpu);
if (kvm_check_request(KVM_REQ_TRIPLE_FAULT, vcpu)) {
vcpu->run->exit_reason = KVM_EXIT_SHUTDOWN;
@@ -8491,9 +8523,7 @@ bool kvm_vcpu_has_events(struct kvm_vcpu *vcpu)
if (kvm_hv_has_stimer_pending(vcpu))
return true;
- if (is_guest_mode(vcpu) &&
- kvm_x86_ops.nested_ops->has_events &&
- kvm_x86_ops.nested_ops->has_events(vcpu, false))
+ if (is_guest_mode(vcpu) && kvm_nested_call(has_events)(vcpu, false))
return true;
if (kvm_xen_has_pending_events(vcpu))
@@ -8896,8 +8926,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
* a pending VM-Exit if L1 wants to intercept the exception.
*/
if (vcpu->arch.exception_from_userspace && is_guest_mode(vcpu) &&
- kvm_x86_ops.nested_ops->is_exception_vmexit(vcpu, ex->vector,
- ex->error_code)) {
+ kvm_nested_call(is_exception_vmexit)(vcpu, ex->vector, ex->error_code)) {
kvm_queue_exception_vmexit(vcpu, ex->vector,
ex->has_error_code, ex->error_code,
ex->has_payload, ex->payload);
diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
index 8ece468087a8..e72f8b82da67 100644
--- a/arch/x86/kvm/x86.h
+++ b/arch/x86/kvm/x86.h
@@ -93,7 +93,7 @@ int kvm_check_nested_events(struct kvm_vcpu *vcpu);
/* Forcibly leave the nested mode in cases like a vCPU reset */
static inline void kvm_leave_nested(struct kvm_vcpu *vcpu)
{
- kvm_x86_ops.nested_ops->leave_nested(vcpu);
+ kvm_nested_call(leave_nested)(vcpu);
}
/*
@@ -482,6 +482,12 @@ int kvm_emulate_wbinvd(struct kvm_vcpu *vcpu);
void kvm_vcpu_deliver_sipi_vector(struct kvm_vcpu *vcpu, u8 vector);
+enum kvm_task_switch_reason {
+ TASK_SWITCH_CALL = 0,
+ TASK_SWITCH_IRET = 1,
+ TASK_SWITCH_JMP = 2,
+ TASK_SWITCH_GATE = 3,
+};
int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int idt_index,
int reason, bool has_error_code, u32 error_code);
diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c
index eae17141773a..f93c9c42e03b 100644
--- a/arch/x86/kvm/xen.c
+++ b/arch/x86/kvm/xen.c
@@ -22,6 +22,7 @@
#include <xen/interface/version.h>
#include <xen/interface/event_channel.h>
#include <xen/interface/sched.h>
+#include <xen/xen-ops.h>
#include <asm/xen/cpuid.h>
#include <asm/pvclock.h>
@@ -1103,6 +1104,8 @@ int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data)
break;
case KVM_XEN_VCPU_ATTR_TYPE_VCPU_ID:
+ BUILD_BUG_ON(XEN_VCPU_ID_INVALID < KVM_MAX_VCPUS);
+
if (data->u.vcpu_id >= KVM_MAX_VCPUS)
r = -EINVAL;
else {
@@ -1607,16 +1610,28 @@ static bool kvm_xen_hcall_vcpu_op(struct kvm_vcpu *vcpu, bool longmode, int cmd,
struct vcpu_set_singleshot_timer oneshot;
struct x86_exception e;
+ if (cmd != VCPUOP_set_singleshot_timer &&
+ cmd != VCPUOP_stop_singleshot_timer)
+ return false;
+
if (!kvm_xen_timer_enabled(vcpu))
return false;
- switch (cmd) {
- case VCPUOP_set_singleshot_timer:
- if (vcpu->arch.xen.vcpu_id != vcpu_id) {
- *r = -EINVAL;
- return true;
- }
+ if (vcpu->arch.xen.vcpu_id == XEN_VCPU_ID_INVALID)
+ return false;
+
+ /*
+ * Reject the hypercall if the guest is trying to start/stop the timer
+ * for a different vCPU. Xen per-vCPU hypercalls take a target vCPU as
+ * a common parameter, as all per-vCPU hypercalls *except* single-shot
+ * timer updates can be cross-vCPU.
+ */
+ if (vcpu->arch.xen.vcpu_id != vcpu_id) {
+ *r = -EINVAL;
+ return true;
+ }
+ if (cmd == VCPUOP_set_singleshot_timer) {
/*
* The only difference for 32-bit compat is the 4 bytes of
* padding after the interesting part of the structure. So
@@ -1640,20 +1655,12 @@ static bool kvm_xen_hcall_vcpu_op(struct kvm_vcpu *vcpu, bool longmode, int cmd,
}
kvm_xen_start_timer(vcpu, oneshot.timeout_abs_ns, false);
- *r = 0;
- return true;
-
- case VCPUOP_stop_singleshot_timer:
- if (vcpu->arch.xen.vcpu_id != vcpu_id) {
- *r = -EINVAL;
- return true;
- }
+ } else {
kvm_xen_stop_timer(vcpu);
- *r = 0;
- return true;
}
- return false;
+ *r = 0;
+ return true;
}
static bool kvm_xen_hcall_set_timer_op(struct kvm_vcpu *vcpu, uint64_t timeout,
@@ -2299,7 +2306,7 @@ static bool kvm_xen_hcall_evtchn_send(struct kvm_vcpu *vcpu, u64 param, u64 *r)
void kvm_xen_init_vcpu(struct kvm_vcpu *vcpu)
{
- vcpu->arch.xen.vcpu_id = vcpu->vcpu_idx;
+ vcpu->arch.xen.vcpu_id = XEN_VCPU_ID_INVALID;
vcpu->arch.xen.poll_evtchn = 0;
timer_setup(&vcpu->arch.xen.poll_timer, cancel_evtchn_poll, 0);
diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c
index 90a065fcb1fa..02c56a02eb9b 100644
--- a/arch/x86/platform/efi/quirks.c
+++ b/arch/x86/platform/efi/quirks.c
@@ -832,12 +832,5 @@ void efi_crash_gracefully_on_page_fault(unsigned long phys_addr,
clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
pr_info("Froze efi_rts_wq and disabled EFI Runtime Services\n");
- /*
- * Call schedule() in an infinite loop, so that any spurious wake ups
- * will never run efi_rts_wq again.
- */
- for (;;) {
- set_current_state(TASK_IDLE);
- schedule();
- }
+ efi_rts_park_worker();
}
diff --git a/arch/x86/platform/olpc/olpc-xo15-sci.c b/arch/x86/platform/olpc/olpc-xo15-sci.c
index e486109e88c8..75ed6ceb9df3 100644
--- a/arch/x86/platform/olpc/olpc-xo15-sci.c
+++ b/arch/x86/platform/olpc/olpc-xo15-sci.c
@@ -18,8 +18,6 @@
#define DRV_NAME "olpc-xo15-sci"
#define PFX DRV_NAME ": "
-#define XO15_SCI_CLASS DRV_NAME
-#define XO15_SCI_DEVICE_NAME "OLPC XO-1.5 SCI"
static unsigned long xo15_sci_gpe;
static bool lid_wake_on_close;
@@ -148,9 +146,6 @@ static int xo15_sci_probe(struct platform_device *pdev)
if (!device)
return -ENODEV;
- strscpy(acpi_device_name(device), XO15_SCI_DEVICE_NAME);
- strscpy(acpi_device_class(device), XO15_SCI_CLASS);
-
/* Get GPE bit assignment (EC events). */
status = acpi_evaluate_integer(device->handle, "_GPE", NULL, &tmp);
if (ACPI_FAILURE(status))
diff --git a/arch/xtensa/platforms/iss/simdisk.c b/arch/xtensa/platforms/iss/simdisk.c
index 7c7a2aa749f8..a2ddb49c269d 100644
--- a/arch/xtensa/platforms/iss/simdisk.c
+++ b/arch/xtensa/platforms/iss/simdisk.c
@@ -41,7 +41,7 @@ module_param(simdisk_count, int, S_IRUGO);
MODULE_PARM_DESC(simdisk_count, "Number of simdisk units.");
static int n_files;
-static const char *filename[MAX_SIMDISK_COUNT] = {
+static char *filename[MAX_SIMDISK_COUNT] = {
#ifdef CONFIG_SIMDISK0_FILENAME
CONFIG_SIMDISK0_FILENAME,
#ifdef CONFIG_SIMDISK1_FILENAME
@@ -50,20 +50,48 @@ static const char *filename[MAX_SIMDISK_COUNT] = {
#endif
};
+/*
+ * The simdisk code can be built either into the kernel or as a loadable module.
+ * When built-in, CONFIG_SIMDISK{0,1}_FILENAME can be used to specify the
+ * initial simdisk filenames and additional filenames can be provided on the
+ * kernel command line. These arguments are parsed during early boot when slab
+ * is not yet available, but the command line itself is preserved for the
+ * lifetime of the kernel, so the incoming pointer is stored directly.
+ * When built as a loadable module, each value is copied with kstrdup() and all
+ * allocated memory is freed in simdisk_param_free_filename() when the module is
+ * unloaded.
+ */
static int simdisk_param_set_filename(const char *val,
const struct kernel_param *kp)
{
- if (n_files < ARRAY_SIZE(filename))
- filename[n_files++] = val;
- else
+ char *str;
+
+ if (n_files >= ARRAY_SIZE(filename))
return -EINVAL;
+
+#ifdef MODULE
+ str = kstrdup(val, GFP_KERNEL);
+ if (!str)
+ return -ENOMEM;
+#else
+ str = (char *)val;
+#endif
+
+ filename[n_files++] = str;
return 0;
}
+static void simdisk_param_free_filename(void *arg)
+{
+ for (int i = 0; i < n_files; i++)
+ kfree(filename[i]);
+}
+
static const struct kernel_param_ops simdisk_param_ops_filename = {
.set = simdisk_param_set_filename,
+ .free = simdisk_param_free_filename,
};
-module_param_cb(filename, &simdisk_param_ops_filename, &n_files, 0);
+module_param_cb(filename, &simdisk_param_ops_filename, NULL, 0);
MODULE_PARM_DESC(filename, "Backing storage filename.");
static int simdisk_major = SIMDISK_MAJOR;
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index af7a9b2fd5bc..34412cd697d8 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -789,11 +789,9 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 id,
return irq_find_matching_fwnode(handle, bus_token);
}
-struct fwnode_handle *iort_iwb_handle(u32 iwb_id)
+acpi_handle iort_iwb_handle(u32 iwb_id)
{
- struct fwnode_handle *fwnode;
struct acpi_iort_node *node;
- struct acpi_device *device;
struct acpi_iort_iwb *iwb;
acpi_status status;
acpi_handle handle;
@@ -808,6 +806,19 @@ struct fwnode_handle *iort_iwb_handle(u32 iwb_id)
if (ACPI_FAILURE(status))
return NULL;
+ return handle;
+}
+
+struct fwnode_handle *iort_iwb_handle_fwnode(u32 iwb_id)
+{
+ struct fwnode_handle *fwnode;
+ struct acpi_device *device;
+ acpi_handle handle;
+
+ handle = iort_iwb_handle(iwb_id);
+ if (!handle)
+ return NULL;
+
device = acpi_get_acpi_dev(handle);
if (!device)
return NULL;
@@ -2090,6 +2101,11 @@ static void __init iort_init_platform_devices(void)
}
}
+u32 arch_acpi_add_auto_dep(acpi_handle handle)
+{
+ return acpi_irq_add_auto_dep(handle);
+}
+
void __init acpi_iort_init(void)
{
acpi_status status;
diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c
index d1595156c86a..e4293458bf61 100644
--- a/drivers/acpi/irq.c
+++ b/drivers/acpi/irq.c
@@ -13,6 +13,7 @@
enum acpi_irq_model_id acpi_irq_model;
static acpi_gsi_domain_disp_fn acpi_get_gsi_domain_id;
+static acpi_gsi_handle_disp_fn acpi_get_gsi_handle;
static u32 (*acpi_gsi_to_irq_fallback)(u32 gsi);
/**
@@ -321,15 +322,19 @@ const struct cpumask *acpi_irq_get_affinity(acpi_handle handle,
/**
* acpi_set_irq_model - Setup the GSI irqdomain information
- * @model: the value assigned to acpi_irq_model
- * @fn: a dispatcher function that will return the domain fwnode
- * for a given GSI
+ * @model: the value assigned to acpi_irq_model
+ * @fn: a dispatcher function that will return the domain fwnode
+ * for a given GSI
+ * @gsi_dep_fn: a function to retrieve the acpi_handle a GSI interrupt is
+ * dependent on
+ *
*/
void __init acpi_set_irq_model(enum acpi_irq_model_id model,
- acpi_gsi_domain_disp_fn fn)
+ acpi_gsi_domain_disp_fn fn, acpi_gsi_handle_disp_fn gsi_dep_fn)
{
acpi_irq_model = model;
acpi_get_gsi_domain_id = fn;
+ acpi_get_gsi_handle = gsi_dep_fn;
}
/*
@@ -385,3 +390,162 @@ struct irq_domain *acpi_irq_create_hierarchy(unsigned int flags,
host_data);
}
EXPORT_SYMBOL_GPL(acpi_irq_create_hierarchy);
+
+struct acpi_irq_dep_ctx {
+ int rc;
+ unsigned int index;
+ acpi_handle handle;
+};
+
+static acpi_status acpi_irq_get_parent(struct acpi_resource *ares, void *context)
+{
+ struct acpi_irq_dep_ctx *ctx = context;
+ struct acpi_resource_irq *irq;
+ struct acpi_resource_extended_irq *eirq;
+
+ switch (ares->type) {
+ case ACPI_RESOURCE_TYPE_IRQ:
+ irq = &ares->data.irq;
+ if (ctx->index >= irq->interrupt_count) {
+ ctx->index -= irq->interrupt_count;
+ return AE_OK;
+ }
+ ctx->handle = acpi_get_gsi_handle(irq->interrupts[ctx->index]);
+ ctx->rc = 0;
+ return AE_CTRL_TERMINATE;
+ case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
+ eirq = &ares->data.extended_irq;
+ if (eirq->producer_consumer == ACPI_PRODUCER)
+ return AE_OK;
+
+ if (ctx->index >= eirq->interrupt_count) {
+ ctx->index -= eirq->interrupt_count;
+ return AE_OK;
+ }
+
+ /* Support GSIs only */
+ if (eirq->resource_source.string_length)
+ return AE_OK;
+
+ ctx->handle = acpi_get_gsi_handle(eirq->interrupts[ctx->index]);
+ ctx->rc = 0;
+ return AE_CTRL_TERMINATE;
+ }
+
+ return AE_OK;
+}
+
+static int acpi_irq_get_dep(acpi_handle handle, unsigned int index, acpi_handle *gsi_handle)
+{
+ struct acpi_irq_dep_ctx ctx = {-EINVAL, index, NULL};
+
+ if (!gsi_handle)
+ return -EINVAL;
+
+ acpi_walk_resources(handle, METHOD_NAME__CRS, acpi_irq_get_parent, &ctx);
+ *gsi_handle = ctx.handle;
+
+ return ctx.rc;
+}
+
+static bool acpi_prt_entry_valid(void *prt_entry)
+{
+ struct acpi_pci_routing_table *entry = prt_entry;
+
+ return entry && entry->length > 0;
+}
+
+static void *acpi_prt_next_entry(void *prt_entry)
+{
+ struct acpi_pci_routing_table *entry = prt_entry;
+
+ return prt_entry + entry->length;
+}
+
+static u32 acpi_add_prt_dep(acpi_handle handle)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpi_pci_routing_table *entry;
+ struct acpi_handle_list dep_devices;
+ acpi_handle gsi_handle;
+ acpi_handle link_handle;
+ acpi_status status;
+ u32 count = 0;
+
+ status = acpi_get_irq_routing_table(handle, &buffer);
+ if (ACPI_FAILURE(status)) {
+ acpi_handle_err(handle, "failed to get IRQ routing table\n");
+ kfree(buffer.pointer);
+ return 0;
+ }
+
+ entry = buffer.pointer;
+ for (; acpi_prt_entry_valid(entry); entry = acpi_prt_next_entry(entry)) {
+ if (entry->source[0]) {
+ status = acpi_get_handle(handle, entry->source, &link_handle);
+ if (ACPI_FAILURE(status))
+ continue;
+ dep_devices.count = 1;
+ dep_devices.handles = kcalloc(1, sizeof(*dep_devices.handles), GFP_KERNEL);
+ if (!dep_devices.handles) {
+ acpi_handle_err(handle, "failed to allocate memory\n");
+ continue;
+ }
+
+ dep_devices.handles[0] = link_handle;
+ count += acpi_scan_add_dep(handle, &dep_devices);
+ } else {
+ gsi_handle = acpi_get_gsi_handle(entry->source_index);
+ if (!gsi_handle)
+ continue;
+ dep_devices.count = 1;
+ dep_devices.handles = kcalloc(1, sizeof(*dep_devices.handles), GFP_KERNEL);
+ if (!dep_devices.handles) {
+ acpi_handle_err(handle, "failed to allocate memory\n");
+ continue;
+ }
+
+ dep_devices.handles[0] = gsi_handle;
+ count += acpi_scan_add_dep(handle, &dep_devices);
+ }
+ }
+
+ kfree(buffer.pointer);
+ return count;
+}
+
+static u32 acpi_add_irq_dep(acpi_handle handle)
+{
+ struct acpi_handle_list dep_devices;
+ acpi_handle gsi_handle;
+ u32 count = 0;
+ int i;
+
+ for (i = 0; !acpi_irq_get_dep(handle, i, &gsi_handle); i++) {
+ if (!gsi_handle)
+ continue;
+
+ dep_devices.count = 1;
+ dep_devices.handles = kcalloc(1, sizeof(*dep_devices.handles), GFP_KERNEL);
+ if (!dep_devices.handles) {
+ acpi_handle_err(handle, "failed to allocate memory\n");
+ continue;
+ }
+
+ dep_devices.handles[0] = gsi_handle;
+ count += acpi_scan_add_dep(handle, &dep_devices);
+ }
+
+ return count;
+}
+
+u32 acpi_irq_add_auto_dep(acpi_handle handle)
+{
+ if (!acpi_get_gsi_handle)
+ return 0;
+
+ if (acpi_has_method(handle, "_PRT"))
+ return acpi_add_prt_dep(handle);
+
+ return acpi_add_irq_dep(handle);
+}
diff --git a/drivers/acpi/riscv/irq.c b/drivers/acpi/riscv/irq.c
index 9b88d0993e88..da2c42e0ebfd 100644
--- a/drivers/acpi/riscv/irq.c
+++ b/drivers/acpi/riscv/irq.c
@@ -23,12 +23,6 @@ struct riscv_ext_intc_list {
struct list_head list;
};
-struct acpi_irq_dep_ctx {
- int rc;
- unsigned int index;
- acpi_handle handle;
-};
-
LIST_HEAD(ext_intc_list);
static int irqchip_cmp_func(const void *in0, const void *in1)
@@ -254,7 +248,7 @@ void __init riscv_acpi_init_gsi_mapping(void)
acpi_get_devices("RSCV0006", riscv_acpi_create_gsi_map_smsi, NULL, NULL);
}
-static acpi_handle riscv_acpi_get_gsi_handle(u32 gsi)
+acpi_handle acpi_get_riscv_gsi_handle(u32 gsi)
{
struct riscv_ext_intc_list *ext_intc_element;
struct list_head *i;
@@ -269,138 +263,7 @@ static acpi_handle riscv_acpi_get_gsi_handle(u32 gsi)
return NULL;
}
-static acpi_status riscv_acpi_irq_get_parent(struct acpi_resource *ares, void *context)
-{
- struct acpi_irq_dep_ctx *ctx = context;
- struct acpi_resource_irq *irq;
- struct acpi_resource_extended_irq *eirq;
-
- switch (ares->type) {
- case ACPI_RESOURCE_TYPE_IRQ:
- irq = &ares->data.irq;
- if (ctx->index >= irq->interrupt_count) {
- ctx->index -= irq->interrupt_count;
- return AE_OK;
- }
- ctx->handle = riscv_acpi_get_gsi_handle(irq->interrupts[ctx->index]);
- return AE_CTRL_TERMINATE;
- case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
- eirq = &ares->data.extended_irq;
- if (eirq->producer_consumer == ACPI_PRODUCER)
- return AE_OK;
-
- if (ctx->index >= eirq->interrupt_count) {
- ctx->index -= eirq->interrupt_count;
- return AE_OK;
- }
-
- /* Support GSIs only */
- if (eirq->resource_source.string_length)
- return AE_OK;
-
- ctx->handle = riscv_acpi_get_gsi_handle(eirq->interrupts[ctx->index]);
- return AE_CTRL_TERMINATE;
- }
-
- return AE_OK;
-}
-
-static int riscv_acpi_irq_get_dep(acpi_handle handle, unsigned int index, acpi_handle *gsi_handle)
-{
- struct acpi_irq_dep_ctx ctx = {-EINVAL, index, NULL};
-
- if (!gsi_handle)
- return 0;
-
- acpi_walk_resources(handle, METHOD_NAME__CRS, riscv_acpi_irq_get_parent, &ctx);
- *gsi_handle = ctx.handle;
- if (*gsi_handle)
- return 1;
-
- return 0;
-}
-
-static u32 riscv_acpi_add_prt_dep(acpi_handle handle)
-{
- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
- struct acpi_pci_routing_table *entry;
- struct acpi_handle_list dep_devices;
- acpi_handle gsi_handle;
- acpi_handle link_handle;
- acpi_status status;
- u32 count = 0;
-
- status = acpi_get_irq_routing_table(handle, &buffer);
- if (ACPI_FAILURE(status)) {
- acpi_handle_err(handle, "failed to get IRQ routing table\n");
- kfree(buffer.pointer);
- return 0;
- }
-
- entry = buffer.pointer;
- while (entry && (entry->length > 0)) {
- if (entry->source[0]) {
- acpi_get_handle(handle, entry->source, &link_handle);
- dep_devices.count = 1;
- dep_devices.handles = kzalloc_objs(*dep_devices.handles,
- 1);
- if (!dep_devices.handles) {
- acpi_handle_err(handle, "failed to allocate memory\n");
- continue;
- }
-
- dep_devices.handles[0] = link_handle;
- count += acpi_scan_add_dep(handle, &dep_devices);
- } else {
- gsi_handle = riscv_acpi_get_gsi_handle(entry->source_index);
- dep_devices.count = 1;
- dep_devices.handles = kzalloc_objs(*dep_devices.handles,
- 1);
- if (!dep_devices.handles) {
- acpi_handle_err(handle, "failed to allocate memory\n");
- continue;
- }
-
- dep_devices.handles[0] = gsi_handle;
- count += acpi_scan_add_dep(handle, &dep_devices);
- }
-
- entry = (struct acpi_pci_routing_table *)
- ((unsigned long)entry + entry->length);
- }
-
- kfree(buffer.pointer);
- return count;
-}
-
-static u32 riscv_acpi_add_irq_dep(acpi_handle handle)
-{
- struct acpi_handle_list dep_devices;
- acpi_handle gsi_handle;
- u32 count = 0;
- int i;
-
- for (i = 0;
- riscv_acpi_irq_get_dep(handle, i, &gsi_handle);
- i++) {
- dep_devices.count = 1;
- dep_devices.handles = kzalloc_objs(*dep_devices.handles, 1);
- if (!dep_devices.handles) {
- acpi_handle_err(handle, "failed to allocate memory\n");
- continue;
- }
-
- dep_devices.handles[0] = gsi_handle;
- count += acpi_scan_add_dep(handle, &dep_devices);
- }
-
- return count;
-}
-
u32 arch_acpi_add_auto_dep(acpi_handle handle)
{
- if (acpi_has_method(handle, "_PRT"))
- return riscv_acpi_add_prt_dep(handle);
-
- return riscv_acpi_add_irq_dep(handle);
+ return acpi_irq_add_auto_dep(handle);
}
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 8515e1892643..36c368324138 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -850,6 +850,7 @@ static const char * const acpi_ignore_dep_ids[] = {
/* List of HIDs for which we honor deps of matching ACPI devs, when checking _DEP lists. */
static const char * const acpi_honor_dep_ids[] = {
+ "ARMH0003", /* ARM GICv5 IWB */
"INT3472", /* Camera sensor PMIC / clk and regulator info */
"INTC1059", /* IVSC (TGL) driver must be loaded to allow i2c access to camera sensors */
"INTC1095", /* IVSC (ADL) driver must be loaded to allow i2c access to camera sensors */
@@ -858,6 +859,7 @@ static const char * const acpi_honor_dep_ids[] = {
"INTC10DE", /* CVS (LNL) driver must be loaded to allow camera streaming */
"INTC10E0", /* CVS (ARL) driver must be loaded to allow camera streaming */
"INTC10E1", /* CVS (PTL) driver must be loaded to allow camera streaming */
+ "INTC10FA", /* CVS (NVL) driver must be loaded to allow camera streaming */
"RSCV0001", /* RISC-V PLIC */
"RSCV0002", /* RISC-V APLIC */
"RSCV0005", /* RISC-V SBI MPXY MBOX */
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index eb93c060426f..4286e4af1092 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -22,7 +22,6 @@
#include <linux/initrd.h>
#include <linux/security.h>
#include <linux/kmemleak.h>
-#include <asm/fixmap.h>
#include "internal.h"
#ifdef CONFIG_ACPI_CUSTOM_DSDT
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 335288e8b5b3..fab38bc98113 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -469,9 +469,6 @@ static int rpm_callback(int (*cb)(struct device *), struct device *dev)
if (retval == -EACCES)
retval = -EAGAIN;
- if (retval != -EAGAIN && retval != -EBUSY)
- dev->power.runtime_error = retval;
-
return retval;
}
@@ -751,6 +748,9 @@ static int rpm_suspend(struct device *dev, int rpmflags)
dev->power.deferred_resume = false;
wake_up_all(&dev->power.wait_queue);
+ if (retval != -EAGAIN && retval != -EBUSY)
+ dev->power.runtime_error = retval;
+
/*
* On transient errors, if the callback routine failed an autosuspend,
* and if the last_busy time has been updated so that there is a new
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index f765970578f9..8dad7bf5f664 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -2080,6 +2080,15 @@ static int blkfront_resume(struct xenbus_device *dev)
continue;
/*
+ * For requests split across multiple slots, process the
+ * underlying request only once: skip the linked, sg-less
+ * secondary slot.
+ */
+ if (shadow[j].associated_id != NO_ASSOCIATED_ID &&
+ shadow[j].num_sg == 0)
+ continue;
+
+ /*
* Get the bios in the request so we can re-queue them.
*/
if (req_op(shadow[j].request) == REQ_OP_FLUSH ||
diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c
index 2b7231be5973..7a87549f587d 100644
--- a/drivers/bluetooth/btintel_pcie.c
+++ b/drivers/bluetooth/btintel_pcie.c
@@ -1446,72 +1446,134 @@ exit_on_error:
return err;
}
+/* Queue a coredump dump_traces() pass.
+ *
+ * Returns true if a new coredump was queued, false if one was already
+ * in-flight (the BTINTEL_PCIE_COREDUMP_INPROGRESS bit serves as the
+ * single-writer guard for the @coredump_work item) or the workqueue is
+ * disabled (reset / remove in progress).
+ *
+ * Always queue this AFTER any companion event-reader work (hwexp /
+ * fwtrigger) so that, on the ordered @dump_workqueue, the event reader
+ * runs first and populates dmp_hdr.event_type / event_id before
+ * dump_traces consumes them.
+ */
+static bool btintel_pcie_queue_coredump(struct btintel_pcie_data *data,
+ u16 trigger_reason)
+{
+ if (test_and_set_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags))
+ return false;
+
+ data->dmp_hdr.trigger_reason = trigger_reason;
+
+ if (queue_work(data->dump_workqueue, &data->coredump_work))
+ return true;
+
+ /* Workqueue is disabled (reset/remove drained it). Release the
+ * guard so a later trigger, after re-probe, can succeed.
+ */
+ clear_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags);
+ return false;
+}
+
static void btintel_pcie_msix_fw_trigger_handler(struct btintel_pcie_data *data)
{
bt_dev_dbg(data->hdev, "Received firmware smart trigger cause");
- if (test_and_set_bit(BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS, &data->flags))
+ /* Per-work guard: deduplicate concurrent FW-trigger interrupts.
+ * Cleared at the tail of btintel_pcie_fwtrigger_worker().
+ */
+ if (test_and_set_bit(BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS,
+ &data->flags))
return;
- /* Trigger device core dump when there is FW assert */
- if (!test_and_set_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags))
- data->dmp_hdr.trigger_reason = BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT;
+ if (!queue_work(data->dump_workqueue, &data->fwtrigger_work)) {
+ clear_bit(BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS, &data->flags);
+ return;
+ }
- queue_work(data->coredump_workqueue, &data->coredump_work);
+ /* Queue coredump after the fwtrigger event reader so dmp_hdr.event_*
+ * is populated before dump_traces consumes it.
+ */
+ btintel_pcie_queue_coredump(data, BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT);
}
static void btintel_pcie_msix_hw_exp_handler(struct btintel_pcie_data *data)
{
bt_dev_err(data->hdev, "Received hw exception interrupt");
+ /* CORE_HALTED is the single-writer guard for this handler. It is
+ * set once on first HW exception and cleared only by re-probe
+ * (data is reallocated), so it also serializes hwexp_work
+ * scheduling without needing a separate bit.
+ */
if (test_and_set_bit(BTINTEL_PCIE_CORE_HALTED, &data->flags))
return;
- if (test_and_set_bit(BTINTEL_PCIE_HWEXP_INPROGRESS, &data->flags))
- return;
-
- /* Trigger device core dump when there is HW exception */
- if (!test_and_set_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags))
- data->dmp_hdr.trigger_reason = BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT;
+ /* Queue companion coredump first so it is appended after hwexp_work
+ * on the ordered @dump_workqueue (preserves the original
+ * coredump-then-hwexp ordering).
+ */
+ btintel_pcie_queue_coredump(data, BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT);
- queue_work(data->coredump_workqueue, &data->coredump_work);
+ queue_work(data->dump_workqueue, &data->hwexp_work);
}
static void btintel_pcie_coredump_worker(struct work_struct *work)
{
struct btintel_pcie_data *data = container_of(work,
struct btintel_pcie_data, coredump_work);
- int err;
/* hdev is NULL until setup_hdev() succeeds, and is cleared on
* teardown after disable_work_sync() drains us; bail in that case.
*/
if (!data->hdev)
+ goto out;
+
+ btintel_pcie_dump_traces(data->hdev);
+out:
+ /* Release guard last so a new trigger can run only after this
+ * pass has fully completed (including dev_coredumpv()).
+ */
+ clear_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags);
+}
+
+static void btintel_pcie_hwexp_worker(struct work_struct *work)
+{
+ struct btintel_pcie_data *data = container_of(work,
+ struct btintel_pcie_data, hwexp_work);
+
+ if (!data->hdev)
return;
- if (test_bit(BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS, &data->flags)) {
- err = btintel_pcie_dump_fwtrigger_event(data);
- if (err)
- bt_dev_warn(data->hdev, "failed to log fwtrigger event");
- clear_bit(BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS, &data->flags);
- }
+ /* Unlike usb products, controller will not send hardware exception
+ * event on exception. Instead controller writes the hardware event
+ * to device memory along with optional debug events, raises MSIX
+ * and halts. Driver shall read the exception event from device
+ * memory and passes it to the stack for further processing.
+ *
+ * Re-entry is gated by BTINTEL_PCIE_CORE_HALTED in the IRQ
+ * handler, which is only cleared by re-probe; no per-work bit
+ * is needed here.
+ */
+ btintel_pcie_read_hwexp(data);
+}
- if (test_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags)) {
- btintel_pcie_dump_traces(data->hdev);
- clear_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags);
- }
+static void btintel_pcie_fwtrigger_worker(struct work_struct *work)
+{
+ struct btintel_pcie_data *data = container_of(work,
+ struct btintel_pcie_data, fwtrigger_work);
+ int err;
- if (test_bit(BTINTEL_PCIE_HWEXP_INPROGRESS, &data->flags)) {
- /* Unlike usb products, controller will not send hardware
- * exception event on exception. Instead controller writes the
- * hardware event to device memory along with optional debug
- * events, raises MSIX and halts. Driver shall read the
- * exception event from device memory and passes it stack for
- * further processing.
- */
- btintel_pcie_read_hwexp(data);
- clear_bit(BTINTEL_PCIE_HWEXP_INPROGRESS, &data->flags);
- }
+ if (!data->hdev)
+ goto out;
+
+ err = btintel_pcie_dump_fwtrigger_event(data);
+ if (err)
+ bt_dev_warn(data->hdev, "failed to log fwtrigger event");
+out:
+ /* Release guard last; matches set in fw_trigger handler. */
+ clear_bit(BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS, &data->flags);
}
static void btintel_pcie_rx_work(struct work_struct *work)
@@ -2650,20 +2712,22 @@ static void btintel_pcie_reset_work(struct work_struct *wk)
btintel_pcie_synchronize_irqs(data);
flush_work(&data->rx_work);
- /* Drain any in-flight coredump and block new ones across reset.
- * Safe from self-deadlock: coredump_work runs on a separate wq.
+ /* Drain any in-flight dump workers and block new ones across reset.
+ * Safe from self-deadlock: they all run on a separate wq.
*/
disable_work_sync(&data->coredump_work);
+ disable_work_sync(&data->hwexp_work);
+ disable_work_sync(&data->fwtrigger_work);
bt_dev_dbg(data->hdev, "Release bluetooth interface");
/* Both reset paths follow the same contract: on success they
* destroy 'data' via device_reprobe() (a fresh probe re-INIT_WORKs
- * the coredump_work with disable count 0), so enable_work() must
+ * the dump workers with disable count 0), so enable_work() must
* NOT be called on the success path. Only the FLR path can fail
* with 'data' still alive, in which case we balance the
- * disable_work_sync() above so a later successful reset is not
- * permanently blocked.
+ * disable_work_sync() calls above so a later successful reset is
+ * not permanently blocked.
*
* pci_lock_rescan_remove() (held above) serializes against PCI
* device addition/removal (hotplug), so no device can be added to
@@ -2869,8 +2933,8 @@ static int btintel_pcie_probe(struct pci_dev *pdev,
if (!data->workqueue)
return -ENOMEM;
- data->coredump_workqueue = alloc_ordered_workqueue(KBUILD_MODNAME "_cd", 0);
- if (!data->coredump_workqueue) {
+ data->dump_workqueue = alloc_ordered_workqueue(KBUILD_MODNAME "_cd", 0);
+ if (!data->dump_workqueue) {
destroy_workqueue(data->workqueue);
return -ENOMEM;
}
@@ -2879,6 +2943,8 @@ static int btintel_pcie_probe(struct pci_dev *pdev,
INIT_WORK(&data->rx_work, btintel_pcie_rx_work);
INIT_WORK(&data->reset_work, btintel_pcie_reset_work);
INIT_WORK(&data->coredump_work, btintel_pcie_coredump_worker);
+ INIT_WORK(&data->hwexp_work, btintel_pcie_hwexp_worker);
+ INIT_WORK(&data->fwtrigger_work, btintel_pcie_fwtrigger_worker);
data->boot_stage_cache = 0x00;
data->img_resp_cache = 0x00;
@@ -2921,7 +2987,7 @@ exit_error:
/* reset device before exit */
btintel_pcie_reset_bt(data);
- destroy_workqueue(data->coredump_workqueue);
+ destroy_workqueue(data->dump_workqueue);
pci_clear_master(pdev);
@@ -2940,12 +3006,14 @@ static void btintel_pcie_remove(struct pci_dev *pdev)
return;
}
- /* Permanently block coredump triggers and drain the worker before
- * tearing down. Must run before cancel_work_sync(&reset_work) so
- * the disable counter stays >= 1 even after reset_work()'s
+ /* Permanently block all dump triggers and drain the workers before
+ * tearing down. Must run before disable_work_sync(&reset_work) so
+ * the disable counters stay >= 1 even after reset_work()'s
* balanced enable_work() (counter 2 -> 1, never reaching 0).
*/
disable_work_sync(&data->coredump_work);
+ disable_work_sync(&data->hwexp_work);
+ disable_work_sync(&data->fwtrigger_work);
/* Cancel pending reset work. Skip only when remove() is called from
* within the reset work itself (PLDR device_reprobe path) to avoid
@@ -2973,7 +3041,7 @@ static void btintel_pcie_remove(struct pci_dev *pdev)
btintel_pcie_release_hdev(data);
- destroy_workqueue(data->coredump_workqueue);
+ destroy_workqueue(data->dump_workqueue);
destroy_workqueue(data->workqueue);
btintel_pcie_free(data);
@@ -2992,16 +3060,8 @@ static void btintel_pcie_coredump(struct device *dev)
if (!data)
return;
- if (test_and_set_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags))
- return;
-
- data->dmp_hdr.trigger_reason = BTINTEL_PCIE_TRIGGER_REASON_USER_TRIGGER;
- /* queue_work() returns false if the work is disabled (reset or
- * remove in progress); clear the in-progress bit so a later
- * trigger can succeed once the work is re-enabled.
- */
- if (!queue_work(data->coredump_workqueue, &data->coredump_work))
- clear_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags);
+ btintel_pcie_queue_coredump(data,
+ BTINTEL_PCIE_TRIGGER_REASON_USER_TRIGGER);
}
#endif
@@ -3138,12 +3198,8 @@ static int btintel_pcie_resume(struct device *dev)
if (btintel_pcie_in_error(data) ||
btintel_pcie_in_device_halt(data)) {
bt_dev_err(data->hdev, "Controller in error state for D0 entry");
- if (!test_and_set_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS,
- &data->flags)) {
- data->dmp_hdr.trigger_reason =
- BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT;
- queue_work(data->coredump_workqueue, &data->coredump_work);
- }
+ btintel_pcie_queue_coredump(data,
+ BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT);
set_bit(BTINTEL_PCIE_CORE_HALTED, &data->flags);
btintel_pcie_reset(data->hdev);
}
diff --git a/drivers/bluetooth/btintel_pcie.h b/drivers/bluetooth/btintel_pcie.h
index 7caee093e316..749369b24031 100644
--- a/drivers/bluetooth/btintel_pcie.h
+++ b/drivers/bluetooth/btintel_pcie.h
@@ -118,7 +118,6 @@ enum {
enum {
BTINTEL_PCIE_CORE_HALTED,
- BTINTEL_PCIE_HWEXP_INPROGRESS,
BTINTEL_PCIE_COREDUMP_INPROGRESS,
BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS,
BTINTEL_PCIE_RECOVERY_IN_PROGRESS,
@@ -466,8 +465,11 @@ struct btintel_pcie_dump_header {
* @workqueue: workqueue for RX work
* @rx_skb_q: SKB queue for RX packet
* @rx_work: RX work struct to process the RX packet in @rx_skb_q
- * @coredump_workqueue: dedicated workqueue for coredump collection
- * @coredump_work: work struct for coredump trace collection
+ * @dump_workqueue: dedicated ordered workqueue serializing the coredump,
+ * hardware exception, and firmware-trigger dump workers
+ * @coredump_work: work struct for DRAM trace coredump collection
+ * @hwexp_work: work struct for hardware exception event read
+ * @fwtrigger_work: work struct for firmware-triggered diagnostic event read
* @dma_pool: DMA pool for descriptors, index array and ci
* @dma_p_addr: DMA address for pool
* @dma_v_addr: address of pool
@@ -516,8 +518,10 @@ struct btintel_pcie_data {
struct work_struct rx_work;
struct work_struct reset_work;
- struct workqueue_struct *coredump_workqueue;
+ struct workqueue_struct *dump_workqueue;
struct work_struct coredump_work;
+ struct work_struct hwexp_work;
+ struct work_struct fwtrigger_work;
struct dma_pool *dma_pool;
dma_addr_t dma_p_addr;
diff --git a/drivers/bus/mhi/ep/main.c b/drivers/bus/mhi/ep/main.c
index b1213786f72c..21bc2c50170f 100644
--- a/drivers/bus/mhi/ep/main.c
+++ b/drivers/bus/mhi/ep/main.c
@@ -1340,14 +1340,19 @@ static int mhi_ep_create_device(struct mhi_ep_cntrl *mhi_cntrl, u32 ch_id)
ret = dev_set_name(&mhi_dev->dev, "%s_%s",
dev_name(&mhi_cntrl->mhi_dev->dev),
mhi_dev->name);
- if (ret) {
- put_device(&mhi_dev->dev);
- return ret;
- }
+ if (ret)
+ goto err_put_channels;
ret = device_add(&mhi_dev->dev);
if (ret)
- put_device(&mhi_dev->dev);
+ goto err_put_channels;
+
+ return 0;
+
+err_put_channels:
+ put_device(&mhi_dev->dev); /* DL channel reference */
+ put_device(&mhi_dev->dev); /* UL channel reference */
+ put_device(&mhi_dev->dev); /* device_initialize() reference */
return ret;
}
diff --git a/drivers/bus/mhi/host/main.c b/drivers/bus/mhi/host/main.c
index 53c0ffe30070..4d458396233a 100644
--- a/drivers/bus/mhi/host/main.c
+++ b/drivers/bus/mhi/host/main.c
@@ -170,6 +170,9 @@ EXPORT_SYMBOL_GPL(mhi_get_mhi_state);
void mhi_soc_reset(struct mhi_controller *mhi_cntrl)
{
+ int __maybe_unused ret;
+ u32 tmp;
+
if (mhi_cntrl->reset) {
mhi_cntrl->reset(mhi_cntrl);
return;
@@ -178,6 +181,9 @@ void mhi_soc_reset(struct mhi_controller *mhi_cntrl)
/* Generic MHI SoC reset */
mhi_write_reg(mhi_cntrl, mhi_cntrl->regs, MHI_SOC_RESET_REQ_OFFSET,
MHI_SOC_RESET_REQ);
+ /* Flush the posted write to the device (ignore return value) */
+ ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->regs, MHI_SOC_RESET_REQ_OFFSET,
+ &tmp);
}
EXPORT_SYMBOL_GPL(mhi_soc_reset);
diff --git a/drivers/bus/mhi/host/pm.c b/drivers/bus/mhi/host/pm.c
index f799503c8f36..9d29f1591a45 100644
--- a/drivers/bus/mhi/host/pm.c
+++ b/drivers/bus/mhi/host/pm.c
@@ -651,21 +651,13 @@ static void mhi_pm_sys_error_transition(struct mhi_controller *mhi_cntrl)
/* Trigger MHI RESET so that the device will not access host memory */
if (reset_device) {
- u32 in_reset = -1;
- unsigned long timeout = msecs_to_jiffies(mhi_cntrl->timeout_ms);
-
dev_dbg(dev, "Triggering MHI Reset in device\n");
mhi_set_mhi_state(mhi_cntrl, MHI_STATE_RESET);
/* Wait for the reset bit to be cleared by the device */
- ret = wait_event_timeout(mhi_cntrl->state_event,
- mhi_read_reg_field(mhi_cntrl,
- mhi_cntrl->regs,
- MHICTRL,
- MHICTRL_RESET_MASK,
- &in_reset) ||
- !in_reset, timeout);
- if (!ret || in_reset) {
+ ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs, MHICTRL,
+ MHICTRL_RESET_MASK, 0, 25000, mhi_cntrl->timeout_ms);
+ if (ret) {
dev_err(dev, "Device failed to exit MHI Reset state\n");
write_lock_irq(&mhi_cntrl->pm_lock);
cur_state = mhi_tryset_pm_state(mhi_cntrl,
diff --git a/drivers/bus/qcom-ebi2.c b/drivers/bus/qcom-ebi2.c
index be8166565e7c..ab00c75b9e95 100644
--- a/drivers/bus/qcom-ebi2.c
+++ b/drivers/bus/qcom-ebi2.c
@@ -353,7 +353,7 @@ static int qcom_ebi2_probe(struct platform_device *pdev)
/* Figure out the chipselect */
ret = of_property_read_u32(child, "reg", &csindex);
if (ret)
- return ret;
+ goto err_disable_clk;
if (csindex > 5) {
dev_err(dev,
@@ -372,8 +372,12 @@ static int qcom_ebi2_probe(struct platform_device *pdev)
have_children = true;
}
- if (have_children)
- return of_platform_default_populate(np, NULL, dev);
+ if (have_children) {
+ ret = of_platform_default_populate(np, NULL, dev);
+ if (ret)
+ goto err_disable_clk;
+ }
+
return 0;
err_disable_clk:
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index 9309cfb935be..9a88d287fa09 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -1125,8 +1125,6 @@ static int sonypi_acpi_probe(struct platform_device *pdev)
return -ENODEV;
sonypi_acpi_device = device;
- strscpy(acpi_device_name(device), "Sony laptop hotkeys");
- strscpy(acpi_device_class(device), "sony/hotkey");
return 0;
}
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 6fd4aac1b6cf..00880d676296 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -166,6 +166,16 @@ config CLK_NORD_GCC
SPI, I2C, USB, SD/UFS, PCIe etc. The clock controller is a combination
of GCC, SE_GCC, NE_GCC and NW_GCC.
+config CLK_SHIKRA_GCC
+ tristate "Shikra Global Clock Controller"
+ depends on ARM64 || COMPILE_TEST
+ select QCOM_GDSC
+ default ARCH_QCOM
+ help
+ Support for the global clock controller on Shikra devices.
+ Say Y if you want to use multimedia devices or peripheral
+ devices such as Camera, Video, UART, SPI, I2C, USB, SD/eMMC etc.
+
config CLK_X1E80100_CAMCC
tristate "X1E80100 Camera Clock Controller"
depends on ARM64 || COMPILE_TEST
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index 81237e2c8db3..76946206d4aa 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_CLK_KAANAPALI_TCSRCC) += tcsrcc-kaanapali.o
obj-$(CONFIG_CLK_KAANAPALI_VIDEOCC) += videocc-kaanapali.o
obj-$(CONFIG_CLK_NORD_GCC) += gcc-nord.o negcc-nord.o nwgcc-nord.o segcc-nord.o
obj-$(CONFIG_CLK_NORD_TCSRCC) += tcsrcc-nord.o
+obj-$(CONFIG_CLK_SHIKRA_GCC) += gcc-shikra.o
obj-$(CONFIG_CLK_X1E80100_CAMCC) += camcc-x1e80100.o
obj-$(CONFIG_CLK_X1E80100_DISPCC) += dispcc-x1e80100.o
obj-$(CONFIG_CLK_X1E80100_GCC) += gcc-x1e80100.o
diff --git a/drivers/clk/qcom/clk-regmap-phy-mux.c b/drivers/clk/qcom/clk-regmap-phy-mux.c
index b7d1c69d62f7..7b7243b7107d 100644
--- a/drivers/clk/qcom/clk-regmap-phy-mux.c
+++ b/drivers/clk/qcom/clk-regmap-phy-mux.c
@@ -15,66 +15,48 @@
#define PHY_MUX_PHY_SRC 0
#define PHY_MUX_REF_SRC 2
-#define XO_RATE 19200000UL
-
static inline struct clk_regmap_phy_mux *to_clk_regmap_phy_mux(struct clk_regmap *clkr)
{
return container_of(clkr, struct clk_regmap_phy_mux, clkr);
}
-static unsigned long phy_mux_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+static int phy_mux_is_enabled(struct clk_hw *hw)
{
struct clk_regmap *clkr = to_clk_regmap(hw);
struct clk_regmap_phy_mux *phy_mux = to_clk_regmap_phy_mux(clkr);
- u32 val;
+ unsigned int val;
regmap_read(clkr->regmap, phy_mux->reg, &val);
+ val = FIELD_GET(PHY_MUX_MASK, val);
+
+ WARN_ON(val != PHY_MUX_PHY_SRC && val != PHY_MUX_REF_SRC);
- switch (FIELD_GET(PHY_MUX_MASK, val)) {
- case PHY_MUX_PHY_SRC:
- return ULONG_MAX;
- case PHY_MUX_REF_SRC:
- return XO_RATE;
- default:
- return 0;
- }
+ return val == PHY_MUX_PHY_SRC;
}
-static int phy_mux_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
+static int phy_mux_enable(struct clk_hw *hw)
{
- if (req->rate == XO_RATE || req->rate == ULONG_MAX)
- return 0;
+ struct clk_regmap *clkr = to_clk_regmap(hw);
+ struct clk_regmap_phy_mux *phy_mux = to_clk_regmap_phy_mux(clkr);
- return -EINVAL;
+ return regmap_update_bits(clkr->regmap, phy_mux->reg,
+ PHY_MUX_MASK,
+ FIELD_PREP(PHY_MUX_MASK, PHY_MUX_PHY_SRC));
}
-static int phy_mux_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate)
+static void phy_mux_disable(struct clk_hw *hw)
{
struct clk_regmap *clkr = to_clk_regmap(hw);
struct clk_regmap_phy_mux *phy_mux = to_clk_regmap_phy_mux(clkr);
- u32 val;
-
- switch (rate) {
- case XO_RATE:
- val = PHY_MUX_REF_SRC;
- break;
- case ULONG_MAX:
- val = PHY_MUX_PHY_SRC;
- break;
- default:
- return -EINVAL;
- }
regmap_update_bits(clkr->regmap, phy_mux->reg,
PHY_MUX_MASK,
- FIELD_PREP(PHY_MUX_MASK, val));
-
- return 0;
+ FIELD_PREP(PHY_MUX_MASK, PHY_MUX_REF_SRC));
}
const struct clk_ops clk_regmap_phy_mux_ops = {
- .recalc_rate = phy_mux_recalc_rate,
- .determine_rate = phy_mux_determine_rate,
- .set_rate = phy_mux_set_rate,
+ .enable = phy_mux_enable,
+ .disable = phy_mux_disable,
+ .is_enabled = phy_mux_is_enabled,
};
EXPORT_SYMBOL_GPL(clk_regmap_phy_mux_ops);
diff --git a/drivers/clk/qcom/clk-smd-rpm.c b/drivers/clk/qcom/clk-smd-rpm.c
index 103db984a40b..0b624ed4715c 100644
--- a/drivers/clk/qcom/clk-smd-rpm.c
+++ b/drivers/clk/qcom/clk-smd-rpm.c
@@ -495,6 +495,7 @@ DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(rf_clk2, 5, 19200000);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(rf_clk3, 6, 19200000);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(ln_bb_clk, 8, 19200000);
+DEFINE_CLK_SMD_RPM_XO_BUFFER_PREFIX(38m4_, rf_clk2, 5, 38400000);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PREFIX(38m4_, rf_clk3, 6, 38400000);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(cxo_d0, 1, 19200000);
@@ -1262,6 +1263,10 @@ static struct clk_smd_rpm *qcm2290_clks[] = {
[RPM_SMD_QDSS_A_CLK] = &clk_smd_rpm_branch_qdss_a_clk,
[RPM_SMD_LN_BB_CLK2] = &clk_smd_rpm_ln_bb_clk2,
[RPM_SMD_LN_BB_CLK2_A] = &clk_smd_rpm_ln_bb_clk2_a,
+ [RPM_SMD_RF_CLK1] = &clk_smd_rpm_rf_clk1,
+ [RPM_SMD_RF_CLK1_A] = &clk_smd_rpm_rf_clk1_a,
+ [RPM_SMD_RF_CLK2] = &clk_smd_rpm_38m4_rf_clk2,
+ [RPM_SMD_RF_CLK2_A] = &clk_smd_rpm_38m4_rf_clk2_a,
[RPM_SMD_RF_CLK3] = &clk_smd_rpm_38m4_rf_clk3,
[RPM_SMD_RF_CLK3_A] = &clk_smd_rpm_38m4_rf_clk3_a,
[RPM_SMD_IPA_CLK] = &clk_smd_rpm_ipa_clk,
diff --git a/drivers/clk/qcom/gcc-ipq5424.c b/drivers/clk/qcom/gcc-ipq5424.c
index 35af6ffeeb85..3ddd4b3aedea 100644
--- a/drivers/clk/qcom/gcc-ipq5424.c
+++ b/drivers/clk/qcom/gcc-ipq5424.c
@@ -139,17 +139,6 @@ static struct clk_alpha_pll gpll4 = {
.parent_data = &gcc_parent_data_xo,
.num_parents = 1,
.ops = &clk_alpha_pll_ops,
- /*
- * There are no consumers for this GPLL in kernel yet,
- * (will be added soon), so the clock framework
- * disables this source. But some of the clocks
- * initialized by boot loaders uses this source. So we
- * need to keep this clock ON. Add the
- * CLK_IGNORE_UNUSED flag so the clock will not be
- * disabled. Once the consumer in kernel is added, we
- * can get rid of this flag.
- */
- .flags = CLK_IGNORE_UNUSED,
},
},
};
diff --git a/drivers/clk/qcom/gcc-qcs8300.c b/drivers/clk/qcom/gcc-qcs8300.c
index 07218d9c96a7..31fd870b10f7 100644
--- a/drivers/clk/qcom/gcc-qcs8300.c
+++ b/drivers/clk/qcom/gcc-qcs8300.c
@@ -3267,7 +3267,7 @@ static struct gdsc gcc_pcie_0_gdsc = {
.pd = {
.name = "gcc_pcie_0_gdsc",
},
- .pwrsts = PWRSTS_OFF_ON,
+ .pwrsts = PWRSTS_RET_ON,
.flags = VOTABLE | RETAIN_FF_ENABLE | POLL_CFG_GDSCR,
};
@@ -3281,7 +3281,7 @@ static struct gdsc gcc_pcie_1_gdsc = {
.pd = {
.name = "gcc_pcie_1_gdsc",
},
- .pwrsts = PWRSTS_OFF_ON,
+ .pwrsts = PWRSTS_RET_ON,
.flags = VOTABLE | RETAIN_FF_ENABLE | POLL_CFG_GDSCR,
};
@@ -3305,7 +3305,7 @@ static struct gdsc gcc_usb20_prim_gdsc = {
.pd = {
.name = "gcc_usb20_prim_gdsc",
},
- .pwrsts = PWRSTS_OFF_ON,
+ .pwrsts = PWRSTS_RET_ON,
.flags = RETAIN_FF_ENABLE | POLL_CFG_GDSCR,
};
@@ -3317,7 +3317,7 @@ static struct gdsc gcc_usb30_prim_gdsc = {
.pd = {
.name = "gcc_usb30_prim_gdsc",
},
- .pwrsts = PWRSTS_OFF_ON,
+ .pwrsts = PWRSTS_RET_ON,
.flags = RETAIN_FF_ENABLE | POLL_CFG_GDSCR,
};
diff --git a/drivers/clk/qcom/gcc-shikra.c b/drivers/clk/qcom/gcc-shikra.c
new file mode 100644
index 000000000000..d5222756f214
--- /dev/null
+++ b/drivers/clk/qcom/gcc-shikra.c
@@ -0,0 +1,4431 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,shikra-gcc.h>
+
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "clk-pll.h"
+#include "clk-rcg.h"
+#include "clk-regmap.h"
+#include "clk-regmap-divider.h"
+#include "clk-regmap-mux.h"
+#include "clk-regmap-phy-mux.h"
+#include "common.h"
+#include "gdsc.h"
+#include "reset.h"
+
+enum {
+ DT_BI_TCXO,
+ DT_SLEEP_CLK,
+ DT_EMAC0_SGMIIPHY_RCLK,
+ DT_EMAC0_SGMIIPHY_TCLK,
+ DT_EMAC1_SGMIIPHY_RCLK,
+ DT_EMAC1_SGMIIPHY_TCLK,
+ DT_PCIE_PIPE_CLK,
+ DT_USB3_PHY_WRAPPER_GCC_USB30_PIPE_CLK,
+};
+
+enum {
+ P_BI_TCXO,
+ P_EMAC0_SGMIIPHY_RCLK,
+ P_EMAC0_SGMIIPHY_TCLK,
+ P_EMAC1_SGMIIPHY_RCLK,
+ P_EMAC1_SGMIIPHY_TCLK,
+ P_GPLL0_OUT_AUX2,
+ P_GPLL0_OUT_EARLY,
+ P_GPLL10_OUT_MAIN,
+ P_GPLL11_OUT_AUX,
+ P_GPLL11_OUT_AUX2,
+ P_GPLL11_OUT_MAIN,
+ P_GPLL12_OUT_AUX2,
+ P_GPLL12_OUT_EARLY,
+ P_GPLL3_OUT_EARLY,
+ P_GPLL3_OUT_MAIN,
+ P_GPLL4_OUT_MAIN,
+ P_GPLL5_OUT_MAIN,
+ P_GPLL6_OUT_EARLY,
+ P_GPLL6_OUT_MAIN,
+ P_GPLL7_OUT_MAIN,
+ P_GPLL8_OUT_EARLY,
+ P_GPLL8_OUT_MAIN,
+ P_GPLL9_OUT_EARLY,
+ P_GPLL9_OUT_MAIN,
+ P_PCIE_PIPE_CLK,
+ P_SLEEP_CLK,
+ P_USB3_PHY_WRAPPER_GCC_USB30_PIPE_CLK,
+};
+
+static const struct pll_vco brammo_vco[] = {
+ { 500000000, 1250000000, 0 },
+};
+
+static const struct pll_vco default_vco[] = {
+ { 500000000, 1000000000, 2 },
+};
+
+static const struct pll_vco spark_vco[] = {
+ { 750000000, 1500000000, 1 },
+};
+
+static struct clk_alpha_pll gpll0 = {
+ .offset = 0x0,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT_EVO],
+ .clkr = {
+ .enable_reg = 0x79000,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gpll0",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_gpll0_out_aux2[] = {
+ { 0x1, 2 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv gpll0_out_aux2 = {
+ .offset = 0x0,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_gpll0_out_aux2,
+ .num_post_div = ARRAY_SIZE(post_div_table_gpll0_out_aux2),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT_EVO],
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gpll0_out_aux2",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gpll0.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_ro_ops,
+ },
+};
+
+/* 1152.0 MHz Configuration */
+static const struct alpha_pll_config gpll10_config = {
+ .l = 0x3c,
+ .alpha = 0x0,
+ .vco_val = BIT(20),
+ .vco_mask = GENMASK(21, 20),
+ .main_output_mask = BIT(0),
+ .config_ctl_val = 0x4001055b,
+ .test_ctl_hi1_val = 0x1,
+};
+
+static struct clk_alpha_pll gpll10 = {
+ .offset = 0xa000,
+ .config = &gpll10_config,
+ .vco_table = spark_vco,
+ .num_vco = ARRAY_SIZE(spark_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT_EVO],
+ .clkr = {
+ .enable_reg = 0x79000,
+ .enable_mask = BIT(10),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gpll10",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ },
+ },
+};
+
+/* 600.0 MHz Configuration */
+static const struct alpha_pll_config gpll11_config = {
+ .l = 0x1f,
+ .alpha = 0x0,
+ .alpha_hi = 0x40,
+ .alpha_en_mask = BIT(24),
+ .vco_val = BIT(21),
+ .vco_mask = GENMASK(21, 20),
+ .main_output_mask = BIT(0),
+ .config_ctl_val = 0x4001055b,
+ .test_ctl_hi1_val = 0x1,
+};
+
+static struct clk_alpha_pll gpll11 = {
+ .offset = 0xb000,
+ .config = &gpll11_config,
+ .vco_table = default_vco,
+ .num_vco = ARRAY_SIZE(default_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT_EVO],
+ .flags = SUPPORTS_DYNAMIC_UPDATE,
+ .clkr = {
+ .enable_reg = 0x79000,
+ .enable_mask = BIT(11),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gpll11",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll gpll12 = {
+ .offset = 0xc000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT_EVO],
+ .clkr = {
+ .enable_reg = 0x79000,
+ .enable_mask = BIT(12),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gpll12",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_gpll12_out_aux2[] = {
+ { 0x1, 2 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv gpll12_out_aux2 = {
+ .offset = 0xc000,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_gpll12_out_aux2,
+ .num_post_div = ARRAY_SIZE(post_div_table_gpll12_out_aux2),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT_EVO],
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gpll12_out_aux2",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gpll12.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_ro_ops,
+ },
+};
+
+static struct clk_alpha_pll gpll3 = {
+ .offset = 0x3000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT_EVO],
+ .clkr = {
+ .enable_reg = 0x79000,
+ .enable_mask = BIT(3),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gpll3",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_gpll3_out_main[] = {
+ { 0x1, 2 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv gpll3_out_main = {
+ .offset = 0x3000,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_gpll3_out_main,
+ .num_post_div = ARRAY_SIZE(post_div_table_gpll3_out_main),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT_EVO],
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gpll3_out_main",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gpll3.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_ro_ops,
+ },
+};
+
+static struct clk_alpha_pll gpll4 = {
+ .offset = 0x4000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT_EVO],
+ .clkr = {
+ .enable_reg = 0x79000,
+ .enable_mask = BIT(4),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gpll4",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll gpll5 = {
+ .offset = 0x5000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT_EVO],
+ .clkr = {
+ .enable_reg = 0x79000,
+ .enable_mask = BIT(5),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gpll5",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll gpll6 = {
+ .offset = 0x6000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT_EVO],
+ .clkr = {
+ .enable_reg = 0x79000,
+ .enable_mask = BIT(6),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gpll6",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_gpll6_out_main[] = {
+ { 0x1, 2 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv gpll6_out_main = {
+ .offset = 0x6000,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_gpll6_out_main,
+ .num_post_div = ARRAY_SIZE(post_div_table_gpll6_out_main),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT_EVO],
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gpll6_out_main",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gpll6.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_ro_ops,
+ },
+};
+
+static struct clk_alpha_pll gpll7 = {
+ .offset = 0x7000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT_EVO],
+ .clkr = {
+ .enable_reg = 0x79000,
+ .enable_mask = BIT(7),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gpll7",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_ops,
+ },
+ },
+};
+
+/* 533.2 MHz Configuration */
+static const struct alpha_pll_config gpll8_config = {
+ .l = 0x1b,
+ .alpha = 0x55555555,
+ .alpha_hi = 0xc5,
+ .alpha_en_mask = BIT(24),
+ .vco_val = BIT(21),
+ .vco_mask = GENMASK(21, 20),
+ .main_output_mask = BIT(0),
+ .early_output_mask = BIT(3),
+ .post_div_val = BIT(8),
+ .post_div_mask = GENMASK(11, 8),
+ .config_ctl_val = 0x4001055b,
+ .test_ctl_hi1_val = 0x1,
+};
+
+static struct clk_alpha_pll gpll8 = {
+ .offset = 0x8000,
+ .config = &gpll8_config,
+ .vco_table = default_vco,
+ .num_vco = ARRAY_SIZE(default_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT_EVO],
+ .flags = SUPPORTS_DYNAMIC_UPDATE,
+ .clkr = {
+ .enable_reg = 0x79000,
+ .enable_mask = BIT(8),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gpll8",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_gpll8_out_main[] = {
+ { 0x1, 2 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv gpll8_out_main = {
+ .offset = 0x8000,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_gpll8_out_main,
+ .num_post_div = ARRAY_SIZE(post_div_table_gpll8_out_main),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT_EVO],
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gpll8_out_main",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gpll8.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_ro_ops,
+ },
+};
+
+/* 1152.0 MHz Configuration */
+static const struct alpha_pll_config gpll9_config = {
+ .l = 0x3c,
+ .alpha = 0x0,
+ .post_div_val = BIT(8),
+ .post_div_mask = GENMASK(9, 8),
+ .main_output_mask = BIT(0),
+ .early_output_mask = BIT(3),
+ .config_ctl_val = 0x00004289,
+ .test_ctl_val = 0x08000000,
+};
+
+static struct clk_alpha_pll gpll9 = {
+ .offset = 0x9000,
+ .config = &gpll9_config,
+ .vco_table = brammo_vco,
+ .num_vco = ARRAY_SIZE(brammo_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_BRAMMO_EVO],
+ .clkr = {
+ .enable_reg = 0x79000,
+ .enable_mask = BIT(9),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gpll9",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_gpll9_out_main[] = {
+ { 0x1, 2 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv gpll9_out_main = {
+ .offset = 0x9000,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_gpll9_out_main,
+ .num_post_div = ARRAY_SIZE(post_div_table_gpll9_out_main),
+ .width = 2,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_BRAMMO_EVO],
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gpll9_out_main",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gpll9.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_ro_ops,
+ },
+};
+
+static const struct parent_map gcc_parent_map_0[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL0_OUT_AUX2, 2 },
+};
+
+static const struct clk_parent_data gcc_parent_data_0[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gpll0.clkr.hw },
+ { .hw = &gpll0_out_aux2.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_1[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL0_OUT_AUX2, 2 },
+ { P_GPLL6_OUT_MAIN, 4 },
+};
+
+static const struct clk_parent_data gcc_parent_data_1[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gpll0.clkr.hw },
+ { .hw = &gpll0_out_aux2.clkr.hw },
+ { .hw = &gpll6_out_main.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_2[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL0_OUT_AUX2, 2 },
+ { P_SLEEP_CLK, 5 },
+};
+
+static const struct clk_parent_data gcc_parent_data_2[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gpll0.clkr.hw },
+ { .hw = &gpll0_out_aux2.clkr.hw },
+ { .index = DT_SLEEP_CLK },
+};
+
+static const struct parent_map gcc_parent_map_3[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL9_OUT_EARLY, 2 },
+ { P_GPLL10_OUT_MAIN, 3 },
+ { P_GPLL9_OUT_MAIN, 5 },
+ { P_GPLL3_OUT_MAIN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_3[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gpll0.clkr.hw },
+ { .hw = &gpll9.clkr.hw },
+ { .hw = &gpll10.clkr.hw },
+ { .hw = &gpll9_out_main.clkr.hw },
+ { .hw = &gpll3_out_main.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_4[] = {
+ { P_BI_TCXO, 0 },
+ { P_SLEEP_CLK, 5 },
+};
+
+static const struct clk_parent_data gcc_parent_data_4[] = {
+ { .index = DT_BI_TCXO },
+ { .index = DT_SLEEP_CLK },
+};
+
+static const struct parent_map gcc_parent_map_5[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL0_OUT_AUX2, 2 },
+ { P_GPLL10_OUT_MAIN, 3 },
+ { P_GPLL4_OUT_MAIN, 5 },
+ { P_GPLL3_OUT_EARLY, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_5[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gpll0.clkr.hw },
+ { .hw = &gpll0_out_aux2.clkr.hw },
+ { .hw = &gpll10.clkr.hw },
+ { .hw = &gpll4.clkr.hw },
+ { .hw = &gpll3.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_6[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL0_OUT_AUX2, 2 },
+ { P_GPLL4_OUT_MAIN, 5 },
+ { P_GPLL3_OUT_MAIN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_6[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gpll0.clkr.hw },
+ { .hw = &gpll0_out_aux2.clkr.hw },
+ { .hw = &gpll4.clkr.hw },
+ { .hw = &gpll3_out_main.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_7[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL8_OUT_EARLY, 2 },
+ { P_GPLL10_OUT_MAIN, 3 },
+ { P_GPLL8_OUT_MAIN, 4 },
+ { P_GPLL9_OUT_MAIN, 5 },
+ { P_GPLL3_OUT_EARLY, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_7[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gpll0.clkr.hw },
+ { .hw = &gpll8.clkr.hw },
+ { .hw = &gpll10.clkr.hw },
+ { .hw = &gpll8_out_main.clkr.hw },
+ { .hw = &gpll9.clkr.hw },
+ { .hw = &gpll3.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_8[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL8_OUT_EARLY, 2 },
+ { P_GPLL10_OUT_MAIN, 3 },
+ { P_GPLL8_OUT_MAIN, 4 },
+ { P_GPLL9_OUT_MAIN, 5 },
+ { P_GPLL3_OUT_MAIN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_8[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gpll0.clkr.hw },
+ { .hw = &gpll8.clkr.hw },
+ { .hw = &gpll10.clkr.hw },
+ { .hw = &gpll8_out_main.clkr.hw },
+ { .hw = &gpll9.clkr.hw },
+ { .hw = &gpll3_out_main.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_9[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL8_OUT_EARLY, 2 },
+ { P_GPLL10_OUT_MAIN, 3 },
+ { P_GPLL6_OUT_MAIN, 4 },
+ { P_GPLL9_OUT_MAIN, 5 },
+ { P_GPLL3_OUT_EARLY, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_9[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gpll0.clkr.hw },
+ { .hw = &gpll8.clkr.hw },
+ { .hw = &gpll10.clkr.hw },
+ { .hw = &gpll6_out_main.clkr.hw },
+ { .hw = &gpll9.clkr.hw },
+ { .hw = &gpll3.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_10[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_SLEEP_CLK, 5 },
+};
+
+static const struct clk_parent_data gcc_parent_data_10[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gpll0.clkr.hw },
+ { .index = DT_SLEEP_CLK },
+};
+
+static const struct parent_map gcc_parent_map_11[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL12_OUT_EARLY, 1 },
+ { P_GPLL12_OUT_AUX2, 4 },
+ { P_GPLL3_OUT_EARLY, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_11[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gpll12.clkr.hw },
+ { .hw = &gpll12_out_aux2.clkr.hw },
+ { .hw = &gpll3.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_12[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL12_OUT_EARLY, 1 },
+ { P_GPLL0_OUT_AUX2, 2 },
+ { P_GPLL12_OUT_AUX2, 4 },
+};
+
+static const struct clk_parent_data gcc_parent_data_12[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gpll12.clkr.hw },
+ { .hw = &gpll0_out_aux2.clkr.hw },
+ { .hw = &gpll12_out_aux2.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_13[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+};
+
+static const struct clk_parent_data gcc_parent_data_13[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gpll0.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_14[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL0_OUT_AUX2, 2 },
+ { P_GPLL10_OUT_MAIN, 3 },
+ { P_GPLL8_OUT_MAIN, 4 },
+ { P_GPLL9_OUT_MAIN, 5 },
+ { P_GPLL3_OUT_EARLY, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_14[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gpll0.clkr.hw },
+ { .hw = &gpll0_out_aux2.clkr.hw },
+ { .hw = &gpll10.clkr.hw },
+ { .hw = &gpll8_out_main.clkr.hw },
+ { .hw = &gpll9.clkr.hw },
+ { .hw = &gpll3.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_15[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL8_OUT_EARLY, 2 },
+ { P_GPLL10_OUT_MAIN, 3 },
+ { P_GPLL6_OUT_EARLY, 5 },
+ { P_GPLL3_OUT_MAIN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_15[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gpll0.clkr.hw },
+ { .hw = &gpll8.clkr.hw },
+ { .hw = &gpll10.clkr.hw },
+ { .hw = &gpll6.clkr.hw },
+ { .hw = &gpll3_out_main.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_21[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL0_OUT_AUX2, 2 },
+ { P_GPLL7_OUT_MAIN, 3 },
+ { P_GPLL4_OUT_MAIN, 5 },
+};
+
+static const struct clk_parent_data gcc_parent_data_21[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gpll0.clkr.hw },
+ { .hw = &gpll0_out_aux2.clkr.hw },
+ { .hw = &gpll7.clkr.hw },
+ { .hw = &gpll4.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_22[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL12_OUT_EARLY, 1 },
+ { P_GPLL5_OUT_MAIN, 3 },
+ { P_GPLL12_OUT_AUX2, 4 },
+ { P_GPLL3_OUT_EARLY, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_22[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gpll12.clkr.hw },
+ { .hw = &gpll5.clkr.hw },
+ { .hw = &gpll12_out_aux2.clkr.hw },
+ { .hw = &gpll3.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_24[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL11_OUT_MAIN, 1 },
+ { P_GPLL11_OUT_AUX, 2 },
+ { P_GPLL11_OUT_AUX2, 3 },
+};
+
+static const struct clk_parent_data gcc_parent_data_24[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gpll11.clkr.hw },
+ { .hw = &gpll11.clkr.hw },
+ { .hw = &gpll11.clkr.hw },
+};
+
+static struct clk_regmap_phy_mux gcc_emac0_cc_sgmiiphy_rx_clk_src = {
+ .reg = 0xad048,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_emac0_cc_sgmiiphy_rx_clk_src",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_EMAC0_SGMIIPHY_RCLK,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_phy_mux_ops,
+ },
+ },
+};
+
+static struct clk_regmap_phy_mux gcc_emac0_cc_sgmiiphy_tx_clk_src = {
+ .reg = 0xad040,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_emac0_cc_sgmiiphy_tx_clk_src",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_EMAC0_SGMIIPHY_TCLK,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_phy_mux_ops,
+ },
+ },
+};
+
+static struct clk_regmap_phy_mux gcc_emac1_cc_sgmiiphy_rx_clk_src = {
+ .reg = 0xae048,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_emac1_cc_sgmiiphy_rx_clk_src",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_EMAC1_SGMIIPHY_RCLK,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_phy_mux_ops,
+ },
+ },
+};
+
+static struct clk_regmap_phy_mux gcc_emac1_cc_sgmiiphy_tx_clk_src = {
+ .reg = 0xae040,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_emac1_cc_sgmiiphy_tx_clk_src",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_EMAC1_SGMIIPHY_TCLK,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_phy_mux_ops,
+ },
+ },
+};
+
+static struct clk_regmap_phy_mux gcc_pcie_pipe_clk_src = {
+ .reg = 0xaf058,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_pipe_clk_src",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_PCIE_PIPE_CLK,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_phy_mux_ops,
+ },
+ },
+};
+
+static struct clk_regmap_phy_mux gcc_usb3_prim_phy_pipe_clk_src = {
+ .reg = 0x1a05c,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_prim_phy_pipe_clk_src",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_USB3_PHY_WRAPPER_GCC_USB30_PIPE_CLK,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_phy_mux_ops,
+ },
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_camss_axi_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(150000000, P_GPLL0_OUT_AUX2, 2, 0, 0),
+ F(200000000, P_GPLL0_OUT_AUX2, 1.5, 0, 0),
+ F(300000000, P_GPLL0_OUT_AUX2, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_camss_axi_clk_src = {
+ .cmd_rcgr = 0x5802c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_5,
+ .freq_tbl = ftbl_gcc_camss_axi_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_axi_clk_src",
+ .parent_data = gcc_parent_data_5,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_5),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_camss_cci_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(37500000, P_GPLL0_OUT_AUX2, 8, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_camss_cci_clk_src = {
+ .cmd_rcgr = 0x56000,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_14,
+ .freq_tbl = ftbl_gcc_camss_cci_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_cci_clk_src",
+ .parent_data = gcc_parent_data_14,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_14),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_camss_csi0phytimer_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(100000000, P_GPLL0_OUT_AUX2, 3, 0, 0),
+ F(200000000, P_GPLL0_OUT_AUX2, 1.5, 0, 0),
+ F(268800000, P_GPLL4_OUT_MAIN, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_camss_csi0phytimer_clk_src = {
+ .cmd_rcgr = 0x45000,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_6,
+ .freq_tbl = ftbl_gcc_camss_csi0phytimer_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_csi0phytimer_clk_src",
+ .parent_data = gcc_parent_data_6,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_6),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_camss_csi1phytimer_clk_src = {
+ .cmd_rcgr = 0x4501c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_6,
+ .freq_tbl = ftbl_gcc_camss_csi0phytimer_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_csi1phytimer_clk_src",
+ .parent_data = gcc_parent_data_6,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_6),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_camss_mclk0_clk_src[] = {
+ F(19200000, P_GPLL9_OUT_EARLY, 1, 1, 60),
+ F(24000000, P_GPLL9_OUT_MAIN, 1, 1, 24),
+ F(64000000, P_GPLL9_OUT_EARLY, 9, 1, 2),
+ { }
+};
+
+static struct clk_rcg2 gcc_camss_mclk0_clk_src = {
+ .cmd_rcgr = 0x51000,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_3,
+ .freq_tbl = ftbl_gcc_camss_mclk0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_mclk0_clk_src",
+ .parent_data = gcc_parent_data_3,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_3),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_camss_mclk1_clk_src = {
+ .cmd_rcgr = 0x5101c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_3,
+ .freq_tbl = ftbl_gcc_camss_mclk0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_mclk1_clk_src",
+ .parent_data = gcc_parent_data_3,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_3),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_camss_mclk2_clk_src = {
+ .cmd_rcgr = 0x51038,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_3,
+ .freq_tbl = ftbl_gcc_camss_mclk0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_mclk2_clk_src",
+ .parent_data = gcc_parent_data_3,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_3),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_camss_mclk3_clk_src = {
+ .cmd_rcgr = 0x51054,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_3,
+ .freq_tbl = ftbl_gcc_camss_mclk0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_mclk3_clk_src",
+ .parent_data = gcc_parent_data_3,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_3),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_camss_ope_ahb_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(171428571, P_GPLL0_OUT_EARLY, 3.5, 0, 0),
+ F(240000000, P_GPLL0_OUT_EARLY, 2.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_camss_ope_ahb_clk_src = {
+ .cmd_rcgr = 0x55024,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_7,
+ .freq_tbl = ftbl_gcc_camss_ope_ahb_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_ope_ahb_clk_src",
+ .parent_data = gcc_parent_data_7,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_7),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_camss_ope_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(200000000, P_GPLL8_OUT_MAIN, 2, 0, 0),
+ F(266600000, P_GPLL8_OUT_MAIN, 1, 0, 0),
+ F(465000000, P_GPLL8_OUT_MAIN, 1, 0, 0),
+ F(580000000, P_GPLL8_OUT_EARLY, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_camss_ope_clk_src = {
+ .cmd_rcgr = 0x55004,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_7,
+ .freq_tbl = ftbl_gcc_camss_ope_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_ope_clk_src",
+ .parent_data = gcc_parent_data_7,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_7),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_camss_tfe_0_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(128000000, P_GPLL10_OUT_MAIN, 9, 0, 0),
+ F(135529412, P_GPLL10_OUT_MAIN, 8.5, 0, 0),
+ F(144000000, P_GPLL10_OUT_MAIN, 8, 0, 0),
+ F(153600000, P_GPLL10_OUT_MAIN, 7.5, 0, 0),
+ F(164571429, P_GPLL10_OUT_MAIN, 7, 0, 0),
+ F(177230769, P_GPLL10_OUT_MAIN, 6.5, 0, 0),
+ F(192000000, P_GPLL10_OUT_MAIN, 6, 0, 0),
+ F(209454545, P_GPLL10_OUT_MAIN, 5.5, 0, 0),
+ F(230400000, P_GPLL10_OUT_MAIN, 5, 0, 0),
+ F(256000000, P_GPLL10_OUT_MAIN, 4.5, 0, 0),
+ F(288000000, P_GPLL10_OUT_MAIN, 4, 0, 0),
+ F(329142857, P_GPLL10_OUT_MAIN, 3.5, 0, 0),
+ F(384000000, P_GPLL10_OUT_MAIN, 3, 0, 0),
+ F(460800000, P_GPLL10_OUT_MAIN, 2.5, 0, 0),
+ F(576000000, P_GPLL10_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_camss_tfe_0_clk_src = {
+ .cmd_rcgr = 0x52004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_8,
+ .freq_tbl = ftbl_gcc_camss_tfe_0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_tfe_0_clk_src",
+ .parent_data = gcc_parent_data_8,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_8),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_camss_tfe_0_csid_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(120000000, P_GPLL0_OUT_EARLY, 5, 0, 0),
+ F(192000000, P_GPLL6_OUT_MAIN, 2, 0, 0),
+ F(240000000, P_GPLL0_OUT_EARLY, 2.5, 0, 0),
+ F(384000000, P_GPLL6_OUT_MAIN, 1, 0, 0),
+ F(426400000, P_GPLL3_OUT_EARLY, 2.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_camss_tfe_0_csid_clk_src = {
+ .cmd_rcgr = 0x52094,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_9,
+ .freq_tbl = ftbl_gcc_camss_tfe_0_csid_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_tfe_0_csid_clk_src",
+ .parent_data = gcc_parent_data_9,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_9),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_camss_tfe_1_clk_src = {
+ .cmd_rcgr = 0x52024,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_8,
+ .freq_tbl = ftbl_gcc_camss_tfe_0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_tfe_1_clk_src",
+ .parent_data = gcc_parent_data_8,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_8),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_camss_tfe_1_csid_clk_src = {
+ .cmd_rcgr = 0x520b4,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_9,
+ .freq_tbl = ftbl_gcc_camss_tfe_0_csid_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_tfe_1_csid_clk_src",
+ .parent_data = gcc_parent_data_9,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_9),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_camss_tfe_cphy_rx_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(240000000, P_GPLL0_OUT_EARLY, 2.5, 0, 0),
+ F(341333333, P_GPLL6_OUT_EARLY, 1, 4, 9),
+ F(384000000, P_GPLL6_OUT_EARLY, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_camss_tfe_cphy_rx_clk_src = {
+ .cmd_rcgr = 0x52064,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_15,
+ .freq_tbl = ftbl_gcc_camss_tfe_cphy_rx_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_tfe_cphy_rx_clk_src",
+ .parent_data = gcc_parent_data_15,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_15),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_camss_top_ahb_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(40000000, P_GPLL0_OUT_AUX2, 7.5, 0, 0),
+ F(80000000, P_GPLL0_OUT_EARLY, 7.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_camss_top_ahb_clk_src = {
+ .cmd_rcgr = 0x58010,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_5,
+ .freq_tbl = ftbl_gcc_camss_top_ahb_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_top_ahb_clk_src",
+ .parent_data = gcc_parent_data_5,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_5),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_emac0_axi_clk_src[] = {
+ F(75000000, P_GPLL0_OUT_AUX2, 4, 0, 0),
+ F(120000000, P_GPLL0_OUT_AUX2, 2.5, 0, 0),
+ F(150000000, P_GPLL0_OUT_AUX2, 2, 0, 0),
+ F(200000000, P_GPLL0_OUT_AUX2, 1.5, 0, 0),
+ F(240000000, P_GPLL0_OUT_EARLY, 2.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_emac0_axi_clk_src = {
+ .cmd_rcgr = 0x109dc,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_emac0_axi_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_emac0_axi_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_emac0_phy_aux_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_emac0_phy_aux_clk_src = {
+ .cmd_rcgr = 0xad01c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_10,
+ .freq_tbl = ftbl_gcc_emac0_phy_aux_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_emac0_phy_aux_clk_src",
+ .parent_data = gcc_parent_data_10,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_10),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_emac0_ptp_clk_src[] = {
+ F(250000000, P_GPLL12_OUT_AUX2, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_emac0_ptp_clk_src = {
+ .cmd_rcgr = 0xad064,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_11,
+ .freq_tbl = ftbl_gcc_emac0_ptp_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_emac0_ptp_clk_src",
+ .parent_data = gcc_parent_data_11,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_11),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_emac0_rgmii_clk_src[] = {
+ F(50000000, P_GPLL0_OUT_AUX2, 6, 0, 0),
+ F(125000000, P_GPLL12_OUT_AUX2, 4, 0, 0),
+ F(250000000, P_GPLL12_OUT_EARLY, 4, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_emac0_rgmii_clk_src = {
+ .cmd_rcgr = 0xad04c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_12,
+ .freq_tbl = ftbl_gcc_emac0_rgmii_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_emac0_rgmii_clk_src",
+ .parent_data = gcc_parent_data_12,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_12),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_emac1_axi_clk_src = {
+ .cmd_rcgr = 0x109fc,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_emac0_axi_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_emac1_axi_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_emac1_phy_aux_clk_src = {
+ .cmd_rcgr = 0xae01c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_10,
+ .freq_tbl = ftbl_gcc_emac0_phy_aux_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_emac1_phy_aux_clk_src",
+ .parent_data = gcc_parent_data_10,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_10),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_emac1_ptp_clk_src = {
+ .cmd_rcgr = 0xae064,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_11,
+ .freq_tbl = ftbl_gcc_emac0_ptp_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_emac1_ptp_clk_src",
+ .parent_data = gcc_parent_data_11,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_11),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_emac1_rgmii_clk_src = {
+ .cmd_rcgr = 0xae04c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_12,
+ .freq_tbl = ftbl_gcc_emac0_rgmii_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_emac1_rgmii_clk_src",
+ .parent_data = gcc_parent_data_12,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_12),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_gp1_clk_src[] = {
+ F(25000000, P_GPLL0_OUT_AUX2, 12, 0, 0),
+ F(50000000, P_GPLL0_OUT_AUX2, 6, 0, 0),
+ F(100000000, P_GPLL0_OUT_AUX2, 3, 0, 0),
+ F(200000000, P_GPLL0_OUT_AUX2, 1.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_gp1_clk_src = {
+ .cmd_rcgr = 0x4d004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_2,
+ .freq_tbl = ftbl_gcc_gp1_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gp1_clk_src",
+ .parent_data = gcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_2),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_gp2_clk_src = {
+ .cmd_rcgr = 0x4e004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_2,
+ .freq_tbl = ftbl_gcc_gp1_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gp2_clk_src",
+ .parent_data = gcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_2),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_gp3_clk_src = {
+ .cmd_rcgr = 0x4f004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_2,
+ .freq_tbl = ftbl_gcc_gp1_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gp3_clk_src",
+ .parent_data = gcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_2),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie_aux_clk_src = {
+ .cmd_rcgr = 0xaf074,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_4,
+ .freq_tbl = ftbl_gcc_emac0_phy_aux_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_aux_clk_src",
+ .parent_data = gcc_parent_data_4,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_4),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie_aux_phy_clk_src = {
+ .cmd_rcgr = 0xaf05c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_4,
+ .freq_tbl = ftbl_gcc_emac0_phy_aux_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_aux_phy_clk_src",
+ .parent_data = gcc_parent_data_4,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_4),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_pcie_rchng_phy_clk_src[] = {
+ F(100000000, P_GPLL0_OUT_AUX2, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_pcie_rchng_phy_clk_src = {
+ .cmd_rcgr = 0xaf028,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_rchng_phy_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_rchng_phy_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_pdm2_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(60000000, P_GPLL0_OUT_AUX2, 5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_pdm2_clk_src = {
+ .cmd_rcgr = 0x20010,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pdm2_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pdm2_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = {
+ F(7372800, P_GPLL0_OUT_AUX2, 1, 384, 15625),
+ F(14745600, P_GPLL0_OUT_AUX2, 1, 768, 15625),
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(29491200, P_GPLL0_OUT_AUX2, 1, 1536, 15625),
+ F(32000000, P_GPLL0_OUT_AUX2, 1, 8, 75),
+ F(48000000, P_GPLL0_OUT_AUX2, 1, 4, 25),
+ F(64000000, P_GPLL0_OUT_AUX2, 1, 16, 75),
+ F(75000000, P_GPLL0_OUT_AUX2, 4, 0, 0),
+ F(80000000, P_GPLL0_OUT_AUX2, 1, 4, 15),
+ F(96000000, P_GPLL0_OUT_AUX2, 1, 8, 25),
+ F(100000000, P_GPLL0_OUT_AUX2, 3, 0, 0),
+ F(102400000, P_GPLL0_OUT_AUX2, 1, 128, 375),
+ F(112000000, P_GPLL0_OUT_AUX2, 1, 28, 75),
+ F(117964800, P_GPLL0_OUT_AUX2, 1, 6144, 15625),
+ F(120000000, P_GPLL0_OUT_AUX2, 2.5, 0, 0),
+ F(128000000, P_GPLL6_OUT_MAIN, 3, 0, 0),
+ { }
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s0_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s0_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s0_clk_src = {
+ .cmd_rcgr = 0x1f148,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s0_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s1_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s1_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s1_clk_src = {
+ .cmd_rcgr = 0x1f278,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s1_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s2_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s2_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s2_clk_src = {
+ .cmd_rcgr = 0x1f3a8,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s2_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s3_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s3_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s3_clk_src = {
+ .cmd_rcgr = 0x1f4d8,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s3_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s4_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s4_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s4_clk_src = {
+ .cmd_rcgr = 0x1f608,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s4_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s5_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s5_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s5_clk_src = {
+ .cmd_rcgr = 0x1f738,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s5_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s6_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s6_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s6_clk_src = {
+ .cmd_rcgr = 0x1f868,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s6_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s7_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s7_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s7_clk_src = {
+ .cmd_rcgr = 0x1f998,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s7_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s8_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s8_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s8_clk_src = {
+ .cmd_rcgr = 0x1fac8,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s8_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s9_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s9_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s9_clk_src = {
+ .cmd_rcgr = 0x1fbf8,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s9_clk_src_init,
+};
+
+static const struct freq_tbl ftbl_gcc_sdcc1_apps_clk_src[] = {
+ F(144000, P_BI_TCXO, 16, 3, 25),
+ F(400000, P_BI_TCXO, 12, 1, 4),
+ F(20000000, P_GPLL0_OUT_AUX2, 5, 1, 3),
+ F(25000000, P_GPLL0_OUT_AUX2, 6, 1, 2),
+ F(50000000, P_GPLL0_OUT_AUX2, 6, 0, 0),
+ F(100000000, P_GPLL0_OUT_AUX2, 3, 0, 0),
+ F(192000000, P_GPLL6_OUT_MAIN, 2, 0, 0),
+ F(384000000, P_GPLL6_OUT_MAIN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_sdcc1_apps_clk_src = {
+ .cmd_rcgr = 0x38028,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_sdcc1_apps_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc1_apps_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_shared_floor_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_sdcc1_ice_core_clk_src[] = {
+ F(75000000, P_GPLL0_OUT_AUX2, 4, 0, 0),
+ F(100000000, P_GPLL0_OUT_AUX2, 3, 0, 0),
+ F(150000000, P_GPLL0_OUT_AUX2, 2, 0, 0),
+ F(200000000, P_GPLL0_OUT_EARLY, 3, 0, 0),
+ F(300000000, P_GPLL0_OUT_AUX2, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_sdcc1_ice_core_clk_src = {
+ .cmd_rcgr = 0x38010,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_sdcc1_ice_core_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc1_ice_core_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_shared_floor_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = {
+ F(400000, P_BI_TCXO, 12, 1, 4),
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(25000000, P_GPLL0_OUT_AUX2, 12, 0, 0),
+ F(50000000, P_GPLL0_OUT_AUX2, 6, 0, 0),
+ F(100000000, P_GPLL0_OUT_AUX2, 3, 0, 0),
+ F(202000000, P_GPLL7_OUT_MAIN, 4, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_sdcc2_apps_clk_src = {
+ .cmd_rcgr = 0x1e00c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_21,
+ .freq_tbl = ftbl_gcc_sdcc2_apps_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc2_apps_clk_src",
+ .parent_data = gcc_parent_data_21,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_21),
+ .ops = &clk_rcg2_shared_floor_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_tscss_clk_src = {
+ .cmd_rcgr = 0xac004,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_22,
+ .freq_tbl = ftbl_gcc_emac0_ptp_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_tscss_clk_src",
+ .parent_data = gcc_parent_data_22,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_22),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_usb20_master_clk_src[] = {
+ F(60000000, P_GPLL0_OUT_AUX2, 5, 0, 0),
+ F(120000000, P_GPLL0_OUT_EARLY, 5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_usb20_master_clk_src = {
+ .cmd_rcgr = 0xb003c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_usb20_master_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb20_master_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb20_mock_utmi_clk_src = {
+ .cmd_rcgr = 0xb0020,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_13,
+ .freq_tbl = ftbl_gcc_emac0_phy_aux_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb20_mock_utmi_clk_src",
+ .parent_data = gcc_parent_data_13,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_13),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_usb30_prim_master_clk_src[] = {
+ F(66666667, P_GPLL0_OUT_AUX2, 4.5, 0, 0),
+ F(133333333, P_GPLL0_OUT_EARLY, 4.5, 0, 0),
+ F(200000000, P_GPLL0_OUT_EARLY, 3, 0, 0),
+ F(240000000, P_GPLL0_OUT_EARLY, 2.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_usb30_prim_master_clk_src = {
+ .cmd_rcgr = 0x1a01c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_usb30_prim_master_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_prim_master_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb30_prim_mock_utmi_clk_src = {
+ .cmd_rcgr = 0x1a034,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_emac0_phy_aux_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_prim_mock_utmi_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb3_prim_phy_aux_clk_src = {
+ .cmd_rcgr = 0x1a060,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_4,
+ .freq_tbl = ftbl_gcc_emac0_phy_aux_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_prim_phy_aux_clk_src",
+ .parent_data = gcc_parent_data_4,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_4),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_video_venus_clk_src[] = {
+ F(133333333, P_GPLL11_OUT_MAIN, 4.5, 0, 0),
+ F(240000000, P_GPLL11_OUT_MAIN, 2.5, 0, 0),
+ F(300000000, P_GPLL11_OUT_MAIN, 2, 0, 0),
+ F(384000000, P_GPLL11_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_video_venus_clk_src = {
+ .cmd_rcgr = 0x6d000,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_24,
+ .freq_tbl = ftbl_gcc_video_venus_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_video_venus_clk_src",
+ .parent_data = gcc_parent_data_24,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_24),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_regmap_div gcc_disp_gpll0_clk_src = {
+ .reg = 0x17058,
+ .shift = 0,
+ .width = 2,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_disp_gpll0_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gpll0.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_div_ops,
+ },
+};
+
+static struct clk_regmap_div gcc_usb20_mock_utmi_postdiv_clk_src = {
+ .reg = 0xb0038,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb20_mock_utmi_postdiv_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb20_mock_utmi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div gcc_usb30_prim_mock_utmi_postdiv_clk_src = {
+ .reg = 0x1a04c,
+ .shift = 0,
+ .width = 2,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_prim_mock_utmi_postdiv_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_mock_utmi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_branch gcc_ahb2phy_csi_clk = {
+ .halt_reg = 0x1d004,
+ .halt_check = BRANCH_HALT_DELAY,
+ .hwcg_reg = 0x1d004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x1d004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ahb2phy_csi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ahb2phy_usb_clk = {
+ .halt_reg = 0x1d008,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x1d008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x1d008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ahb2phy_usb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_boot_rom_ahb_clk = {
+ .halt_reg = 0x23004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x23004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(1),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_boot_rom_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cam_throttle_nrt_clk = {
+ .halt_reg = 0x17070,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x17070,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(16),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_cam_throttle_nrt_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cam_throttle_rt_clk = {
+ .halt_reg = 0x1706c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x1706c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(15),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_cam_throttle_rt_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_axi_clk = {
+ .halt_reg = 0x58044,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x58044,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_axi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_axi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_camnoc_atb_clk = {
+ .halt_reg = 0x5804c,
+ .halt_check = BRANCH_HALT_DELAY,
+ .hwcg_reg = 0x5804c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x5804c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_camnoc_atb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_camnoc_dragonlink_atb_clk = {
+ .halt_reg = 0x58060,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x58060,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x58060,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_camnoc_dragonlink_atb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_camnoc_nts_xo_clk = {
+ .halt_reg = 0x58050,
+ .halt_check = BRANCH_HALT_DELAY,
+ .hwcg_reg = 0x58050,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x58050,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_camnoc_nts_xo_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_cci_0_clk = {
+ .halt_reg = 0x56018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x56018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_cci_0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_cci_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_cphy_0_clk = {
+ .halt_reg = 0x52088,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x52088,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_cphy_0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_tfe_cphy_rx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_cphy_1_clk = {
+ .halt_reg = 0x5208c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5208c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_cphy_1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_tfe_cphy_rx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_csi0phytimer_clk = {
+ .halt_reg = 0x45018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x45018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_csi0phytimer_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_csi0phytimer_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_csi1phytimer_clk = {
+ .halt_reg = 0x45034,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x45034,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_csi1phytimer_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_csi1phytimer_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_mclk0_clk = {
+ .halt_reg = 0x51018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x51018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_mclk0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_mclk0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_mclk1_clk = {
+ .halt_reg = 0x51034,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x51034,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_mclk1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_mclk1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_mclk2_clk = {
+ .halt_reg = 0x51050,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x51050,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_mclk2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_mclk2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_mclk3_clk = {
+ .halt_reg = 0x5106c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5106c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_mclk3_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_mclk3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_nrt_axi_clk = {
+ .halt_reg = 0x58054,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x58054,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_nrt_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_ope_ahb_clk = {
+ .halt_reg = 0x5503c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5503c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_ope_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_ope_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_ope_clk = {
+ .halt_reg = 0x5501c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5501c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_ope_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_ope_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_rt_axi_clk = {
+ .halt_reg = 0x5805c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5805c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_rt_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_tfe_0_clk = {
+ .halt_reg = 0x5201c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5201c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_tfe_0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_tfe_0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_tfe_0_cphy_rx_clk = {
+ .halt_reg = 0x5207c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5207c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_tfe_0_cphy_rx_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_tfe_cphy_rx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_tfe_0_csid_clk = {
+ .halt_reg = 0x520ac,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x520ac,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_tfe_0_csid_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_tfe_0_csid_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_tfe_1_clk = {
+ .halt_reg = 0x5203c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5203c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_tfe_1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_tfe_1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_tfe_1_cphy_rx_clk = {
+ .halt_reg = 0x52080,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x52080,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_tfe_1_cphy_rx_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_tfe_cphy_rx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_tfe_1_csid_clk = {
+ .halt_reg = 0x520cc,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x520cc,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_tfe_1_csid_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_tfe_1_csid_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_top_ahb_clk = {
+ .halt_reg = 0x58028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x58028,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camss_top_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_top_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cfg_noc_usb2_prim_axi_clk = {
+ .halt_reg = 0x111c4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x111c4,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x111c4,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_cfg_noc_usb2_prim_axi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb20_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cfg_noc_usb3_prim_axi_clk = {
+ .halt_reg = 0x1a07c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x1a07c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x1a07c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_cfg_noc_usb3_prim_axi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ddrss_gpu_axi_clk = {
+ .halt_reg = 0x71000,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x71000,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x71000,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ddrss_gpu_axi_clk",
+ .ops = &clk_branch2_aon_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ddrss_memnoc_pcie_sf_clk = {
+ .halt_reg = 0x29044,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x29044,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x29044,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ddrss_memnoc_pcie_sf_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_disp_gpll0_div_clk_src = {
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(11),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_disp_gpll0_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_disp_gpll0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_disp_hf_axi_clk = {
+ .halt_reg = 0x17020,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x17020,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x17020,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_disp_hf_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_disp_throttle_core_clk = {
+ .halt_reg = 0x17064,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x17064,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(13),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_disp_throttle_core_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_emac0_ahb_clk = {
+ .halt_reg = 0xad010,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0xad010,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0xad010,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_emac0_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_emac0_axi_clk = {
+ .halt_reg = 0xad014,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0xad014,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0xad014,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_emac0_axi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_emac0_axi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_emac0_axi_sys_noc_clk = {
+ .halt_reg = 0x109d4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x109d4,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x109d4,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_emac0_axi_sys_noc_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_emac0_axi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_emac0_cc_sgmiiphy_rx_clk = {
+ .halt_reg = 0xad044,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0xad044,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_emac0_cc_sgmiiphy_rx_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_emac0_cc_sgmiiphy_rx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_emac0_cc_sgmiiphy_tx_clk = {
+ .halt_reg = 0xad03c,
+ .halt_check = BRANCH_HALT_DELAY,
+ .hwcg_reg = 0xad03c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0xad03c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_emac0_cc_sgmiiphy_tx_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_emac0_cc_sgmiiphy_tx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_emac0_phy_aux_clk = {
+ .halt_reg = 0xad018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xad018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_emac0_phy_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_emac0_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_emac0_ptp_clk = {
+ .halt_reg = 0xad034,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xad034,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_emac0_ptp_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_emac0_ptp_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_emac0_rgmii_clk = {
+ .halt_reg = 0xad038,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xad038,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_emac0_rgmii_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_emac0_rgmii_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_emac1_ahb_clk = {
+ .halt_reg = 0xae010,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0xae010,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0xae010,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_emac1_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_emac1_axi_clk = {
+ .halt_reg = 0xae014,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0xae014,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0xae014,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_emac1_axi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_emac1_axi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_emac1_axi_sys_noc_clk = {
+ .halt_reg = 0x109f4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x109f4,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x109f4,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_emac1_axi_sys_noc_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_emac1_axi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_emac1_cc_sgmiiphy_rx_clk = {
+ .halt_reg = 0xae044,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0xae044,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_emac1_cc_sgmiiphy_rx_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_emac1_cc_sgmiiphy_rx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_emac1_cc_sgmiiphy_tx_clk = {
+ .halt_reg = 0xae03c,
+ .halt_check = BRANCH_HALT_DELAY,
+ .hwcg_reg = 0xae03c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0xae03c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_emac1_cc_sgmiiphy_tx_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_emac1_cc_sgmiiphy_tx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_emac1_phy_aux_clk = {
+ .halt_reg = 0xae018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xae018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_emac1_phy_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_emac1_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_emac1_ptp_clk = {
+ .halt_reg = 0xae034,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xae034,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_emac1_ptp_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_emac1_ptp_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_emac1_rgmii_clk = {
+ .halt_reg = 0xae038,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xae038,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_emac1_rgmii_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_emac1_rgmii_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp1_clk = {
+ .halt_reg = 0x4d000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4d000,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gp1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gp1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp2_clk = {
+ .halt_reg = 0x4e000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4e000,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gp2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gp2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp3_clk = {
+ .halt_reg = 0x4f000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4f000,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gp3_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gp3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_gpll0_clk_src = {
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(18),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpu_gpll0_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gpll0.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_gpll0_div_clk_src = {
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(19),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpu_gpll0_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gpll0_out_aux2.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_memnoc_gfx_clk = {
+ .halt_reg = 0x3600c,
+ .halt_check = BRANCH_VOTED,
+ .hwcg_reg = 0x3600c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x3600c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpu_memnoc_gfx_clk",
+ .ops = &clk_branch2_aon_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_smmu_vote_clk = {
+ .halt_reg = 0x7d000,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x7d000,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpu_smmu_vote_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_snoc_dvm_gfx_clk = {
+ .halt_reg = 0x36018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x36018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpu_snoc_dvm_gfx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_throttle_core_clk = {
+ .halt_reg = 0x36048,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x36048,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(21),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpu_throttle_core_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_mmu_tcu_vote_clk = {
+ .halt_reg = 0x7d06c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x7d06c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_mmu_tcu_vote_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_aux_clk = {
+ .halt_reg = 0xaf044,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0xaf044,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x79018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_cfg_ahb_clk = {
+ .halt_reg = 0xaf010,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0xaf010,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(27),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_cfg_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_clkref_en = {
+ .halt_reg = 0xb8000,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0xb8000,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_clkref_en",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_mstr_axi_clk = {
+ .halt_reg = 0xaf020,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0xaf020,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(30),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_mstr_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_pipe_clk = {
+ .halt_reg = 0xaf050,
+ .halt_check = BRANCH_HALT_DELAY,
+ .hwcg_reg = 0xaf050,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x79018,
+ .enable_mask = BIT(2),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_pipe_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_pipe_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_rchng_phy_clk = {
+ .halt_reg = 0xaf040,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0xaf040,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(31),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_rchng_phy_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_rchng_phy_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_sleep_clk = {
+ .halt_reg = 0xaf04c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0xaf04c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x79018,
+ .enable_mask = BIT(1),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_sleep_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_aux_phy_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_slv_axi_clk = {
+ .halt_reg = 0xaf018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(29),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_slv_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_slv_q2a_axi_clk = {
+ .halt_reg = 0xaf014,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0xaf014,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(28),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_slv_q2a_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_tbu_clk = {
+ .halt_reg = 0xaf098,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0xaf098,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x79018,
+ .enable_mask = BIT(6),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_tbu_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_throttle_core_clk = {
+ .halt_reg = 0xaf094,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0xaf094,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x79018,
+ .enable_mask = BIT(5),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_throttle_core_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_throttle_xo_clk = {
+ .halt_reg = 0xaf090,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x79018,
+ .enable_mask = BIT(4),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_throttle_xo_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_tile_axi_sys_noc_clk = {
+ .halt_reg = 0x10f2c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x10f2c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x10f2c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_tile_axi_sys_noc_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_emac0_axi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pdm2_clk = {
+ .halt_reg = 0x2000c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2000c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pdm2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pdm2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pdm_ahb_clk = {
+ .halt_reg = 0x20004,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x20004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x20004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pdm_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pdm_xo4_clk = {
+ .halt_reg = 0x20008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x20008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pdm_xo4_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pwm0_xo512_clk = {
+ .halt_reg = 0x2002c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2002c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pwm0_xo512_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_camera_nrt_ahb_clk = {
+ .halt_reg = 0x17014,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x17014,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(9),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qmip_camera_nrt_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_camera_rt_ahb_clk = {
+ .halt_reg = 0x17060,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x17060,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(12),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qmip_camera_rt_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_disp_ahb_clk = {
+ .halt_reg = 0x17018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x17018,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(10),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qmip_disp_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_gpu_cfg_ahb_clk = {
+ .halt_reg = 0x36040,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x36040,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(20),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qmip_gpu_cfg_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_pcie_cfg_ahb_clk = {
+ .halt_reg = 0xaf08c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0xaf08c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x79018,
+ .enable_mask = BIT(3),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qmip_pcie_cfg_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_video_vcodec_ahb_clk = {
+ .halt_reg = 0x17010,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x17010,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(8),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qmip_video_vcodec_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_core_2x_clk = {
+ .halt_reg = 0x1f014,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(21),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_core_2x_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_core_clk = {
+ .halt_reg = 0x1f00c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(20),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_core_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s0_clk = {
+ .halt_reg = 0x1f144,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(22),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_s0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s1_clk = {
+ .halt_reg = 0x1f274,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(23),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_s1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s2_clk = {
+ .halt_reg = 0x1f3a4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(24),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_s2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s3_clk = {
+ .halt_reg = 0x1f4d4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(25),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_s3_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s4_clk = {
+ .halt_reg = 0x1f604,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(26),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_s4_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s4_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s5_clk = {
+ .halt_reg = 0x1f734,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(27),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_s5_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s5_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s6_clk = {
+ .halt_reg = 0x1f864,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(28),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_s6_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s6_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s7_clk = {
+ .halt_reg = 0x1f994,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(29),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_s7_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s7_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s8_clk = {
+ .halt_reg = 0x1fac4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(30),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_s8_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s8_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s9_clk = {
+ .halt_reg = 0x1fbf4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(31),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_s9_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s9_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_0_m_ahb_clk = {
+ .halt_reg = 0x1f004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x1f004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(18),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_0_m_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_0_s_ahb_clk = {
+ .halt_reg = 0x1f008,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x1f008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(19),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_0_s_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc1_ahb_clk = {
+ .halt_reg = 0x38008,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x38008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x38008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc1_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc1_apps_clk = {
+ .halt_reg = 0x38004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x38004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc1_apps_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_sdcc1_apps_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc1_ice_core_clk = {
+ .halt_reg = 0x3800c,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x3800c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x3800c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc1_ice_core_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_sdcc1_ice_core_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc2_ahb_clk = {
+ .halt_reg = 0x1e008,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x1e008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x1e008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc2_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc2_apps_clk = {
+ .halt_reg = 0x1e004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1e004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc2_apps_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_sdcc2_apps_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sys_noc_usb2_prim_axi_clk = {
+ .halt_reg = 0x10a14,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x10a14,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x10a14,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sys_noc_usb2_prim_axi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb20_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sys_noc_usb3_prim_axi_clk = {
+ .halt_reg = 0x1a078,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x1a078,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x1a078,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sys_noc_usb3_prim_axi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_tscss_ahb_clk = {
+ .halt_reg = 0xac024,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0xac024,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0xac024,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_tscss_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_tscss_cntr_clk = {
+ .halt_reg = 0xac020,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xac020,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_tscss_cntr_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_tscss_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_tscss_etu_clk = {
+ .halt_reg = 0xac01c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xac01c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_tscss_etu_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_tscss_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_clkref_en = {
+ .halt_reg = 0x8c000,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x8c000,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_clkref_en",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb20_master_clk = {
+ .halt_reg = 0xb0010,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0xb0010,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0xb0010,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb20_master_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb20_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb20_mock_utmi_clk = {
+ .halt_reg = 0xb001c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0xb001c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb20_mock_utmi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb20_mock_utmi_postdiv_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb20_sleep_clk = {
+ .halt_reg = 0xb0018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0xb0018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb20_sleep_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_prim_master_clk = {
+ .halt_reg = 0x1a010,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x1a010,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x1a010,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_prim_master_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_prim_mock_utmi_clk = {
+ .halt_reg = 0x1a018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1a018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_prim_mock_utmi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_prim_sleep_clk = {
+ .halt_reg = 0x1a014,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1a014,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_prim_sleep_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_prim_clkref_en = {
+ .halt_reg = 0x9f000,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x9f000,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_prim_clkref_en",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_prim_phy_com_aux_clk = {
+ .halt_reg = 0x1a054,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1a054,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_prim_phy_com_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb3_prim_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_prim_phy_pipe_clk = {
+ .halt_reg = 0x1a058,
+ .halt_check = BRANCH_HALT_DELAY,
+ .hwcg_reg = 0x1a058,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x1a058,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_prim_phy_pipe_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb3_prim_phy_pipe_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_vcodec0_axi_clk = {
+ .halt_reg = 0x6e008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x6e008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_vcodec0_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_venus_ahb_clk = {
+ .halt_reg = 0x6e010,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x6e010,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_venus_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_venus_ctl_axi_clk = {
+ .halt_reg = 0x6e004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x6e004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_venus_ctl_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_video_axi0_clk = {
+ .halt_reg = 0x1701c,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x1701c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x1701c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_video_axi0_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_video_throttle_core_clk = {
+ .halt_reg = 0x17068,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x17068,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(14),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_video_throttle_core_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_video_vcodec0_sys_clk = {
+ .halt_reg = 0x6d044,
+ .halt_check = BRANCH_HALT_DELAY,
+ .hwcg_reg = 0x6d044,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x6d044,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_video_vcodec0_sys_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_video_venus_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_video_venus_ctl_clk = {
+ .halt_reg = 0x6d02c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x6d02c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_video_venus_ctl_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_video_venus_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct gdsc gcc_camss_top_gdsc = {
+ .gdscr = 0x58004,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "gcc_camss_top_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc gcc_emac0_gdsc = {
+ .gdscr = 0xad004,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0x2,
+ .pd = {
+ .name = "gcc_emac0_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc gcc_emac1_gdsc = {
+ .gdscr = 0xae004,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0x2,
+ .pd = {
+ .name = "gcc_emac1_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc gcc_pcie_gdsc = {
+ .gdscr = 0xaf004,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "gcc_pcie_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc gcc_usb20_gdsc = {
+ .gdscr = 0xb0004,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "gcc_usb20_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc gcc_usb30_prim_gdsc = {
+ .gdscr = 0x1a004,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0x2,
+ .pd = {
+ .name = "gcc_usb30_prim_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc gcc_venus_gdsc = {
+ .gdscr = 0x6d01c,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "gcc_venus_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc gcc_vcodec0_gdsc = {
+ .gdscr = 0x6d038,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "gcc_vcodec0_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .parent = &gcc_venus_gdsc.pd,
+ .flags = HW_CTRL_TRIGGER | POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct clk_regmap *gcc_shikra_clocks[] = {
+ [GCC_AHB2PHY_CSI_CLK] = &gcc_ahb2phy_csi_clk.clkr,
+ [GCC_AHB2PHY_USB_CLK] = &gcc_ahb2phy_usb_clk.clkr,
+ [GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr,
+ [GCC_CAM_THROTTLE_NRT_CLK] = &gcc_cam_throttle_nrt_clk.clkr,
+ [GCC_CAM_THROTTLE_RT_CLK] = &gcc_cam_throttle_rt_clk.clkr,
+ [GCC_CAMSS_AXI_CLK] = &gcc_camss_axi_clk.clkr,
+ [GCC_CAMSS_AXI_CLK_SRC] = &gcc_camss_axi_clk_src.clkr,
+ [GCC_CAMSS_CAMNOC_ATB_CLK] = &gcc_camss_camnoc_atb_clk.clkr,
+ [GCC_CAMSS_CAMNOC_DRAGONLINK_ATB_CLK] = &gcc_camss_camnoc_dragonlink_atb_clk.clkr,
+ [GCC_CAMSS_CAMNOC_NTS_XO_CLK] = &gcc_camss_camnoc_nts_xo_clk.clkr,
+ [GCC_CAMSS_CCI_0_CLK] = &gcc_camss_cci_0_clk.clkr,
+ [GCC_CAMSS_CCI_CLK_SRC] = &gcc_camss_cci_clk_src.clkr,
+ [GCC_CAMSS_CPHY_0_CLK] = &gcc_camss_cphy_0_clk.clkr,
+ [GCC_CAMSS_CPHY_1_CLK] = &gcc_camss_cphy_1_clk.clkr,
+ [GCC_CAMSS_CSI0PHYTIMER_CLK] = &gcc_camss_csi0phytimer_clk.clkr,
+ [GCC_CAMSS_CSI0PHYTIMER_CLK_SRC] = &gcc_camss_csi0phytimer_clk_src.clkr,
+ [GCC_CAMSS_CSI1PHYTIMER_CLK] = &gcc_camss_csi1phytimer_clk.clkr,
+ [GCC_CAMSS_CSI1PHYTIMER_CLK_SRC] = &gcc_camss_csi1phytimer_clk_src.clkr,
+ [GCC_CAMSS_MCLK0_CLK] = &gcc_camss_mclk0_clk.clkr,
+ [GCC_CAMSS_MCLK0_CLK_SRC] = &gcc_camss_mclk0_clk_src.clkr,
+ [GCC_CAMSS_MCLK1_CLK] = &gcc_camss_mclk1_clk.clkr,
+ [GCC_CAMSS_MCLK1_CLK_SRC] = &gcc_camss_mclk1_clk_src.clkr,
+ [GCC_CAMSS_MCLK2_CLK] = &gcc_camss_mclk2_clk.clkr,
+ [GCC_CAMSS_MCLK2_CLK_SRC] = &gcc_camss_mclk2_clk_src.clkr,
+ [GCC_CAMSS_MCLK3_CLK] = &gcc_camss_mclk3_clk.clkr,
+ [GCC_CAMSS_MCLK3_CLK_SRC] = &gcc_camss_mclk3_clk_src.clkr,
+ [GCC_CAMSS_NRT_AXI_CLK] = &gcc_camss_nrt_axi_clk.clkr,
+ [GCC_CAMSS_OPE_AHB_CLK] = &gcc_camss_ope_ahb_clk.clkr,
+ [GCC_CAMSS_OPE_AHB_CLK_SRC] = &gcc_camss_ope_ahb_clk_src.clkr,
+ [GCC_CAMSS_OPE_CLK] = &gcc_camss_ope_clk.clkr,
+ [GCC_CAMSS_OPE_CLK_SRC] = &gcc_camss_ope_clk_src.clkr,
+ [GCC_CAMSS_RT_AXI_CLK] = &gcc_camss_rt_axi_clk.clkr,
+ [GCC_CAMSS_TFE_0_CLK] = &gcc_camss_tfe_0_clk.clkr,
+ [GCC_CAMSS_TFE_0_CLK_SRC] = &gcc_camss_tfe_0_clk_src.clkr,
+ [GCC_CAMSS_TFE_0_CPHY_RX_CLK] = &gcc_camss_tfe_0_cphy_rx_clk.clkr,
+ [GCC_CAMSS_TFE_0_CSID_CLK] = &gcc_camss_tfe_0_csid_clk.clkr,
+ [GCC_CAMSS_TFE_0_CSID_CLK_SRC] = &gcc_camss_tfe_0_csid_clk_src.clkr,
+ [GCC_CAMSS_TFE_1_CLK] = &gcc_camss_tfe_1_clk.clkr,
+ [GCC_CAMSS_TFE_1_CLK_SRC] = &gcc_camss_tfe_1_clk_src.clkr,
+ [GCC_CAMSS_TFE_1_CPHY_RX_CLK] = &gcc_camss_tfe_1_cphy_rx_clk.clkr,
+ [GCC_CAMSS_TFE_1_CSID_CLK] = &gcc_camss_tfe_1_csid_clk.clkr,
+ [GCC_CAMSS_TFE_1_CSID_CLK_SRC] = &gcc_camss_tfe_1_csid_clk_src.clkr,
+ [GCC_CAMSS_TFE_CPHY_RX_CLK_SRC] = &gcc_camss_tfe_cphy_rx_clk_src.clkr,
+ [GCC_CAMSS_TOP_AHB_CLK] = &gcc_camss_top_ahb_clk.clkr,
+ [GCC_CAMSS_TOP_AHB_CLK_SRC] = &gcc_camss_top_ahb_clk_src.clkr,
+ [GCC_CFG_NOC_USB2_PRIM_AXI_CLK] = &gcc_cfg_noc_usb2_prim_axi_clk.clkr,
+ [GCC_CFG_NOC_USB3_PRIM_AXI_CLK] = &gcc_cfg_noc_usb3_prim_axi_clk.clkr,
+ [GCC_DDRSS_GPU_AXI_CLK] = &gcc_ddrss_gpu_axi_clk.clkr,
+ [GCC_DDRSS_MEMNOC_PCIE_SF_CLK] = &gcc_ddrss_memnoc_pcie_sf_clk.clkr,
+ [GCC_DISP_GPLL0_CLK_SRC] = &gcc_disp_gpll0_clk_src.clkr,
+ [GCC_DISP_GPLL0_DIV_CLK_SRC] = &gcc_disp_gpll0_div_clk_src.clkr,
+ [GCC_DISP_HF_AXI_CLK] = &gcc_disp_hf_axi_clk.clkr,
+ [GCC_DISP_THROTTLE_CORE_CLK] = &gcc_disp_throttle_core_clk.clkr,
+ [GCC_EMAC0_AHB_CLK] = &gcc_emac0_ahb_clk.clkr,
+ [GCC_EMAC0_AXI_CLK] = &gcc_emac0_axi_clk.clkr,
+ [GCC_EMAC0_AXI_CLK_SRC] = &gcc_emac0_axi_clk_src.clkr,
+ [GCC_EMAC0_AXI_SYS_NOC_CLK] = &gcc_emac0_axi_sys_noc_clk.clkr,
+ [GCC_EMAC0_CC_SGMIIPHY_RX_CLK] = &gcc_emac0_cc_sgmiiphy_rx_clk.clkr,
+ [GCC_EMAC0_CC_SGMIIPHY_RX_CLK_SRC] = &gcc_emac0_cc_sgmiiphy_rx_clk_src.clkr,
+ [GCC_EMAC0_CC_SGMIIPHY_TX_CLK] = &gcc_emac0_cc_sgmiiphy_tx_clk.clkr,
+ [GCC_EMAC0_CC_SGMIIPHY_TX_CLK_SRC] = &gcc_emac0_cc_sgmiiphy_tx_clk_src.clkr,
+ [GCC_EMAC0_PHY_AUX_CLK] = &gcc_emac0_phy_aux_clk.clkr,
+ [GCC_EMAC0_PHY_AUX_CLK_SRC] = &gcc_emac0_phy_aux_clk_src.clkr,
+ [GCC_EMAC0_PTP_CLK] = &gcc_emac0_ptp_clk.clkr,
+ [GCC_EMAC0_PTP_CLK_SRC] = &gcc_emac0_ptp_clk_src.clkr,
+ [GCC_EMAC0_RGMII_CLK] = &gcc_emac0_rgmii_clk.clkr,
+ [GCC_EMAC0_RGMII_CLK_SRC] = &gcc_emac0_rgmii_clk_src.clkr,
+ [GCC_EMAC1_AHB_CLK] = &gcc_emac1_ahb_clk.clkr,
+ [GCC_EMAC1_AXI_CLK] = &gcc_emac1_axi_clk.clkr,
+ [GCC_EMAC1_AXI_CLK_SRC] = &gcc_emac1_axi_clk_src.clkr,
+ [GCC_EMAC1_AXI_SYS_NOC_CLK] = &gcc_emac1_axi_sys_noc_clk.clkr,
+ [GCC_EMAC1_CC_SGMIIPHY_RX_CLK] = &gcc_emac1_cc_sgmiiphy_rx_clk.clkr,
+ [GCC_EMAC1_CC_SGMIIPHY_RX_CLK_SRC] = &gcc_emac1_cc_sgmiiphy_rx_clk_src.clkr,
+ [GCC_EMAC1_CC_SGMIIPHY_TX_CLK] = &gcc_emac1_cc_sgmiiphy_tx_clk.clkr,
+ [GCC_EMAC1_CC_SGMIIPHY_TX_CLK_SRC] = &gcc_emac1_cc_sgmiiphy_tx_clk_src.clkr,
+ [GCC_EMAC1_PHY_AUX_CLK] = &gcc_emac1_phy_aux_clk.clkr,
+ [GCC_EMAC1_PHY_AUX_CLK_SRC] = &gcc_emac1_phy_aux_clk_src.clkr,
+ [GCC_EMAC1_PTP_CLK] = &gcc_emac1_ptp_clk.clkr,
+ [GCC_EMAC1_PTP_CLK_SRC] = &gcc_emac1_ptp_clk_src.clkr,
+ [GCC_EMAC1_RGMII_CLK] = &gcc_emac1_rgmii_clk.clkr,
+ [GCC_EMAC1_RGMII_CLK_SRC] = &gcc_emac1_rgmii_clk_src.clkr,
+ [GCC_GP1_CLK] = &gcc_gp1_clk.clkr,
+ [GCC_GP1_CLK_SRC] = &gcc_gp1_clk_src.clkr,
+ [GCC_GP2_CLK] = &gcc_gp2_clk.clkr,
+ [GCC_GP2_CLK_SRC] = &gcc_gp2_clk_src.clkr,
+ [GCC_GP3_CLK] = &gcc_gp3_clk.clkr,
+ [GCC_GP3_CLK_SRC] = &gcc_gp3_clk_src.clkr,
+ [GCC_GPU_GPLL0_CLK_SRC] = &gcc_gpu_gpll0_clk_src.clkr,
+ [GCC_GPU_GPLL0_DIV_CLK_SRC] = &gcc_gpu_gpll0_div_clk_src.clkr,
+ [GCC_GPU_MEMNOC_GFX_CLK] = &gcc_gpu_memnoc_gfx_clk.clkr,
+ [GCC_GPU_SMMU_VOTE_CLK] = &gcc_gpu_smmu_vote_clk.clkr,
+ [GCC_GPU_SNOC_DVM_GFX_CLK] = &gcc_gpu_snoc_dvm_gfx_clk.clkr,
+ [GCC_GPU_THROTTLE_CORE_CLK] = &gcc_gpu_throttle_core_clk.clkr,
+ [GCC_MMU_TCU_VOTE_CLK] = &gcc_mmu_tcu_vote_clk.clkr,
+ [GCC_PCIE_AUX_CLK] = &gcc_pcie_aux_clk.clkr,
+ [GCC_PCIE_AUX_CLK_SRC] = &gcc_pcie_aux_clk_src.clkr,
+ [GCC_PCIE_AUX_PHY_CLK_SRC] = &gcc_pcie_aux_phy_clk_src.clkr,
+ [GCC_PCIE_CFG_AHB_CLK] = &gcc_pcie_cfg_ahb_clk.clkr,
+ [GCC_PCIE_CLKREF_EN] = &gcc_pcie_clkref_en.clkr,
+ [GCC_PCIE_MSTR_AXI_CLK] = &gcc_pcie_mstr_axi_clk.clkr,
+ [GCC_PCIE_PIPE_CLK] = &gcc_pcie_pipe_clk.clkr,
+ [GCC_PCIE_PIPE_CLK_SRC] = &gcc_pcie_pipe_clk_src.clkr,
+ [GCC_PCIE_RCHNG_PHY_CLK] = &gcc_pcie_rchng_phy_clk.clkr,
+ [GCC_PCIE_RCHNG_PHY_CLK_SRC] = &gcc_pcie_rchng_phy_clk_src.clkr,
+ [GCC_PCIE_SLEEP_CLK] = &gcc_pcie_sleep_clk.clkr,
+ [GCC_PCIE_SLV_AXI_CLK] = &gcc_pcie_slv_axi_clk.clkr,
+ [GCC_PCIE_SLV_Q2A_AXI_CLK] = &gcc_pcie_slv_q2a_axi_clk.clkr,
+ [GCC_PCIE_TBU_CLK] = &gcc_pcie_tbu_clk.clkr,
+ [GCC_PCIE_THROTTLE_CORE_CLK] = &gcc_pcie_throttle_core_clk.clkr,
+ [GCC_PCIE_THROTTLE_XO_CLK] = &gcc_pcie_throttle_xo_clk.clkr,
+ [GCC_PCIE_TILE_AXI_SYS_NOC_CLK] = &gcc_pcie_tile_axi_sys_noc_clk.clkr,
+ [GCC_PDM2_CLK] = &gcc_pdm2_clk.clkr,
+ [GCC_PDM2_CLK_SRC] = &gcc_pdm2_clk_src.clkr,
+ [GCC_PDM_AHB_CLK] = &gcc_pdm_ahb_clk.clkr,
+ [GCC_PDM_XO4_CLK] = &gcc_pdm_xo4_clk.clkr,
+ [GCC_PWM0_XO512_CLK] = &gcc_pwm0_xo512_clk.clkr,
+ [GCC_QMIP_CAMERA_NRT_AHB_CLK] = &gcc_qmip_camera_nrt_ahb_clk.clkr,
+ [GCC_QMIP_CAMERA_RT_AHB_CLK] = &gcc_qmip_camera_rt_ahb_clk.clkr,
+ [GCC_QMIP_DISP_AHB_CLK] = &gcc_qmip_disp_ahb_clk.clkr,
+ [GCC_QMIP_GPU_CFG_AHB_CLK] = &gcc_qmip_gpu_cfg_ahb_clk.clkr,
+ [GCC_QMIP_PCIE_CFG_AHB_CLK] = &gcc_qmip_pcie_cfg_ahb_clk.clkr,
+ [GCC_QMIP_VIDEO_VCODEC_AHB_CLK] = &gcc_qmip_video_vcodec_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP0_CORE_2X_CLK] = &gcc_qupv3_wrap0_core_2x_clk.clkr,
+ [GCC_QUPV3_WRAP0_CORE_CLK] = &gcc_qupv3_wrap0_core_clk.clkr,
+ [GCC_QUPV3_WRAP0_S0_CLK] = &gcc_qupv3_wrap0_s0_clk.clkr,
+ [GCC_QUPV3_WRAP0_S0_CLK_SRC] = &gcc_qupv3_wrap0_s0_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S1_CLK] = &gcc_qupv3_wrap0_s1_clk.clkr,
+ [GCC_QUPV3_WRAP0_S1_CLK_SRC] = &gcc_qupv3_wrap0_s1_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S2_CLK] = &gcc_qupv3_wrap0_s2_clk.clkr,
+ [GCC_QUPV3_WRAP0_S2_CLK_SRC] = &gcc_qupv3_wrap0_s2_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S3_CLK] = &gcc_qupv3_wrap0_s3_clk.clkr,
+ [GCC_QUPV3_WRAP0_S3_CLK_SRC] = &gcc_qupv3_wrap0_s3_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S4_CLK] = &gcc_qupv3_wrap0_s4_clk.clkr,
+ [GCC_QUPV3_WRAP0_S4_CLK_SRC] = &gcc_qupv3_wrap0_s4_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S5_CLK] = &gcc_qupv3_wrap0_s5_clk.clkr,
+ [GCC_QUPV3_WRAP0_S5_CLK_SRC] = &gcc_qupv3_wrap0_s5_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S6_CLK] = &gcc_qupv3_wrap0_s6_clk.clkr,
+ [GCC_QUPV3_WRAP0_S6_CLK_SRC] = &gcc_qupv3_wrap0_s6_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S7_CLK] = &gcc_qupv3_wrap0_s7_clk.clkr,
+ [GCC_QUPV3_WRAP0_S7_CLK_SRC] = &gcc_qupv3_wrap0_s7_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S8_CLK] = &gcc_qupv3_wrap0_s8_clk.clkr,
+ [GCC_QUPV3_WRAP0_S8_CLK_SRC] = &gcc_qupv3_wrap0_s8_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S9_CLK] = &gcc_qupv3_wrap0_s9_clk.clkr,
+ [GCC_QUPV3_WRAP0_S9_CLK_SRC] = &gcc_qupv3_wrap0_s9_clk_src.clkr,
+ [GCC_QUPV3_WRAP_0_M_AHB_CLK] = &gcc_qupv3_wrap_0_m_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP_0_S_AHB_CLK] = &gcc_qupv3_wrap_0_s_ahb_clk.clkr,
+ [GCC_SDCC1_AHB_CLK] = &gcc_sdcc1_ahb_clk.clkr,
+ [GCC_SDCC1_APPS_CLK] = &gcc_sdcc1_apps_clk.clkr,
+ [GCC_SDCC1_APPS_CLK_SRC] = &gcc_sdcc1_apps_clk_src.clkr,
+ [GCC_SDCC1_ICE_CORE_CLK] = &gcc_sdcc1_ice_core_clk.clkr,
+ [GCC_SDCC1_ICE_CORE_CLK_SRC] = &gcc_sdcc1_ice_core_clk_src.clkr,
+ [GCC_SDCC2_AHB_CLK] = &gcc_sdcc2_ahb_clk.clkr,
+ [GCC_SDCC2_APPS_CLK] = &gcc_sdcc2_apps_clk.clkr,
+ [GCC_SDCC2_APPS_CLK_SRC] = &gcc_sdcc2_apps_clk_src.clkr,
+ [GCC_SYS_NOC_USB2_PRIM_AXI_CLK] = &gcc_sys_noc_usb2_prim_axi_clk.clkr,
+ [GCC_SYS_NOC_USB3_PRIM_AXI_CLK] = &gcc_sys_noc_usb3_prim_axi_clk.clkr,
+ [GCC_TSCSS_AHB_CLK] = &gcc_tscss_ahb_clk.clkr,
+ [GCC_TSCSS_CLK_SRC] = &gcc_tscss_clk_src.clkr,
+ [GCC_TSCSS_CNTR_CLK] = &gcc_tscss_cntr_clk.clkr,
+ [GCC_TSCSS_ETU_CLK] = &gcc_tscss_etu_clk.clkr,
+ [GCC_UFS_CLKREF_EN] = &gcc_ufs_clkref_en.clkr,
+ [GCC_USB20_MASTER_CLK] = &gcc_usb20_master_clk.clkr,
+ [GCC_USB20_MASTER_CLK_SRC] = &gcc_usb20_master_clk_src.clkr,
+ [GCC_USB20_MOCK_UTMI_CLK] = &gcc_usb20_mock_utmi_clk.clkr,
+ [GCC_USB20_MOCK_UTMI_CLK_SRC] = &gcc_usb20_mock_utmi_clk_src.clkr,
+ [GCC_USB20_MOCK_UTMI_POSTDIV_CLK_SRC] = &gcc_usb20_mock_utmi_postdiv_clk_src.clkr,
+ [GCC_USB20_SLEEP_CLK] = &gcc_usb20_sleep_clk.clkr,
+ [GCC_USB30_PRIM_MASTER_CLK] = &gcc_usb30_prim_master_clk.clkr,
+ [GCC_USB30_PRIM_MASTER_CLK_SRC] = &gcc_usb30_prim_master_clk_src.clkr,
+ [GCC_USB30_PRIM_MOCK_UTMI_CLK] = &gcc_usb30_prim_mock_utmi_clk.clkr,
+ [GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC] = &gcc_usb30_prim_mock_utmi_clk_src.clkr,
+ [GCC_USB30_PRIM_MOCK_UTMI_POSTDIV_CLK_SRC] = &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr,
+ [GCC_USB30_PRIM_SLEEP_CLK] = &gcc_usb30_prim_sleep_clk.clkr,
+ [GCC_USB3_PRIM_CLKREF_EN] = &gcc_usb3_prim_clkref_en.clkr,
+ [GCC_USB3_PRIM_PHY_AUX_CLK_SRC] = &gcc_usb3_prim_phy_aux_clk_src.clkr,
+ [GCC_USB3_PRIM_PHY_COM_AUX_CLK] = &gcc_usb3_prim_phy_com_aux_clk.clkr,
+ [GCC_USB3_PRIM_PHY_PIPE_CLK] = &gcc_usb3_prim_phy_pipe_clk.clkr,
+ [GCC_USB3_PRIM_PHY_PIPE_CLK_SRC] = &gcc_usb3_prim_phy_pipe_clk_src.clkr,
+ [GCC_VCODEC0_AXI_CLK] = &gcc_vcodec0_axi_clk.clkr,
+ [GCC_VENUS_AHB_CLK] = &gcc_venus_ahb_clk.clkr,
+ [GCC_VENUS_CTL_AXI_CLK] = &gcc_venus_ctl_axi_clk.clkr,
+ [GCC_VIDEO_AXI0_CLK] = &gcc_video_axi0_clk.clkr,
+ [GCC_VIDEO_THROTTLE_CORE_CLK] = &gcc_video_throttle_core_clk.clkr,
+ [GCC_VIDEO_VCODEC0_SYS_CLK] = &gcc_video_vcodec0_sys_clk.clkr,
+ [GCC_VIDEO_VENUS_CLK_SRC] = &gcc_video_venus_clk_src.clkr,
+ [GCC_VIDEO_VENUS_CTL_CLK] = &gcc_video_venus_ctl_clk.clkr,
+ [GPLL0] = &gpll0.clkr,
+ [GPLL0_OUT_AUX2] = &gpll0_out_aux2.clkr,
+ [GPLL10] = &gpll10.clkr,
+ [GPLL11] = &gpll11.clkr,
+ [GPLL12] = &gpll12.clkr,
+ [GPLL12_OUT_AUX2] = &gpll12_out_aux2.clkr,
+ [GPLL3] = &gpll3.clkr,
+ [GPLL3_OUT_MAIN] = &gpll3_out_main.clkr,
+ [GPLL4] = &gpll4.clkr,
+ [GPLL5] = &gpll5.clkr,
+ [GPLL6] = &gpll6.clkr,
+ [GPLL6_OUT_MAIN] = &gpll6_out_main.clkr,
+ [GPLL7] = &gpll7.clkr,
+ [GPLL8] = &gpll8.clkr,
+ [GPLL8_OUT_MAIN] = &gpll8_out_main.clkr,
+ [GPLL9] = &gpll9.clkr,
+ [GPLL9_OUT_MAIN] = &gpll9_out_main.clkr,
+};
+
+static struct gdsc *gcc_shikra_gdscs[] = {
+ [GCC_CAMSS_TOP_GDSC] = &gcc_camss_top_gdsc,
+ [GCC_EMAC0_GDSC] = &gcc_emac0_gdsc,
+ [GCC_EMAC1_GDSC] = &gcc_emac1_gdsc,
+ [GCC_PCIE_GDSC] = &gcc_pcie_gdsc,
+ [GCC_USB20_GDSC] = &gcc_usb20_gdsc,
+ [GCC_USB30_PRIM_GDSC] = &gcc_usb30_prim_gdsc,
+ [GCC_VCODEC0_GDSC] = &gcc_vcodec0_gdsc,
+ [GCC_VENUS_GDSC] = &gcc_venus_gdsc,
+};
+
+static const struct qcom_reset_map gcc_shikra_resets[] = {
+ [GCC_CAMSS_OPE_BCR] = { 0x55000 },
+ [GCC_CAMSS_TFE_BCR] = { 0x52000 },
+ [GCC_CAMSS_TOP_BCR] = { 0x58000 },
+ [GCC_EMAC0_BCR] = { 0xad000 },
+ [GCC_EMAC1_BCR] = { 0xae000 },
+ [GCC_GPU_BCR] = { 0x36000 },
+ [GCC_MMSS_BCR] = { 0x17000 },
+ [GCC_PCIE_BCR] = { 0xaf000 },
+ [GCC_PCIE_PHY_BCR] = { 0xb1000 },
+ [GCC_PDM_BCR] = { 0x20000 },
+ [GCC_QUPV3_WRAPPER_0_BCR] = { 0x1f000 },
+ [GCC_QUSB2PHY_PRIM_BCR] = { 0x1c000 },
+ [GCC_QUSB2PHY_SEC_BCR] = { 0x1c004 },
+ [GCC_SDCC1_BCR] = { 0x38000 },
+ [GCC_SDCC2_BCR] = { 0x1e000 },
+ [GCC_TSCSS_BCR] = { 0xac000 },
+ [GCC_USB20_BCR] = { 0xb0000 },
+ [GCC_USB30_PRIM_BCR] = { 0x1a000 },
+ [GCC_USB3PHY_PHY_PRIM_SP0_BCR] = { 0x1b008 },
+ [GCC_USB3_DP_PHY_PRIM_BCR] = { 0x1b020 },
+ [GCC_USB3_PHY_PRIM_SP0_BCR] = { 0x1b000 },
+ [GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x1d000 },
+ [GCC_VCODEC0_BCR] = { 0x6d034 },
+ [GCC_VENUS_BCR] = { 0x6d018 },
+ [GCC_VIDEO_INTERFACE_BCR] = { 0x6e000 },
+};
+
+static struct clk_alpha_pll *gcc_shikra_plls[] = {
+ &gpll10,
+ &gpll11,
+ &gpll8,
+ &gpll9,
+};
+
+static const u32 gcc_shikra_critical_cbcrs[] = {
+ 0x17008, /* GCC_CAMERA_AHB_CLK */
+ 0x17028, /* GCC_CAMERA_XO_CLK */
+ 0x1700c, /* GCC_DISP_AHB_CLK */
+ 0x1702c, /* GCC_DISP_XO_CLK */
+ 0x36004, /* GCC_GPU_CFG_AHB_CLK */
+ 0x36100, /* GCC_GPU_IREF_CLK */
+ 0x3a00c, /* GCC_LPASS_CONFIG_CLK */
+ 0x3a008, /* GCC_LPASS_CORE_AXIM_CLK */
+ 0x79004, /* GCC_SYS_NOC_CPUSS_AHB_CLK */
+ 0x17004, /* GCC_VIDEO_AHB_CLK */
+ 0x17024, /* GCC_VIDEO_XO_CLK */
+};
+
+static const struct clk_rcg_dfs_data gcc_shikra_dfs_clocks[] = {
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s0_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s1_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s2_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s3_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s4_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s5_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s6_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s7_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s8_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s9_clk_src),
+};
+
+static const struct regmap_config gcc_shikra_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0xc7000,
+ .fast_io = true,
+};
+
+static const struct qcom_cc_driver_data gcc_shikra_driver_data = {
+ .alpha_plls = gcc_shikra_plls,
+ .num_alpha_plls = ARRAY_SIZE(gcc_shikra_plls),
+ .clk_cbcrs = gcc_shikra_critical_cbcrs,
+ .num_clk_cbcrs = ARRAY_SIZE(gcc_shikra_critical_cbcrs),
+ .dfs_rcgs = gcc_shikra_dfs_clocks,
+ .num_dfs_rcgs = ARRAY_SIZE(gcc_shikra_dfs_clocks),
+};
+
+static const struct qcom_cc_desc gcc_shikra_desc = {
+ .config = &gcc_shikra_regmap_config,
+ .clks = gcc_shikra_clocks,
+ .num_clks = ARRAY_SIZE(gcc_shikra_clocks),
+ .resets = gcc_shikra_resets,
+ .num_resets = ARRAY_SIZE(gcc_shikra_resets),
+ .gdscs = gcc_shikra_gdscs,
+ .num_gdscs = ARRAY_SIZE(gcc_shikra_gdscs),
+ .driver_data = &gcc_shikra_driver_data,
+};
+
+static const struct of_device_id gcc_shikra_match_table[] = {
+ { .compatible = "qcom,shikra-gcc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, gcc_shikra_match_table);
+
+static int gcc_shikra_probe(struct platform_device *pdev)
+{
+ return qcom_cc_probe(pdev, &gcc_shikra_desc);
+}
+
+static struct platform_driver gcc_shikra_driver = {
+ .probe = gcc_shikra_probe,
+ .driver = {
+ .name = "gcc-shikra",
+ .of_match_table = gcc_shikra_match_table,
+ },
+};
+
+static int __init gcc_shikra_init(void)
+{
+ return platform_driver_register(&gcc_shikra_driver);
+}
+subsys_initcall(gcc_shikra_init);
+
+static void __exit gcc_shikra_exit(void)
+{
+ platform_driver_unregister(&gcc_shikra_driver);
+}
+module_exit(gcc_shikra_exit);
+
+MODULE_DESCRIPTION("QTI GCC Shikra Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/qcom/gcc-sm6115.c b/drivers/clk/qcom/gcc-sm6115.c
index 4c3804701e24..c5251aff9886 100644
--- a/drivers/clk/qcom/gcc-sm6115.c
+++ b/drivers/clk/qcom/gcc-sm6115.c
@@ -3218,6 +3218,7 @@ static struct gdsc gcc_vcodec0_gdsc = {
.pd = {
.name = "gcc_vcodec0",
},
+ .flags = HW_CTRL_TRIGGER,
.pwrsts = PWRSTS_OFF_ON,
};
diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c
index f419a28f616b..b99d70149af3 100644
--- a/drivers/clk/qcom/gdsc.c
+++ b/drivers/clk/qcom/gdsc.c
@@ -104,14 +104,21 @@ static int gdsc_hwctrl(struct gdsc *sc, bool en)
static int gdsc_poll_status(struct gdsc *sc, enum gdsc_status status)
{
ktime_t start;
+ int ret;
start = ktime_get();
do {
- if (gdsc_check_status(sc, status))
+ ret = gdsc_check_status(sc, status);
+ if (ret < 0)
+ return ret;
+ if (ret)
return 0;
} while (ktime_us_delta(ktime_get(), start) < STATUS_POLL_TIMEOUT_US);
- if (gdsc_check_status(sc, status))
+ ret = gdsc_check_status(sc, status);
+ if (ret < 0)
+ return ret;
+ if (ret)
return 0;
return -ETIMEDOUT;
@@ -493,7 +500,9 @@ static int gdsc_init(struct gdsc *sc)
} else if (sc->flags & ALWAYS_ON) {
/* If ALWAYS_ON GDSCs are not ON, turn them ON */
- gdsc_enable(&sc->pd);
+ ret = gdsc_enable(&sc->pd);
+ if (ret)
+ return ret;
on = true;
}
@@ -669,10 +678,18 @@ err_pm_subdomain_remove:
void gdsc_unregister(struct gdsc_desc *desc)
{
struct device *dev = desc->dev;
+ struct gdsc **scs = desc->scs;
size_t num = desc->num;
+ int i;
- gdsc_pm_subdomain_remove(desc, num);
of_genpd_del_provider(dev->of_node);
+ gdsc_pm_subdomain_remove(desc, num);
+
+ for (i = 0; i < num; i++) {
+ if (!scs[i])
+ continue;
+ pm_genpd_remove(&scs[i]->pd);
+ }
}
/*
diff --git a/drivers/clk/ux500/clk-prcmu.c b/drivers/clk/ux500/clk-prcmu.c
index ddc86551bf57..ac96c46bd1bb 100644
--- a/drivers/clk/ux500/clk-prcmu.c
+++ b/drivers/clk/ux500/clk-prcmu.c
@@ -7,7 +7,7 @@
*/
#include <linux/clk-provider.h>
-#include <linux/mfd/dbx500-prcmu.h>
+#include <linux/mfd/db8500-prcmu.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/err.h>
@@ -35,13 +35,13 @@ static int clk_prcmu_prepare(struct clk_hw *hw)
{
struct clk_prcmu *clk = to_clk_prcmu(hw);
- return prcmu_request_clock(clk->cg_sel, true);
+ return db8500_prcmu_request_clock(clk->cg_sel, true);
}
static void clk_prcmu_unprepare(struct clk_hw *hw)
{
struct clk_prcmu *clk = to_clk_prcmu(hw);
- if (prcmu_request_clock(clk->cg_sel, false))
+ if (db8500_prcmu_request_clock(clk->cg_sel, false))
pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
clk_hw_get_name(hw));
}
@@ -86,7 +86,7 @@ static int clk_prcmu_opp_prepare(struct clk_hw *hw)
clk->opp_requested = 1;
}
- err = prcmu_request_clock(clk->cg_sel, true);
+ err = db8500_prcmu_request_clock(clk->cg_sel, true);
if (err) {
prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP,
(char *)clk_hw_get_name(hw));
@@ -101,7 +101,7 @@ static void clk_prcmu_opp_unprepare(struct clk_hw *hw)
{
struct clk_prcmu *clk = to_clk_prcmu(hw);
- if (prcmu_request_clock(clk->cg_sel, false)) {
+ if (db8500_prcmu_request_clock(clk->cg_sel, false)) {
pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
clk_hw_get_name(hw));
return;
@@ -120,7 +120,7 @@ static int clk_prcmu_opp_volt_prepare(struct clk_hw *hw)
struct clk_prcmu *clk = to_clk_prcmu(hw);
if (!clk->opp_requested) {
- err = prcmu_request_ape_opp_100_voltage(true);
+ err = db8500_prcmu_request_ape_opp_100_voltage(true);
if (err) {
pr_err("clk_prcmu: %s fail req APE OPP VOLT for %s.\n",
__func__, clk_hw_get_name(hw));
@@ -129,9 +129,9 @@ static int clk_prcmu_opp_volt_prepare(struct clk_hw *hw)
clk->opp_requested = 1;
}
- err = prcmu_request_clock(clk->cg_sel, true);
+ err = db8500_prcmu_request_clock(clk->cg_sel, true);
if (err) {
- prcmu_request_ape_opp_100_voltage(false);
+ db8500_prcmu_request_ape_opp_100_voltage(false);
clk->opp_requested = 0;
return err;
}
@@ -143,14 +143,14 @@ static void clk_prcmu_opp_volt_unprepare(struct clk_hw *hw)
{
struct clk_prcmu *clk = to_clk_prcmu(hw);
- if (prcmu_request_clock(clk->cg_sel, false)) {
+ if (db8500_prcmu_request_clock(clk->cg_sel, false)) {
pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
clk_hw_get_name(hw));
return;
}
if (clk->opp_requested) {
- prcmu_request_ape_opp_100_voltage(false);
+ db8500_prcmu_request_ape_opp_100_voltage(false);
clk->opp_requested = 0;
}
}
diff --git a/drivers/clk/ux500/u8500_of_clk.c b/drivers/clk/ux500/u8500_of_clk.c
index 6f78808387b1..d2499815226f 100644
--- a/drivers/clk/ux500/u8500_of_clk.c
+++ b/drivers/clk/ux500/u8500_of_clk.c
@@ -9,7 +9,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/clk-provider.h>
-#include <linux/mfd/dbx500-prcmu.h>
+#include <linux/mfd/db8500-prcmu.h>
#include "clk.h"
#include "prcc.h"
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index f07b73694cec..0d0df986fa3d 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -2590,6 +2590,9 @@ static void cpufreq_update_pressure(struct cpufreq_policy *policy)
cpu = cpumask_first(policy->related_cpus);
max_freq = arch_scale_freq_ref(cpu);
+ if (!max_freq)
+ max_freq = policy->cpuinfo.max_freq;
+
capped_freq = policy->max;
/*
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
index 2f048929ff6b..2cbf810db66e 100644
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -1048,12 +1048,14 @@ static void hybrid_clear_cpu_capacity(unsigned int cpunum)
static void hybrid_get_capacity_perf(struct cpudata *cpu)
{
+ u64 hwp_cap = READ_ONCE(cpu->hwp_cap_cached);
+
if (READ_ONCE(global.no_turbo)) {
- cpu->capacity_perf = cpu->pstate.max_pstate_physical;
+ cpu->capacity_perf = HWP_GUARANTEED_PERF(hwp_cap);
return;
}
- cpu->capacity_perf = HWP_HIGHEST_PERF(READ_ONCE(cpu->hwp_cap_cached));
+ cpu->capacity_perf = HWP_HIGHEST_PERF(hwp_cap);
}
static void hybrid_set_capacity_of_cpus(void)
diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig
index d6d8386d3f02..00e2562041fd 100644
--- a/drivers/cpuidle/Kconfig
+++ b/drivers/cpuidle/Kconfig
@@ -71,6 +71,11 @@ depends on RISCV
source "drivers/cpuidle/Kconfig.riscv"
endmenu
+menu "S390 CPU Idle Drivers"
+depends on S390
+source "drivers/cpuidle/Kconfig.s390"
+endmenu
+
config HALTPOLL_CPUIDLE
tristate "Halt poll cpuidle driver"
depends on X86 && KVM_GUEST
diff --git a/drivers/cpuidle/Kconfig.s390 b/drivers/cpuidle/Kconfig.s390
new file mode 100644
index 000000000000..c9acf7ba8eee
--- /dev/null
+++ b/drivers/cpuidle/Kconfig.s390
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# S390 CPU Idle drivers
+#
+
+config S390_CPUIDLE
+ bool "S390 CPU idle driver"
+ default y
+ help
+ Select this option to enable processor idle state management
+ through cpuidle subsystem.
diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile
index 1de9e92c5b0f..88cbc2a7aea8 100644
--- a/drivers/cpuidle/Makefile
+++ b/drivers/cpuidle/Makefile
@@ -42,3 +42,7 @@ obj-$(CONFIG_POWERNV_CPUIDLE) += cpuidle-powernv.o
###############################################################################
# RISC-V drivers
obj-$(CONFIG_RISCV_SBI_CPUIDLE) += cpuidle-riscv-sbi.o
+
+###############################################################################
+# S390 drivers
+obj-$(CONFIG_S390_CPUIDLE) += cpuidle-s390.o
diff --git a/drivers/cpuidle/cpuidle-s390.c b/drivers/cpuidle/cpuidle-s390.c
new file mode 100644
index 000000000000..1d02a77ebce0
--- /dev/null
+++ b/drivers/cpuidle/cpuidle-s390.c
@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * s390 generic CPU idle driver.
+ *
+ * Copyright IBM Corp. 2026
+ */
+
+#define pr_fmt(fmt) "CPUidle s390: " fmt
+
+#include <linux/init.h>
+#include <linux/cpuidle.h>
+#include <linux/cpu.h>
+#include <linux/sched/clock.h>
+
+static __cpuidle int s390_enter_idle(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index)
+{
+ arch_cpu_idle();
+ return index;
+}
+
+static struct cpuidle_driver s390_cpuidle_driver = {
+ .cpumask = (struct cpumask *)cpu_present_mask,
+ .name = "s390-idle",
+ .states = {
+ { /* entry 0 is for polling */},
+ {
+ .enter = s390_enter_idle,
+ .name = "IDLE",
+ .desc = "ENABLED WAIT",
+ },
+ },
+ .safe_state_index = 0,
+ .state_count = 2,
+};
+
+static int s390_cpuidle_cpu_online(unsigned int cpu)
+{
+ struct cpuidle_device *dev = &per_cpu(cpuidle_dev, cpu);
+ int rc;
+
+ if (dev->registered) {
+ cpuidle_pause_and_lock();
+ rc = cpuidle_enable_device(dev);
+ cpuidle_resume_and_unlock();
+ if (rc)
+ pr_err("Failed to enable cpuidle device on cpu %u\n", cpu);
+ } else {
+ dev->cpu = cpu;
+ rc = cpuidle_register_device(dev);
+ if (rc)
+ pr_err("Failed to register cpuidle driver on cpu %u\n", cpu);
+ }
+ return rc;
+}
+
+static int s390_cpuidle_cpu_dead(unsigned int cpu)
+{
+ struct cpuidle_device *dev = &per_cpu(cpuidle_dev, cpu);
+
+ if (!dev->registered)
+ return 0;
+ cpuidle_pause_and_lock();
+ cpuidle_disable_device(dev);
+ cpuidle_resume_and_unlock();
+ return 0;
+}
+
+/*
+ * The target_residency and exit_latency values are benchmark-derived estimates
+ * that remain non-deterministic due to s390's virtualized architecture.
+ *
+ * Configuration strategy:
+ * - Poll idle state: Values derived from the next enabled idle state (EW)
+ * - Enabled Wait state: Values selected based on idle behavior and empirical
+ * measurement data
+ *
+ * Goal is to improve responsiveness for workloads with frequent sleep/wakeup
+ * cycles while minimizing any side effects.
+ */
+static void __init s390_cpuidle_ew_tune(void)
+{
+ struct cpuidle_state *state = &s390_cpuidle_driver.states[1];
+
+ if (machine_is_lpar()) {
+ state->target_residency = 5;
+ state->exit_latency = 5;
+ } else {
+ state->target_residency = 1;
+ state->exit_latency = 1;
+ }
+}
+
+static int __init s390_cpuidle_init(void)
+{
+ int rc;
+
+ s390_cpuidle_ew_tune();
+ cpuidle_poll_state_init(&s390_cpuidle_driver);
+ rc = cpuidle_register(&s390_cpuidle_driver, NULL);
+ if (rc)
+ return rc;
+ rc = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
+ "cpuidle/s390:online",
+ s390_cpuidle_cpu_online,
+ s390_cpuidle_cpu_dead);
+ if (rc < 0) {
+ cpuidle_unregister(&s390_cpuidle_driver);
+ pr_err("Failed to allocate hotplug state: cpuidle/s390:online\n");
+ return rc;
+ }
+ return 0;
+}
+device_initcall(s390_cpuidle_init);
diff --git a/drivers/cpuidle/cpuidle-ux500.c b/drivers/cpuidle/cpuidle-ux500.c
index f7d778580e9b..6d6c52c0bcc2 100644
--- a/drivers/cpuidle/cpuidle-ux500.c
+++ b/drivers/cpuidle/cpuidle-ux500.c
@@ -11,7 +11,7 @@
#include <linux/spinlock.h>
#include <linux/atomic.h>
#include <linux/smp.h>
-#include <linux/mfd/dbx500-prcmu.h>
+#include <linux/mfd/db8500-prcmu.h>
#include <linux/platform_data/arm-ux500-pm.h>
#include <linux/platform_device.h>
@@ -66,7 +66,7 @@ static inline int ux500_enter_idle(struct cpuidle_device *dev,
/* Go to the retention state, the prcmu will wait for the
* cpu to go WFI and this is what happens after exiting this
* 'master' critical section */
- if (prcmu_set_power_state(PRCMU_AP_IDLE, true, true))
+ if (db8500_prcmu_set_power_state(PRCMU_AP_IDLE, true, true))
goto out;
/* When we switch to retention, the prcmu is in charge
@@ -109,7 +109,7 @@ static struct cpuidle_driver ux500_idle_driver = {
static int dbx500_cpuidle_probe(struct platform_device *pdev)
{
/* Configure wake up reasons */
- prcmu_enable_wakeups(PRCMU_WAKEUP(ARM) | PRCMU_WAKEUP(RTC) |
+ db8500_prcmu_enable_wakeups(PRCMU_WAKEUP(ARM) | PRCMU_WAKEUP(RTC) |
PRCMU_WAKEUP(ABB));
return cpuidle_register(&ux500_idle_driver, NULL);
diff --git a/drivers/dibs/dibs_loopback.c b/drivers/dibs/dibs_loopback.c
index ec3b48cb0e87..0f2e09311152 100644
--- a/drivers/dibs/dibs_loopback.c
+++ b/drivers/dibs/dibs_loopback.c
@@ -254,6 +254,11 @@ static int dibs_lo_move_data(struct dibs_dev *dibs, u64 dmb_tok,
read_unlock_bh(&ldev->dmb_ht_lock);
return -EINVAL;
}
+ if ((u64)offset + size > rmb_node->len) {
+ read_unlock_bh(&ldev->dmb_ht_lock);
+ return -EINVAL;
+ }
+
memcpy((char *)rmb_node->cpu_addr + offset, data, size);
sba_idx = rmb_node->sba_idx;
read_unlock_bh(&ldev->dmb_ht_lock);
diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c
index 7e3c9f38297b..e735f43dcdeb 100644
--- a/drivers/extcon/extcon-adc-jack.c
+++ b/drivers/extcon/extcon-adc-jack.c
@@ -210,3 +210,4 @@ module_platform_driver(adc_jack_driver);
MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
MODULE_DESCRIPTION("ADC Jack extcon driver");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/firmware/arm_scmi/Kconfig b/drivers/firmware/arm_scmi/Kconfig
index e3fb36825978..783c24a20e29 100644
--- a/drivers/firmware/arm_scmi/Kconfig
+++ b/drivers/firmware/arm_scmi/Kconfig
@@ -96,7 +96,7 @@ config ARM_SCMI_POWER_CONTROL
firmware.
This driver can also be built as a module. If so, the module will be
- called scmi_power_control. Note this may needed early in boot to catch
- early shutdown/reboot SCMI requests.
+ called scmi_power_control. Note this may be needed early in boot to
+ catch early shutdown/reboot SCMI requests.
endmenu
diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c
index 42e666a628c7..0278705d809e 100644
--- a/drivers/firmware/arm_scmi/clock.c
+++ b/drivers/firmware/arm_scmi/clock.c
@@ -718,7 +718,7 @@ static int scmi_clock_rate_set(const struct scmi_protocol_handle *ph,
static int scmi_clock_determine_rate(const struct scmi_protocol_handle *ph,
u32 clk_id, unsigned long *rate)
{
- u64 fmin, fmax, ftmp;
+ u64 fmin, fmax, ftmp, step;
struct scmi_clock_info *clk;
struct scmi_clock_desc *clkd;
struct clock_info *ci = ph->get_priv(ph);
@@ -749,11 +749,14 @@ static int scmi_clock_determine_rate(const struct scmi_protocol_handle *ph,
return 0;
}
+ step = clkd->r.rates[RATE_STEP];
+ if (!step)
+ return -EINVAL;
+
ftmp = *rate - fmin;
- ftmp += clkd->r.rates[RATE_STEP] - 1; /* to round up */
- ftmp = div64_ul(ftmp, clkd->r.rates[RATE_STEP]);
+ ftmp = DIV64_U64_ROUND_UP(ftmp, step);
- *rate = ftmp * clkd->r.rates[RATE_STEP] + fmin;
+ *rate = ftmp * step + fmin;
return 0;
}
diff --git a/drivers/firmware/arm_scmi/notify.c b/drivers/firmware/arm_scmi/notify.c
index 40ec184eedae..3cf706aacc11 100644
--- a/drivers/firmware/arm_scmi/notify.c
+++ b/drivers/firmware/arm_scmi/notify.c
@@ -209,11 +209,11 @@ struct scmi_registered_events_desc;
* @init_work: A work item to perform final initializations of pending handlers
* @notify_wq: A reference to the allocated Kernel cmwq
* @pending_mtx: A mutex to protect @pending_events_handlers
+ * @pending_events_handlers: An hashtable containing all pending events'
+ * handlers descriptors
* @registered_protocols: A statically allocated array containing pointers to
* all the registered protocol-level specific information
* related to events' handling
- * @pending_events_handlers: An hashtable containing all pending events'
- * handlers descriptors
*
* Each platform instance, represented by a handle, has its own instance of
* the notification subsystem represented by this structure.
@@ -225,8 +225,8 @@ struct scmi_notify_instance {
struct workqueue_struct *notify_wq;
/* lock to protect pending_events_handlers */
struct mutex pending_mtx;
- struct scmi_registered_events_desc **registered_protocols;
DECLARE_HASHTABLE(pending_events_handlers, SCMI_PENDING_HASH_SZ);
+ struct scmi_registered_events_desc *registered_protocols[SCMI_MAX_PROTO];
};
/**
@@ -276,13 +276,13 @@ struct scmi_registered_event;
* @eh_sz: Size of the pre-allocated buffer @eh
* @in_flight: A reference to an in flight &struct scmi_registered_event
* @num_events: Number of events in @registered_events
- * @registered_events: A dynamically allocated array holding all the registered
- * events' descriptors, whose fixed-size is determined at
- * compile time.
* @registered_mtx: A mutex to protect @registered_events_handlers
* @ph: SCMI protocol handle reference
* @registered_events_handlers: An hashtable containing all events' handlers
* descriptors registered for this protocol
+ * @registered_events: A dynamically allocated array holding all the registered
+ * events' descriptors, whose fixed-size is determined at
+ * compile time.
*
* All protocols that register at least one event have their protocol-specific
* information stored here, together with the embedded allocated events_queue.
@@ -302,11 +302,11 @@ struct scmi_registered_events_desc {
size_t eh_sz;
void *in_flight;
int num_events;
- struct scmi_registered_event **registered_events;
/* mutex to protect registered_events_handlers */
struct mutex registered_mtx;
const struct scmi_protocol_handle *ph;
DECLARE_HASHTABLE(registered_events_handlers, SCMI_REGISTERED_HASH_SZ);
+ struct scmi_registered_event *registered_events[] __counted_by(num_events);
};
/**
@@ -338,9 +338,9 @@ struct scmi_registered_event {
void *report;
u32 num_sources;
bool not_supported_by_platform;
- refcount_t *sources;
/* locking to serialize the access to sources */
struct mutex sources_mtx;
+ refcount_t sources[] __counted_by(num_sources);
};
/**
@@ -600,9 +600,9 @@ int scmi_notify(const struct scmi_handle *handle, u8 proto_id, u8 evt_id,
return -EINVAL;
}
if (kfifo_avail(&r_evt->proto->equeue.kfifo) < sizeof(eh) + len) {
- dev_warn(handle->dev,
- "queue full, dropping proto_id:%d evt_id:%d ts:%lld\n",
- proto_id, evt_id, ktime_to_ns(ts));
+ dev_warn_ratelimited(handle->dev,
+ "queue full, dropping proto_id:%d evt_id:%d ts:%lld\n",
+ proto_id, evt_id, ktime_to_ns(ts));
return -ENOMEM;
}
@@ -706,9 +706,13 @@ scmi_allocate_registered_events_desc(struct scmi_notify_instance *ni,
if (WARN_ON(ni->registered_protocols[proto_id]))
return ERR_PTR(-EINVAL);
- pd = devm_kzalloc(ni->handle->dev, sizeof(*pd), GFP_KERNEL);
+ pd = devm_kzalloc(ni->handle->dev,
+ struct_size(pd, registered_events, num_events),
+ GFP_KERNEL);
if (!pd)
return ERR_PTR(-ENOMEM);
+
+ pd->num_events = num_events;
pd->id = proto_id;
pd->ops = ops;
pd->ni = ni;
@@ -722,12 +726,6 @@ scmi_allocate_registered_events_desc(struct scmi_notify_instance *ni,
return ERR_PTR(-ENOMEM);
pd->eh_sz = eh_sz;
- pd->registered_events = devm_kcalloc(ni->handle->dev, num_events,
- sizeof(char *), GFP_KERNEL);
- if (!pd->registered_events)
- return ERR_PTR(-ENOMEM);
- pd->num_events = num_events;
-
/* Initialize per protocol handlers table */
mutex_init(&pd->registered_mtx);
hash_init(pd->registered_events_handlers);
@@ -796,18 +794,16 @@ int scmi_register_protocol_events(const struct scmi_handle *handle, u8 proto_id,
int id;
struct scmi_registered_event *r_evt;
- r_evt = devm_kzalloc(ni->handle->dev, sizeof(*r_evt),
+ r_evt = devm_kzalloc(ni->handle->dev,
+ struct_size(r_evt, sources, num_sources),
GFP_KERNEL);
if (!r_evt)
return -ENOMEM;
+
+ r_evt->num_sources = num_sources;
r_evt->proto = pd;
r_evt->evt = evt;
- r_evt->sources = devm_kcalloc(ni->handle->dev, num_sources,
- sizeof(refcount_t), GFP_KERNEL);
- if (!r_evt->sources)
- return -ENOMEM;
- r_evt->num_sources = num_sources;
mutex_init(&r_evt->sources_mtx);
r_evt->report = devm_kzalloc(ni->handle->dev,
@@ -1673,11 +1669,6 @@ int scmi_notification_init(struct scmi_handle *handle)
ni->gid = gid;
ni->handle = handle;
- ni->registered_protocols = devm_kcalloc(handle->dev, SCMI_MAX_PROTO,
- sizeof(char *), GFP_KERNEL);
- if (!ni->registered_protocols)
- goto err;
-
ni->notify_wq = alloc_workqueue(dev_name(handle->dev),
WQ_UNBOUND | WQ_FREEZABLE | WQ_SYSFS,
0);
diff --git a/drivers/firmware/efi/runtime-wrappers.c b/drivers/firmware/efi/runtime-wrappers.c
index da8d29621644..591a725b1061 100644
--- a/drivers/firmware/efi/runtime-wrappers.c
+++ b/drivers/firmware/efi/runtime-wrappers.c
@@ -119,6 +119,14 @@ union efi_rts_args {
struct efi_runtime_work efi_rts_work;
/*
+ * Upper bound on how long we wait for a single EFI runtime service
+ * call to finish before declaring firmware wedged. Chosen to be longer
+ * than any plausible legitimate call (including UpdateCapsule on slow
+ * SPI-NOR) while still bounding userspace wait time.
+ */
+#define EFI_RTS_TIMEOUT (120 * HZ)
+
+/*
* efi_queue_work: Queue EFI runtime service call and wait for completion
* @_rts: EFI runtime service function identifier
* @_args: Arguments to pass to the EFI runtime service
@@ -212,6 +220,19 @@ extern struct semaphore __efi_uv_runtime_lock __alias(efi_runtime_lock);
#endif
/*
+ * Park a worker that must never run efi_rts_wq again: EFI runtime services
+ * have been disabled and its efi_rts_work is abandoned. Loop in schedule()
+ * so a spurious wakeup cannot resume it.
+ */
+void efi_rts_park_worker(void)
+{
+ for (;;) {
+ set_current_state(TASK_IDLE);
+ schedule();
+ }
+}
+
+/*
* Calls the appropriate efi_runtime_service() with the appropriate
* arguments.
*/
@@ -221,6 +242,9 @@ static void __nocfi efi_call_rts(struct work_struct *work)
efi_status_t status = EFI_NOT_FOUND;
unsigned long flags;
+ if (!efi_enabled(EFI_RUNTIME_SERVICES))
+ efi_rts_park_worker();
+
efi_runtime_lock_owner = current;
arch_efi_call_virt_setup();
@@ -312,6 +336,9 @@ static void __nocfi efi_call_rts(struct work_struct *work)
efi_call_virt_check_flags(flags, efi_rts_work.caller);
arch_efi_call_virt_teardown();
+ if (!efi_enabled(EFI_RUNTIME_SERVICES))
+ efi_rts_park_worker();
+
efi_rts_work.status = status;
complete(&efi_rts_work.efi_rts_comp);
efi_runtime_lock_owner = NULL;
@@ -320,17 +347,16 @@ static void __nocfi efi_call_rts(struct work_struct *work)
static efi_status_t __efi_queue_work(enum efi_rts_ids id,
union efi_rts_args *args)
{
+ if (!efi_enabled(EFI_RUNTIME_SERVICES)) {
+ pr_warn_once("EFI Runtime Services are disabled!\n");
+ return EFI_DEVICE_ERROR;
+ }
+
efi_rts_work.efi_rts_id = id;
efi_rts_work.args = args;
efi_rts_work.caller = __builtin_return_address(0);
efi_rts_work.status = EFI_ABORTED;
- if (!efi_enabled(EFI_RUNTIME_SERVICES)) {
- pr_warn_once("EFI Runtime Services are disabled!\n");
- efi_rts_work.status = EFI_DEVICE_ERROR;
- goto exit;
- }
-
init_completion(&efi_rts_work.efi_rts_comp);
INIT_WORK(&efi_rts_work.work, efi_call_rts);
@@ -338,10 +364,18 @@ static efi_status_t __efi_queue_work(enum efi_rts_ids id,
* queue_work() returns 0 if work was already on queue,
* _ideally_ this should never happen.
*/
- if (queue_work(efi_rts_wq, &efi_rts_work.work))
- wait_for_completion(&efi_rts_work.efi_rts_comp);
- else
+ if (!queue_work(efi_rts_wq, &efi_rts_work.work)) {
pr_err("Failed to queue work to efi_rts_wq.\n");
+ goto exit;
+ }
+
+ if (!wait_for_completion_timeout(&efi_rts_work.efi_rts_comp,
+ EFI_RTS_TIMEOUT)) {
+ pr_err("EFI runtime service %d wedged in firmware; disabling EFI runtime services\n",
+ id);
+ clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
+ return EFI_ABORTED;
+ }
WARN_ON_ONCE(efi_rts_work.status == EFI_ABORTED);
exit:
@@ -449,6 +483,11 @@ virt_efi_set_variable_nb(efi_char16_t *name, efi_guid_t *vendor, u32 attr,
if (down_trylock(&efi_runtime_lock))
return EFI_NOT_READY;
+ if (!efi_enabled(EFI_RUNTIME_SERVICES)) {
+ up(&efi_runtime_lock);
+ return EFI_DEVICE_ERROR;
+ }
+
efi_runtime_lock_owner = current;
status = efi_call_virt_pointer(efi.runtime, set_variable, name, vendor,
attr, data_size, data);
@@ -488,6 +527,11 @@ virt_efi_query_variable_info_nb(u32 attr, u64 *storage_space,
if (down_trylock(&efi_runtime_lock))
return EFI_NOT_READY;
+ if (!efi_enabled(EFI_RUNTIME_SERVICES)) {
+ up(&efi_runtime_lock);
+ return EFI_DEVICE_ERROR;
+ }
+
efi_runtime_lock_owner = current;
status = efi_call_virt_pointer(efi.runtime, query_variable_info, attr,
storage_space, remaining_space,
@@ -518,6 +562,12 @@ virt_efi_reset_system(int reset_type, efi_status_t status,
return;
}
+ if (!efi_enabled(EFI_RUNTIME_SERVICES)) {
+ pr_warn("EFI Runtime Services are disabled, not invoking reset_system()\n");
+ up(&efi_runtime_lock);
+ return;
+ }
+
efi_runtime_lock_owner = current;
arch_efi_call_virt_setup();
efi_rts_work.efi_rts_id = EFI_RESET_SYSTEM;
diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig
index b477d54b495a..c7f8413ab996 100644
--- a/drivers/firmware/qcom/Kconfig
+++ b/drivers/firmware/qcom/Kconfig
@@ -6,9 +6,29 @@
menu "Qualcomm firmware drivers"
+config QCOM_PAS
+ tristate "Qualcomm generic PAS interface driver"
+ help
+ Enable the generic Peripheral Authentication Service (PAS) provided
+ by the firmware. It acts as the common layer with different TZ
+ backends plugged in whether it's an SCM implementation or a proper
+ TEE bus based PAS service implementation.
+
+config QCOM_PAS_TEE
+ tristate "Qualcomm PAS TEE interface driver"
+ select QCOM_PAS
+ depends on TEE
+ depends on !CPU_BIG_ENDIAN
+ default m if ARCH_QCOM
+ help
+ Enable the generic Peripheral Authentication Service (PAS) provided
+ by the firmware TEE implementation as the backend.
+
config QCOM_SCM
+ tristate "Qualcomm PAS SCM interface driver"
+ select QCOM_PAS
select QCOM_TZMEM
- tristate
+ default y if ARCH_QCOM
config QCOM_TZMEM
tristate
diff --git a/drivers/firmware/qcom/Makefile b/drivers/firmware/qcom/Makefile
index 0be40a1abc13..48801d18f37b 100644
--- a/drivers/firmware/qcom/Makefile
+++ b/drivers/firmware/qcom/Makefile
@@ -8,3 +8,5 @@ qcom-scm-objs += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o
obj-$(CONFIG_QCOM_TZMEM) += qcom_tzmem.o
obj-$(CONFIG_QCOM_QSEECOM) += qcom_qseecom.o
obj-$(CONFIG_QCOM_QSEECOM_UEFISECAPP) += qcom_qseecom_uefisecapp.o
+obj-$(CONFIG_QCOM_PAS) += qcom_pas.o
+obj-$(CONFIG_QCOM_PAS_TEE) += qcom_pas_tee.o
diff --git a/drivers/firmware/qcom/qcom_pas.c b/drivers/firmware/qcom/qcom_pas.c
new file mode 100644
index 000000000000..24485dd0fa10
--- /dev/null
+++ b/drivers/firmware/qcom/qcom_pas.c
@@ -0,0 +1,298 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2010,2015,2019 The Linux Foundation. All rights reserved.
+ * Copyright (C) 2015 Linaro Ltd.
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/device/devres.h>
+#include <linux/firmware/qcom/qcom_pas.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "qcom_pas.h"
+
+static struct qcom_pas_ops *ops_ptr;
+
+/**
+ * devm_qcom_pas_context_alloc() - Allocate peripheral authentication service
+ * context for a given peripheral
+ *
+ * PAS context is device-resource managed, so the caller does not need
+ * to worry about freeing the context memory.
+ *
+ * @dev: PAS firmware device
+ * @pas_id: peripheral authentication service id
+ * @mem_phys: Subsystem reserve memory start address
+ * @mem_size: Subsystem reserve memory size
+ *
+ * Return: The new PAS context, or ERR_PTR() on failure.
+ */
+struct qcom_pas_context *devm_qcom_pas_context_alloc(struct device *dev,
+ u32 pas_id,
+ phys_addr_t mem_phys,
+ size_t mem_size)
+{
+ struct qcom_pas_context *ctx;
+
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return ERR_PTR(-ENOMEM);
+
+ ctx->dev = dev;
+ ctx->pas_id = pas_id;
+ ctx->mem_phys = mem_phys;
+ ctx->mem_size = mem_size;
+
+ return ctx;
+}
+EXPORT_SYMBOL_GPL(devm_qcom_pas_context_alloc);
+
+/**
+ * qcom_pas_init_image() - Initialize peripheral authentication service state
+ * machine for a given peripheral, using the metadata
+ * @pas_id: peripheral authentication service id
+ * @metadata: pointer to memory containing ELF header, program header table
+ * and optional blob of data used for authenticating the metadata
+ * and the rest of the firmware
+ * @size: size of the metadata
+ * @ctx: optional pas context
+ *
+ * Return: 0 on success.
+ *
+ * Upon successful return, the PAS metadata context (@ctx) will be used to
+ * track the metadata allocation, this needs to be released by invoking
+ * qcom_pas_metadata_release() by the caller.
+ */
+int qcom_pas_init_image(u32 pas_id, const void *metadata, size_t size,
+ struct qcom_pas_context *ctx)
+{
+ if (!ops_ptr)
+ return -ENODEV;
+
+ return ops_ptr->init_image(ops_ptr->dev, pas_id, metadata, size, ctx);
+}
+EXPORT_SYMBOL_GPL(qcom_pas_init_image);
+
+/**
+ * qcom_pas_metadata_release() - release metadata context
+ * @ctx: pas context
+ */
+void qcom_pas_metadata_release(struct qcom_pas_context *ctx)
+{
+ if (!ops_ptr || !ctx || !ctx->ptr)
+ return;
+
+ ops_ptr->metadata_release(ops_ptr->dev, ctx);
+}
+EXPORT_SYMBOL_GPL(qcom_pas_metadata_release);
+
+/**
+ * qcom_pas_mem_setup() - Prepare the memory related to a given peripheral
+ * for firmware loading
+ * @pas_id: peripheral authentication service id
+ * @addr: start address of memory area to prepare
+ * @size: size of the memory area to prepare
+ *
+ * Return: 0 on success.
+ */
+int qcom_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size)
+{
+ if (!ops_ptr)
+ return -ENODEV;
+
+ return ops_ptr->mem_setup(ops_ptr->dev, pas_id, addr, size);
+}
+EXPORT_SYMBOL_GPL(qcom_pas_mem_setup);
+
+/**
+ * qcom_pas_get_rsc_table() - Retrieve the resource table in passed output buffer
+ * for a given peripheral.
+ *
+ * Qualcomm remote processor may rely on both static and dynamic resources for
+ * its functionality. Static resources typically refer to memory-mapped
+ * addresses required by the subsystem and are often embedded within the
+ * firmware binary and dynamic resources, such as shared memory in DDR etc.,
+ * are determined at runtime during the boot process.
+ *
+ * On Qualcomm Technologies devices, it's possible that static resources are
+ * not embedded in the firmware binary and instead are provided by TrustZone.
+ * However, dynamic resources are always expected to come from TrustZone. This
+ * indicates that for Qualcomm devices, all resources (static and dynamic) will
+ * be provided by TrustZone PAS service.
+ *
+ * If the remote processor firmware binary does contain static resources, they
+ * should be passed in input_rt. These will be forwarded to TrustZone for
+ * authentication. TrustZone will then append the dynamic resources and return
+ * the complete resource table in output_rt_tzm.
+ *
+ * If the remote processor firmware binary does not include a resource table,
+ * the caller of this function should set input_rt as NULL and input_rt_size
+ * as zero respectively.
+ *
+ * More about documentation on resource table data structures can be found in
+ * include/linux/remoteproc.h
+ *
+ * @ctx: PAS context
+ * @input_rt: resource table buffer which is present in firmware binary
+ * @input_rt_size: size of the resource table present in firmware binary
+ * @output_rt_size: TrustZone expects caller should pass worst case size for
+ * the output_rt_tzm.
+ *
+ * Return:
+ * On success, returns a pointer to the allocated buffer containing the final
+ * resource table and output_rt_size will have actual resource table size from
+ * TrustZone. The caller is responsible for freeing the buffer. On failure,
+ * returns ERR_PTR(-errno).
+ */
+struct resource_table *qcom_pas_get_rsc_table(struct qcom_pas_context *ctx,
+ void *input_rt,
+ size_t input_rt_size,
+ size_t *output_rt_size)
+{
+ if (!ops_ptr)
+ return ERR_PTR(-ENODEV);
+ if (!ctx)
+ return ERR_PTR(-EINVAL);
+
+ return ops_ptr->get_rsc_table(ops_ptr->dev, ctx, input_rt,
+ input_rt_size, output_rt_size);
+}
+EXPORT_SYMBOL_GPL(qcom_pas_get_rsc_table);
+
+/**
+ * qcom_pas_auth_and_reset() - Authenticate the given peripheral firmware
+ * and reset the remote processor
+ * @pas_id: peripheral authentication service id
+ *
+ * Return: 0 on success.
+ */
+int qcom_pas_auth_and_reset(u32 pas_id)
+{
+ if (!ops_ptr)
+ return -ENODEV;
+
+ return ops_ptr->auth_and_reset(ops_ptr->dev, pas_id);
+}
+EXPORT_SYMBOL_GPL(qcom_pas_auth_and_reset);
+
+/**
+ * qcom_pas_prepare_and_auth_reset() - Prepare, authenticate, and reset the
+ * remote processor
+ *
+ * @ctx: Context saved during call to devm_qcom_pas_context_alloc()
+ *
+ * This function performs the necessary steps to prepare a PAS subsystem,
+ * authenticate it using the provided metadata, and initiate a reset sequence.
+ *
+ * It should be used when Linux is in control setting up the IOMMU hardware
+ * for remote subsystem during secure firmware loading processes. The
+ * preparation step sets up a shmbridge over the firmware memory before
+ * TrustZone accesses the firmware memory region for authentication. The
+ * authentication step verifies the integrity and authenticity of the firmware
+ * or configuration using secure metadata. Finally, the reset step ensures the
+ * subsystem starts in a clean and sane state.
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int qcom_pas_prepare_and_auth_reset(struct qcom_pas_context *ctx)
+{
+ if (!ops_ptr)
+ return -ENODEV;
+ if (!ctx)
+ return -EINVAL;
+
+ return ops_ptr->prepare_and_auth_reset(ops_ptr->dev, ctx);
+}
+EXPORT_SYMBOL_GPL(qcom_pas_prepare_and_auth_reset);
+
+/**
+ * qcom_pas_set_remote_state() - Set the remote processor state
+ * @state: peripheral state
+ * @pas_id: peripheral authentication service id
+ *
+ * Return: 0 on success.
+ */
+int qcom_pas_set_remote_state(u32 state, u32 pas_id)
+{
+ if (!ops_ptr)
+ return -ENODEV;
+
+ return ops_ptr->set_remote_state(ops_ptr->dev, state, pas_id);
+}
+EXPORT_SYMBOL_GPL(qcom_pas_set_remote_state);
+
+/**
+ * qcom_pas_shutdown() - Shut down the remote processor
+ * @pas_id: peripheral authentication service id
+ *
+ * Return: 0 on success.
+ */
+int qcom_pas_shutdown(u32 pas_id)
+{
+ if (!ops_ptr)
+ return -ENODEV;
+
+ return ops_ptr->shutdown(ops_ptr->dev, pas_id);
+}
+EXPORT_SYMBOL_GPL(qcom_pas_shutdown);
+
+/**
+ * qcom_pas_supported() - Check if the peripheral authentication service is
+ * supported for the given peripheral
+ * @pas_id: peripheral authentication service id
+ *
+ * Return: true if PAS is supported for this peripheral, otherwise false.
+ */
+bool qcom_pas_supported(u32 pas_id)
+{
+ if (!ops_ptr)
+ return false;
+
+ return ops_ptr->supported(ops_ptr->dev, pas_id);
+}
+EXPORT_SYMBOL_GPL(qcom_pas_supported);
+
+/**
+ * qcom_pas_is_available() - Check if the peripheral authentication service is
+ * available. Note that it is mandatory for any PAS
+ * client to invoke this API. If it returns true then
+ * only any other PAS API can be invoked.
+ *
+ * Return: true if PAS is available, otherwise false.
+ */
+bool qcom_pas_is_available(void)
+{
+ /*
+ * The barrier for ops_ptr is intended to synchronize the data stores
+ * for the ops data structure when client drivers are in parallel
+ * checking for PAS service availability.
+ *
+ * Once the PAS backend becomes available, it is allowed for multiple
+ * threads to enter TZ for parallel bringup of co-processors during
+ * boot.
+ */
+ return !!smp_load_acquire(&ops_ptr);
+}
+EXPORT_SYMBOL_GPL(qcom_pas_is_available);
+
+void qcom_pas_ops_register(struct qcom_pas_ops *ops)
+{
+ if (!qcom_pas_is_available())
+ /* Paired with smp_load_acquire() in qcom_pas_is_available() */
+ smp_store_release(&ops_ptr, ops);
+ else
+ pr_err("qcom_pas: ops already registered by %s\n",
+ ops_ptr->drv_name);
+}
+EXPORT_SYMBOL_GPL(qcom_pas_ops_register);
+
+void qcom_pas_ops_unregister(void)
+{
+ /* Paired with smp_load_acquire() in qcom_pas_is_available() */
+ smp_store_release(&ops_ptr, NULL);
+}
+EXPORT_SYMBOL_GPL(qcom_pas_ops_unregister);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Qualcomm generic TZ PAS driver");
diff --git a/drivers/firmware/qcom/qcom_pas.h b/drivers/firmware/qcom/qcom_pas.h
new file mode 100644
index 000000000000..8643e2760602
--- /dev/null
+++ b/drivers/firmware/qcom/qcom_pas.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef __QCOM_PAS_INT_H
+#define __QCOM_PAS_INT_H
+
+struct device;
+
+/**
+ * struct qcom_pas_ops - Qcom Peripheral Authentication Service (PAS) ops
+ * @drv_name: PAS driver name.
+ * @dev: PAS device pointer.
+ * @supported: Peripheral supported callback.
+ * @init_image: Peripheral image initialization callback.
+ * @mem_setup: Peripheral memory setup callback.
+ * @get_rsc_table: Peripheral get resource table callback.
+ * @prepare_and_auth_reset: Peripheral prepare firmware authentication and
+ * reset callback.
+ * @auth_and_reset: Peripheral firmware authentication and reset
+ * callback.
+ * @set_remote_state: Peripheral set remote state callback.
+ * @shutdown: Peripheral shutdown callback.
+ * @metadata_release: Image metadata release callback.
+ */
+struct qcom_pas_ops {
+ const char *drv_name;
+ struct device *dev;
+ bool (*supported)(struct device *dev, u32 pas_id);
+ int (*init_image)(struct device *dev, u32 pas_id, const void *metadata,
+ size_t size, struct qcom_pas_context *ctx);
+ int (*mem_setup)(struct device *dev, u32 pas_id, phys_addr_t addr,
+ phys_addr_t size);
+ void *(*get_rsc_table)(struct device *dev, struct qcom_pas_context *ctx,
+ void *input_rt, size_t input_rt_size,
+ size_t *output_rt_size);
+ int (*prepare_and_auth_reset)(struct device *dev,
+ struct qcom_pas_context *ctx);
+ int (*auth_and_reset)(struct device *dev, u32 pas_id);
+ int (*set_remote_state)(struct device *dev, u32 state, u32 pas_id);
+ int (*shutdown)(struct device *dev, u32 pas_id);
+ void (*metadata_release)(struct device *dev,
+ struct qcom_pas_context *ctx);
+};
+
+void qcom_pas_ops_register(struct qcom_pas_ops *ops);
+void qcom_pas_ops_unregister(void);
+
+#endif /* __QCOM_PAS_INT_H */
diff --git a/drivers/firmware/qcom/qcom_pas_tee.c b/drivers/firmware/qcom/qcom_pas_tee.c
new file mode 100644
index 000000000000..ac33a00687aa
--- /dev/null
+++ b/drivers/firmware/qcom/qcom_pas_tee.c
@@ -0,0 +1,479 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/firmware/qcom/qcom_pas.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/tee_drv.h>
+#include <linux/uuid.h>
+
+#include "qcom_pas.h"
+
+/*
+ * Peripheral Authentication Service (PAS) supported.
+ *
+ * [in] params[0].value.a: Unique 32bit remote processor identifier
+ */
+#define TA_QCOM_PAS_IS_SUPPORTED 1
+
+/*
+ * PAS capabilities.
+ *
+ * [in] params[0].value.a: Unique 32bit remote processor identifier
+ * [out] params[1].value.a: PAS capability flags
+ */
+#define TA_QCOM_PAS_CAPABILITIES 2
+
+/*
+ * PAS image initialization.
+ *
+ * [in] params[0].value.a: Unique 32bit remote processor identifier
+ * [in] params[1].memref: Loadable firmware metadata
+ */
+#define TA_QCOM_PAS_INIT_IMAGE 3
+
+/*
+ * PAS memory setup.
+ *
+ * [in] params[0].value.a: Unique 32bit remote processor identifier
+ * [in] params[0].value.b: Relocatable firmware size
+ * [in] params[1].value.a: 32bit LSB relocatable firmware memory address
+ * [in] params[1].value.b: 32bit MSB relocatable firmware memory address
+ */
+#define TA_QCOM_PAS_MEM_SETUP 4
+
+/*
+ * PAS get resource table.
+ *
+ * [in] params[0].value.a: Unique 32bit remote processor identifier
+ * [inout] params[1].memref: Resource table config
+ */
+#define TA_QCOM_PAS_GET_RESOURCE_TABLE 5
+
+/*
+ * PAS image authentication and co-processor reset.
+ *
+ * [in] params[0].value.a: Unique 32bit remote processor identifier
+ * [in] params[0].value.b: Firmware size
+ * [in] params[1].value.a: 32bit LSB firmware memory address
+ * [in] params[1].value.b: 32bit MSB firmware memory address
+ * [in] params[2].memref: Optional fw memory space shared/lent
+ */
+#define TA_QCOM_PAS_AUTH_AND_RESET 6
+
+/*
+ * PAS co-processor set suspend/resume state.
+ *
+ * [in] params[0].value.a: Unique 32bit remote processor identifier
+ * [in] params[0].value.b: Co-processor state identifier
+ */
+#define TA_QCOM_PAS_SET_REMOTE_STATE 7
+
+/*
+ * PAS co-processor shutdown.
+ *
+ * [in] params[0].value.a: Unique 32bit remote processor identifier
+ */
+#define TA_QCOM_PAS_SHUTDOWN 8
+
+#define TEE_NUM_PARAMS 4
+
+/**
+ * struct qcom_pas_tee_private - PAS service private data
+ * @dev: PAS service device.
+ * @ctx: TEE context handler.
+ * @session_id: PAS TA session identifier.
+ */
+struct qcom_pas_tee_private {
+ struct device *dev;
+ struct tee_context *ctx;
+ u32 session_id;
+};
+
+static bool qcom_pas_tee_supported(struct device *dev, u32 pas_id)
+{
+ struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
+ struct tee_ioctl_invoke_arg inv_arg = {
+ .func = TA_QCOM_PAS_IS_SUPPORTED,
+ .session = data->session_id,
+ .num_params = TEE_NUM_PARAMS
+ };
+ struct tee_param param[4] = {
+ [0] = {
+ .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
+ .u.value.a = pas_id
+ }
+ };
+ int ret;
+
+ ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
+ if (ret < 0 || inv_arg.ret != 0) {
+ dev_err(dev, "PAS not supported, pas_id: %d, ret: %d, err: 0x%x\n",
+ pas_id, ret, inv_arg.ret);
+ return false;
+ }
+
+ return true;
+}
+
+static int qcom_pas_tee_init_image(struct device *dev, u32 pas_id,
+ const void *metadata, size_t size,
+ struct qcom_pas_context *ctx)
+{
+ struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
+ struct tee_ioctl_invoke_arg inv_arg = {
+ .func = TA_QCOM_PAS_INIT_IMAGE,
+ .session = data->session_id,
+ .num_params = TEE_NUM_PARAMS
+ };
+ struct tee_param param[4] = {
+ [0] = {
+ .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
+ .u.value.a = pas_id
+ },
+ [1] = {
+ .attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT,
+ }
+ };
+ struct tee_shm *mdata_shm;
+ u8 *mdata_buf = NULL;
+ int ret;
+
+ mdata_shm = tee_shm_alloc_kernel_buf(data->ctx, size);
+ if (IS_ERR(mdata_shm)) {
+ dev_err(dev, "mdata_shm allocation failed\n");
+ return PTR_ERR(mdata_shm);
+ }
+
+ mdata_buf = tee_shm_get_va(mdata_shm, 0);
+ if (IS_ERR(mdata_buf)) {
+ dev_err(dev, "mdata_buf get VA failed\n");
+ tee_shm_free(mdata_shm);
+ return PTR_ERR(mdata_buf);
+ }
+ memcpy(mdata_buf, metadata, size);
+
+ param[1].u.memref.shm = mdata_shm;
+ param[1].u.memref.size = size;
+
+ ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
+ if (ret < 0 || inv_arg.ret != 0) {
+ dev_err(dev, "PAS init image failed, pas_id: %d, ret: %d, err: 0x%x\n",
+ pas_id, ret, inv_arg.ret);
+ tee_shm_free(mdata_shm);
+ return ret ?: -EINVAL;
+ }
+
+ if (ctx)
+ ctx->ptr = (void *)mdata_shm;
+ else
+ tee_shm_free(mdata_shm);
+
+ return ret;
+}
+
+static int qcom_pas_tee_mem_setup(struct device *dev, u32 pas_id,
+ phys_addr_t addr, phys_addr_t size)
+{
+ struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
+ struct tee_ioctl_invoke_arg inv_arg = {
+ .func = TA_QCOM_PAS_MEM_SETUP,
+ .session = data->session_id,
+ .num_params = TEE_NUM_PARAMS
+ };
+ struct tee_param param[4] = {
+ [0] = {
+ .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
+ .u.value.a = pas_id,
+ .u.value.b = size,
+ },
+ [1] = {
+ .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
+ .u.value.a = lower_32_bits(addr),
+ .u.value.b = upper_32_bits(addr),
+ }
+ };
+ int ret;
+
+ ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
+ if (ret < 0 || inv_arg.ret != 0) {
+ dev_err(dev, "PAS mem setup failed, pas_id: %d, ret: %d, err: 0x%x\n",
+ pas_id, ret, inv_arg.ret);
+ return ret ?: -EINVAL;
+ }
+
+ return ret;
+}
+
+DEFINE_FREE(shm_free, struct tee_shm *, tee_shm_free(_T))
+
+static void *qcom_pas_tee_get_rsc_table(struct device *dev,
+ struct qcom_pas_context *ctx,
+ void *input_rt, size_t input_rt_size,
+ size_t *output_rt_size)
+{
+ struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
+ struct tee_ioctl_invoke_arg inv_arg = {
+ .func = TA_QCOM_PAS_GET_RESOURCE_TABLE,
+ .session = data->session_id,
+ .num_params = TEE_NUM_PARAMS
+ };
+ struct tee_param param[4] = {
+ [0] = {
+ .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
+ .u.value.a = ctx->pas_id,
+ },
+ [1] = {
+ .attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT,
+ .u.memref.size = input_rt_size,
+ }
+ };
+ void *rt_buf = NULL;
+ int ret;
+
+ ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
+ if (ret < 0 || inv_arg.ret != 0) {
+ dev_err(dev, "PAS get RT failed, pas_id: %d, ret: %d, err: 0x%x\n",
+ ctx->pas_id, ret, inv_arg.ret);
+ return ret ? ERR_PTR(ret) : ERR_PTR(-EINVAL);
+ }
+
+ if (param[1].u.memref.size >= input_rt_size) {
+ struct tee_shm *rt_shm __free(shm_free) =
+ tee_shm_alloc_kernel_buf(data->ctx,
+ param[1].u.memref.size);
+ void *rt_shm_va;
+
+ if (IS_ERR_OR_NULL(rt_shm)) {
+ dev_err(dev, "rt_shm allocation failed\n");
+ rt_shm = NULL;
+ return ERR_PTR(-ENOMEM);
+ }
+
+ rt_shm_va = tee_shm_get_va(rt_shm, 0);
+ if (IS_ERR(rt_shm_va)) {
+ dev_err(dev, "rt_shm get VA failed\n");
+ return ERR_CAST(rt_shm_va);
+ }
+ memcpy(rt_shm_va, input_rt, input_rt_size);
+
+ param[1].u.memref.shm = rt_shm;
+ ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
+ if (ret < 0 || inv_arg.ret != 0) {
+ dev_err(dev, "PAS get RT failed, pas_id: %d, ret: %d, err: 0x%x\n",
+ ctx->pas_id, ret, inv_arg.ret);
+ return ret ? ERR_PTR(ret) : ERR_PTR(-EINVAL);
+ }
+
+ if (param[1].u.memref.size) {
+ *output_rt_size = param[1].u.memref.size;
+ rt_buf = kmemdup(rt_shm_va, *output_rt_size, GFP_KERNEL);
+ if (!rt_buf)
+ return ERR_PTR(-ENOMEM);
+ }
+ } else {
+ *output_rt_size = 0;
+ }
+
+ return rt_buf;
+}
+
+static int __qcom_pas_tee_auth_and_reset(struct device *dev, u32 pas_id,
+ phys_addr_t mem_phys, size_t mem_size)
+{
+ struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
+ struct tee_ioctl_invoke_arg inv_arg = {
+ .func = TA_QCOM_PAS_AUTH_AND_RESET,
+ .session = data->session_id,
+ .num_params = TEE_NUM_PARAMS
+ };
+ struct tee_param param[4] = {
+ [0] = {
+ .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
+ .u.value.a = pas_id,
+ .u.value.b = mem_size,
+ },
+ [1] = {
+ .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
+ .u.value.a = lower_32_bits(mem_phys),
+ .u.value.b = upper_32_bits(mem_phys),
+ },
+ /* Reserved for fw memory space to be shared or lent */
+ [2] = {
+ .attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT,
+ }
+ };
+ int ret;
+
+ ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
+ if (ret < 0 || inv_arg.ret != 0) {
+ dev_err(dev, "PAS auth reset failed, pas_id: %d, ret: %d, err: 0x%x\n",
+ pas_id, ret, inv_arg.ret);
+ return ret ?: -EINVAL;
+ }
+
+ return ret;
+}
+
+static int qcom_pas_tee_auth_and_reset(struct device *dev, u32 pas_id)
+{
+ return __qcom_pas_tee_auth_and_reset(dev, pas_id, 0, 0);
+}
+
+static int qcom_pas_tee_prepare_and_auth_reset(struct device *dev,
+ struct qcom_pas_context *ctx)
+{
+ return __qcom_pas_tee_auth_and_reset(dev, ctx->pas_id, ctx->mem_phys,
+ ctx->mem_size);
+}
+
+static int qcom_pas_tee_set_remote_state(struct device *dev, u32 state,
+ u32 pas_id)
+{
+ struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
+ struct tee_ioctl_invoke_arg inv_arg = {
+ .func = TA_QCOM_PAS_SET_REMOTE_STATE,
+ .session = data->session_id,
+ .num_params = TEE_NUM_PARAMS
+ };
+ struct tee_param param[4] = {
+ [0] = {
+ .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
+ .u.value.a = pas_id,
+ .u.value.b = state,
+ }
+ };
+ int ret;
+
+ ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
+ if (ret < 0 || inv_arg.ret != 0) {
+ dev_err(dev, "PAS set remote state failed, pas_id: %d, ret: %d, err: 0x%x\n",
+ pas_id, ret, inv_arg.ret);
+ return ret ?: -EINVAL;
+ }
+
+ return ret;
+}
+
+static int qcom_pas_tee_shutdown(struct device *dev, u32 pas_id)
+{
+ struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
+ struct tee_ioctl_invoke_arg inv_arg = {
+ .func = TA_QCOM_PAS_SHUTDOWN,
+ .session = data->session_id,
+ .num_params = TEE_NUM_PARAMS
+ };
+ struct tee_param param[4] = {
+ [0] = {
+ .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
+ .u.value.a = pas_id
+ }
+ };
+ int ret;
+
+ ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
+ if (ret < 0 || inv_arg.ret != 0) {
+ dev_err(dev, "PAS shutdown failed, pas_id: %d, ret: %d, err: 0x%x\n",
+ pas_id, ret, inv_arg.ret);
+ return ret ?: -EINVAL;
+ }
+
+ return ret;
+}
+
+static void qcom_pas_tee_metadata_release(struct device *dev,
+ struct qcom_pas_context *ctx)
+{
+ struct tee_shm *mdata_shm = ctx->ptr;
+
+ tee_shm_free(mdata_shm);
+ ctx->ptr = NULL;
+}
+
+static struct qcom_pas_ops qcom_pas_ops_tee = {
+ .drv_name = "qcom-pas-tee",
+ .supported = qcom_pas_tee_supported,
+ .init_image = qcom_pas_tee_init_image,
+ .mem_setup = qcom_pas_tee_mem_setup,
+ .get_rsc_table = qcom_pas_tee_get_rsc_table,
+ .auth_and_reset = qcom_pas_tee_auth_and_reset,
+ .prepare_and_auth_reset = qcom_pas_tee_prepare_and_auth_reset,
+ .set_remote_state = qcom_pas_tee_set_remote_state,
+ .shutdown = qcom_pas_tee_shutdown,
+ .metadata_release = qcom_pas_tee_metadata_release,
+};
+
+static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
+{
+ return ver->impl_id == TEE_IMPL_ID_OPTEE;
+}
+
+static int qcom_pas_tee_probe(struct tee_client_device *pas_dev)
+{
+ struct device *dev = &pas_dev->dev;
+ struct qcom_pas_tee_private *data;
+ struct tee_ioctl_open_session_arg sess_arg = {
+ .clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL
+ };
+ int ret;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL);
+ if (IS_ERR(data->ctx))
+ return -ENODEV;
+
+ export_uuid(sess_arg.uuid, &pas_dev->id.uuid);
+ ret = tee_client_open_session(data->ctx, &sess_arg, NULL);
+ if (ret < 0 || sess_arg.ret != 0) {
+ dev_err(dev, "tee_client_open_session failed, ret: %d, err: 0x%x\n",
+ ret, sess_arg.ret);
+ tee_client_close_context(data->ctx);
+ return ret ?: -EINVAL;
+ }
+
+ data->session_id = sess_arg.session;
+ dev_set_drvdata(dev, data);
+ qcom_pas_ops_tee.dev = dev;
+ qcom_pas_ops_register(&qcom_pas_ops_tee);
+
+ return ret;
+}
+
+static void qcom_pas_tee_remove(struct tee_client_device *pas_dev)
+{
+ struct device *dev = &pas_dev->dev;
+ struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
+
+ qcom_pas_ops_unregister();
+ tee_client_close_session(data->ctx, data->session_id);
+ tee_client_close_context(data->ctx);
+}
+
+static const struct tee_client_device_id qcom_pas_tee_id_table[] = {
+ {UUID_INIT(0xcff7d191, 0x7ca0, 0x4784,
+ 0xaf, 0x13, 0x48, 0x22, 0x3b, 0x9a, 0x4f, 0xbe)},
+ {}
+};
+MODULE_DEVICE_TABLE(tee, qcom_pas_tee_id_table);
+
+static struct tee_client_driver optee_pas_tee_driver = {
+ .probe = qcom_pas_tee_probe,
+ .remove = qcom_pas_tee_remove,
+ .id_table = qcom_pas_tee_id_table,
+ .driver = {
+ .name = "qcom-pas-tee",
+ },
+};
+
+module_tee_client_driver(optee_pas_tee_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Qualcomm PAS TEE driver");
diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c
index 6b601a4b89db..7933e55803dc 100644
--- a/drivers/firmware/qcom/qcom_scm.c
+++ b/drivers/firmware/qcom/qcom_scm.c
@@ -13,6 +13,7 @@
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/export.h>
+#include <linux/firmware/qcom/qcom_pas.h>
#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/firmware/qcom/qcom_tzmem.h>
#include <linux/init.h>
@@ -33,6 +34,7 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include "qcom_pas.h"
#include "qcom_scm.h"
#include "qcom_tzmem.h"
@@ -479,25 +481,6 @@ void qcom_scm_cpu_power_down(u32 flags)
}
EXPORT_SYMBOL_GPL(qcom_scm_cpu_power_down);
-int qcom_scm_set_remote_state(u32 state, u32 id)
-{
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_BOOT,
- .cmd = QCOM_SCM_BOOT_SET_REMOTE_STATE,
- .arginfo = QCOM_SCM_ARGS(2),
- .args[0] = state,
- .args[1] = id,
- .owner = ARM_SMCCC_OWNER_SIP,
- };
- struct qcom_scm_res res;
- int ret;
-
- ret = qcom_scm_call(__scm->dev, &desc, &res);
-
- return ret ? : res.result[0];
-}
-EXPORT_SYMBOL_GPL(qcom_scm_set_remote_state);
-
static int qcom_scm_disable_sdi(void)
{
int ret;
@@ -570,26 +553,12 @@ static void qcom_scm_set_download_mode(u32 dload_mode)
dev_err(__scm->dev, "failed to set download mode: %d\n", ret);
}
-/**
- * devm_qcom_scm_pas_context_alloc() - Allocate peripheral authentication service
- * context for a given peripheral
- *
- * PAS context is device-resource managed, so the caller does not need
- * to worry about freeing the context memory.
- *
- * @dev: PAS firmware device
- * @pas_id: peripheral authentication service id
- * @mem_phys: Subsystem reserve memory start address
- * @mem_size: Subsystem reserve memory size
- *
- * Returns: The new PAS context, or ERR_PTR() on failure.
- */
struct qcom_scm_pas_context *devm_qcom_scm_pas_context_alloc(struct device *dev,
u32 pas_id,
phys_addr_t mem_phys,
size_t mem_size)
{
- struct qcom_scm_pas_context *ctx;
+ struct qcom_pas_context *ctx;
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
@@ -600,11 +569,12 @@ struct qcom_scm_pas_context *devm_qcom_scm_pas_context_alloc(struct device *dev,
ctx->mem_phys = mem_phys;
ctx->mem_size = mem_size;
- return ctx;
+ return (struct qcom_scm_pas_context *)ctx;
}
EXPORT_SYMBOL_GPL(devm_qcom_scm_pas_context_alloc);
-static int __qcom_scm_pas_init_image(u32 pas_id, dma_addr_t mdata_phys,
+static int __qcom_scm_pas_init_image(struct device *dev, u32 pas_id,
+ dma_addr_t mdata_phys,
struct qcom_scm_res *res)
{
struct qcom_scm_desc desc = {
@@ -626,7 +596,7 @@ static int __qcom_scm_pas_init_image(u32 pas_id, dma_addr_t mdata_phys,
desc.args[1] = mdata_phys;
- ret = qcom_scm_call(__scm->dev, &desc, res);
+ ret = qcom_scm_call(dev, &desc, res);
qcom_scm_bw_disable();
disable_clk:
@@ -635,7 +605,8 @@ disable_clk:
return ret;
}
-static int qcom_scm_pas_prep_and_init_image(struct qcom_scm_pas_context *ctx,
+static int qcom_scm_pas_prep_and_init_image(struct device *dev,
+ struct qcom_pas_context *ctx,
const void *metadata, size_t size)
{
struct qcom_scm_res res;
@@ -650,7 +621,7 @@ static int qcom_scm_pas_prep_and_init_image(struct qcom_scm_pas_context *ctx,
memcpy(mdata_buf, metadata, size);
mdata_phys = qcom_tzmem_to_phys(mdata_buf);
- ret = __qcom_scm_pas_init_image(ctx->pas_id, mdata_phys, &res);
+ ret = __qcom_scm_pas_init_image(dev, ctx->pas_id, mdata_phys, &res);
if (ret < 0)
qcom_tzmem_free(mdata_buf);
else
@@ -659,25 +630,9 @@ static int qcom_scm_pas_prep_and_init_image(struct qcom_scm_pas_context *ctx,
return ret ? : res.result[0];
}
-/**
- * qcom_scm_pas_init_image() - Initialize peripheral authentication service
- * state machine for a given peripheral, using the
- * metadata
- * @pas_id: peripheral authentication service id
- * @metadata: pointer to memory containing ELF header, program header table
- * and optional blob of data used for authenticating the metadata
- * and the rest of the firmware
- * @size: size of the metadata
- * @ctx: optional pas context
- *
- * Return: 0 on success.
- *
- * Upon successful return, the PAS metadata context (@ctx) will be used to
- * track the metadata allocation, this needs to be released by invoking
- * qcom_scm_pas_metadata_release() by the caller.
- */
-int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size,
- struct qcom_scm_pas_context *ctx)
+static int __qcom_scm_pas_init_image2(struct device *dev, u32 pas_id,
+ const void *metadata, size_t size,
+ struct qcom_pas_context *ctx)
{
struct qcom_scm_res res;
dma_addr_t mdata_phys;
@@ -685,7 +640,7 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size,
int ret;
if (ctx && ctx->use_tzmem)
- return qcom_scm_pas_prep_and_init_image(ctx, metadata, size);
+ return qcom_scm_pas_prep_and_init_image(dev, ctx, metadata, size);
/*
* During the scm call memory protection will be enabled for the meta
@@ -699,16 +654,15 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size,
* If we pass a buffer that is already part of an SHM Bridge to this
* call, it will fail.
*/
- mdata_buf = dma_alloc_coherent(__scm->dev, size, &mdata_phys,
- GFP_KERNEL);
+ mdata_buf = dma_alloc_coherent(dev, size, &mdata_phys, GFP_KERNEL);
if (!mdata_buf)
return -ENOMEM;
memcpy(mdata_buf, metadata, size);
- ret = __qcom_scm_pas_init_image(pas_id, mdata_phys, &res);
+ ret = __qcom_scm_pas_init_image(dev, pas_id, mdata_phys, &res);
if (ret < 0 || !ctx) {
- dma_free_coherent(__scm->dev, size, mdata_buf, mdata_phys);
+ dma_free_coherent(dev, size, mdata_buf, mdata_phys);
} else if (ctx) {
ctx->ptr = mdata_buf;
ctx->phys = mdata_phys;
@@ -717,36 +671,35 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size,
return ret ? : res.result[0];
}
-EXPORT_SYMBOL_GPL(qcom_scm_pas_init_image);
-/**
- * qcom_scm_pas_metadata_release() - release metadata context
- * @ctx: pas context
- */
-void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx)
+int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size,
+ struct qcom_scm_pas_context *ctx)
{
- if (!ctx->ptr)
- return;
+ return __qcom_scm_pas_init_image2(__scm->dev, pas_id, metadata, size,
+ (struct qcom_pas_context *)ctx);
+}
+EXPORT_SYMBOL_GPL(qcom_scm_pas_init_image);
+static void __qcom_scm_pas_metadata_release(struct device *dev,
+ struct qcom_pas_context *ctx)
+{
if (ctx->use_tzmem)
qcom_tzmem_free(ctx->ptr);
else
- dma_free_coherent(__scm->dev, ctx->size, ctx->ptr, ctx->phys);
+ dma_free_coherent(dev, ctx->size, ctx->ptr, ctx->phys);
ctx->ptr = NULL;
}
+
+void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx)
+{
+ __qcom_scm_pas_metadata_release(__scm->dev,
+ (struct qcom_pas_context *)ctx);
+}
EXPORT_SYMBOL_GPL(qcom_scm_pas_metadata_release);
-/**
- * qcom_scm_pas_mem_setup() - Prepare the memory related to a given peripheral
- * for firmware loading
- * @pas_id: peripheral authentication service id
- * @addr: start address of memory area to prepare
- * @size: size of the memory area to prepare
- *
- * Returns 0 on success.
- */
-int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size)
+static int __qcom_scm_pas_mem_setup(struct device *dev, u32 pas_id,
+ phys_addr_t addr, phys_addr_t size)
{
int ret;
struct qcom_scm_desc desc = {
@@ -768,7 +721,7 @@ int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size)
if (ret)
goto disable_clk;
- ret = qcom_scm_call(__scm->dev, &desc, &res);
+ ret = qcom_scm_call(dev, &desc, &res);
qcom_scm_bw_disable();
disable_clk:
@@ -776,9 +729,15 @@ disable_clk:
return ret ? : res.result[0];
}
+
+int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size)
+{
+ return __qcom_scm_pas_mem_setup(__scm->dev, pas_id, addr, size);
+}
EXPORT_SYMBOL_GPL(qcom_scm_pas_mem_setup);
-static void *__qcom_scm_pas_get_rsc_table(u32 pas_id, void *input_rt_tzm,
+static void *__qcom_scm_pas_get_rsc_table(struct device *dev, u32 pas_id,
+ void *input_rt_tzm,
size_t input_rt_size,
size_t *output_rt_size)
{
@@ -813,7 +772,7 @@ static void *__qcom_scm_pas_get_rsc_table(u32 pas_id, void *input_rt_tzm,
* with output_rt_tzm buffer with res.result[2] size however, It should not
* be of unresonable size.
*/
- ret = qcom_scm_call(__scm->dev, &desc, &res);
+ ret = qcom_scm_call(dev, &desc, &res);
if (!ret && res.result[2] > SZ_1G) {
ret = -E2BIG;
goto free_output_rt;
@@ -830,51 +789,11 @@ free_output_rt:
return ret ? ERR_PTR(ret) : output_rt_tzm;
}
-/**
- * qcom_scm_pas_get_rsc_table() - Retrieve the resource table in passed output buffer
- * for a given peripheral.
- *
- * Qualcomm remote processor may rely on both static and dynamic resources for
- * its functionality. Static resources typically refer to memory-mapped addresses
- * required by the subsystem and are often embedded within the firmware binary
- * and dynamic resources, such as shared memory in DDR etc., are determined at
- * runtime during the boot process.
- *
- * On Qualcomm Technologies devices, it's possible that static resources are not
- * embedded in the firmware binary and instead are provided by TrustZone However,
- * dynamic resources are always expected to come from TrustZone. This indicates
- * that for Qualcomm devices, all resources (static and dynamic) will be provided
- * by TrustZone via the SMC call.
- *
- * If the remote processor firmware binary does contain static resources, they
- * should be passed in input_rt. These will be forwarded to TrustZone for
- * authentication. TrustZone will then append the dynamic resources and return
- * the complete resource table in output_rt_tzm.
- *
- * If the remote processor firmware binary does not include a resource table,
- * the caller of this function should set input_rt as NULL and input_rt_size
- * as zero respectively.
- *
- * More about documentation on resource table data structures can be found in
- * include/linux/remoteproc.h
- *
- * @ctx: PAS context
- * @pas_id: peripheral authentication service id
- * @input_rt: resource table buffer which is present in firmware binary
- * @input_rt_size: size of the resource table present in firmware binary
- * @output_rt_size: TrustZone expects caller should pass worst case size for
- * the output_rt_tzm.
- *
- * Return:
- * On success, returns a pointer to the allocated buffer containing the final
- * resource table and output_rt_size will have actual resource table size from
- * TrustZone. The caller is responsible for freeing the buffer. On failure,
- * returns ERR_PTR(-errno).
- */
-struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *ctx,
- void *input_rt,
- size_t input_rt_size,
- size_t *output_rt_size)
+static void *__qcom_scm_pas_get_rsc_table2(struct device *dev,
+ struct qcom_pas_context *ctx,
+ void *input_rt,
+ size_t input_rt_size,
+ size_t *output_rt_size)
{
struct resource_table empty_rsc = {};
size_t size = SZ_16K;
@@ -909,11 +828,12 @@ struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *c
memcpy(input_rt_tzm, input_rt, input_rt_size);
- output_rt_tzm = __qcom_scm_pas_get_rsc_table(ctx->pas_id, input_rt_tzm,
+ output_rt_tzm = __qcom_scm_pas_get_rsc_table(dev, ctx->pas_id,
+ input_rt_tzm,
input_rt_size, &size);
if (PTR_ERR(output_rt_tzm) == -EOVERFLOW)
/* Try again with the size requested by the TZ */
- output_rt_tzm = __qcom_scm_pas_get_rsc_table(ctx->pas_id,
+ output_rt_tzm = __qcom_scm_pas_get_rsc_table(dev, ctx->pas_id,
input_rt_tzm,
input_rt_size,
&size);
@@ -943,16 +863,20 @@ disable_clk:
return ret ? ERR_PTR(ret) : tbl_ptr;
}
+
+struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *ctx,
+ void *input_rt,
+ size_t input_rt_size,
+ size_t *output_rt_size)
+{
+ return __qcom_scm_pas_get_rsc_table2(__scm->dev,
+ (struct qcom_pas_context *)ctx,
+ input_rt, input_rt_size,
+ output_rt_size);
+}
EXPORT_SYMBOL_GPL(qcom_scm_pas_get_rsc_table);
-/**
- * qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware
- * and reset the remote processor
- * @pas_id: peripheral authentication service id
- *
- * Return 0 on success.
- */
-int qcom_scm_pas_auth_and_reset(u32 pas_id)
+static int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 pas_id)
{
int ret;
struct qcom_scm_desc desc = {
@@ -972,7 +896,7 @@ int qcom_scm_pas_auth_and_reset(u32 pas_id)
if (ret)
goto disable_clk;
- ret = qcom_scm_call(__scm->dev, &desc, &res);
+ ret = qcom_scm_call(dev, &desc, &res);
qcom_scm_bw_disable();
disable_clk:
@@ -980,28 +904,15 @@ disable_clk:
return ret ? : res.result[0];
}
+
+int qcom_scm_pas_auth_and_reset(u32 pas_id)
+{
+ return __qcom_scm_pas_auth_and_reset(__scm->dev, pas_id);
+}
EXPORT_SYMBOL_GPL(qcom_scm_pas_auth_and_reset);
-/**
- * qcom_scm_pas_prepare_and_auth_reset() - Prepare, authenticate, and reset the
- * remote processor
- *
- * @ctx: Context saved during call to qcom_scm_pas_context_init()
- *
- * This function performs the necessary steps to prepare a PAS subsystem,
- * authenticate it using the provided metadata, and initiate a reset sequence.
- *
- * It should be used when Linux is in control setting up the IOMMU hardware
- * for remote subsystem during secure firmware loading processes. The preparation
- * step sets up a shmbridge over the firmware memory before TrustZone accesses the
- * firmware memory region for authentication. The authentication step verifies
- * the integrity and authenticity of the firmware or configuration using secure
- * metadata. Finally, the reset step ensures the subsystem starts in a clean and
- * sane state.
- *
- * Return: 0 on success, negative errno on failure.
- */
-int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx)
+static int __qcom_scm_pas_prepare_and_auth_reset(struct device *dev,
+ struct qcom_pas_context *ctx)
{
u64 handle;
int ret;
@@ -1012,7 +923,7 @@ int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx)
* memory region and then invokes a call to TrustZone to authenticate.
*/
if (!ctx->use_tzmem)
- return qcom_scm_pas_auth_and_reset(ctx->pas_id);
+ return __qcom_scm_pas_auth_and_reset(dev, ctx->pas_id);
/*
* When Linux runs @ EL2 Linux must create the shmbridge itself and then
@@ -1022,20 +933,45 @@ int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx)
if (ret)
return ret;
- ret = qcom_scm_pas_auth_and_reset(ctx->pas_id);
+ ret = __qcom_scm_pas_auth_and_reset(dev, ctx->pas_id);
qcom_tzmem_shm_bridge_delete(handle);
return ret;
}
+
+int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx)
+{
+ return __qcom_scm_pas_prepare_and_auth_reset(__scm->dev,
+ (struct qcom_pas_context *)ctx);
+}
EXPORT_SYMBOL_GPL(qcom_scm_pas_prepare_and_auth_reset);
-/**
- * qcom_scm_pas_shutdown() - Shut down the remote processor
- * @pas_id: peripheral authentication service id
- *
- * Returns 0 on success.
- */
-int qcom_scm_pas_shutdown(u32 pas_id)
+static int __qcom_scm_pas_set_remote_state(struct device *dev, u32 state,
+ u32 pas_id)
+{
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_BOOT,
+ .cmd = QCOM_SCM_BOOT_SET_REMOTE_STATE,
+ .arginfo = QCOM_SCM_ARGS(2),
+ .args[0] = state,
+ .args[1] = pas_id,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
+ struct qcom_scm_res res;
+ int ret;
+
+ ret = qcom_scm_call(dev, &desc, &res);
+
+ return ret ? : res.result[0];
+}
+
+int qcom_scm_set_remote_state(u32 state, u32 id)
+{
+ return __qcom_scm_pas_set_remote_state(__scm->dev, state, id);
+}
+EXPORT_SYMBOL_GPL(qcom_scm_set_remote_state);
+
+static int __qcom_scm_pas_shutdown(struct device *dev, u32 pas_id)
{
int ret;
struct qcom_scm_desc desc = {
@@ -1055,7 +991,7 @@ int qcom_scm_pas_shutdown(u32 pas_id)
if (ret)
goto disable_clk;
- ret = qcom_scm_call(__scm->dev, &desc, &res);
+ ret = qcom_scm_call(dev, &desc, &res);
qcom_scm_bw_disable();
disable_clk:
@@ -1063,16 +999,14 @@ disable_clk:
return ret ? : res.result[0];
}
+
+int qcom_scm_pas_shutdown(u32 pas_id)
+{
+ return __qcom_scm_pas_shutdown(__scm->dev, pas_id);
+}
EXPORT_SYMBOL_GPL(qcom_scm_pas_shutdown);
-/**
- * qcom_scm_pas_supported() - Check if the peripheral authentication service is
- * available for the given peripherial
- * @pas_id: peripheral authentication service id
- *
- * Returns true if PAS is supported for this peripheral, otherwise false.
- */
-bool qcom_scm_pas_supported(u32 pas_id)
+static bool __qcom_scm_pas_supported(struct device *dev, u32 pas_id)
{
int ret;
struct qcom_scm_desc desc = {
@@ -1084,16 +1018,49 @@ bool qcom_scm_pas_supported(u32 pas_id)
};
struct qcom_scm_res res;
- if (!__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL,
+ if (!__qcom_scm_is_call_available(dev, QCOM_SCM_SVC_PIL,
QCOM_SCM_PIL_PAS_IS_SUPPORTED))
return false;
- ret = qcom_scm_call(__scm->dev, &desc, &res);
+ ret = qcom_scm_call(dev, &desc, &res);
return ret ? false : !!res.result[0];
}
+
+bool qcom_scm_pas_supported(u32 pas_id)
+{
+ return __qcom_scm_pas_supported(__scm->dev, pas_id);
+}
EXPORT_SYMBOL_GPL(qcom_scm_pas_supported);
+static struct qcom_pas_ops qcom_pas_ops_scm = {
+ .drv_name = "qcom_scm",
+ .supported = __qcom_scm_pas_supported,
+ .init_image = __qcom_scm_pas_init_image2,
+ .mem_setup = __qcom_scm_pas_mem_setup,
+ .get_rsc_table = __qcom_scm_pas_get_rsc_table2,
+ .auth_and_reset = __qcom_scm_pas_auth_and_reset,
+ .prepare_and_auth_reset = __qcom_scm_pas_prepare_and_auth_reset,
+ .set_remote_state = __qcom_scm_pas_set_remote_state,
+ .shutdown = __qcom_scm_pas_shutdown,
+ .metadata_release = __qcom_scm_pas_metadata_release,
+};
+
+/**
+ * qcom_scm_is_pas_available() - Check if the peripheral authentication service
+ * is available via SCM or not
+ *
+ * Returns true if PAS is available, otherwise false.
+ */
+static bool qcom_scm_is_pas_available(void)
+{
+ if (!__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL,
+ QCOM_SCM_PIL_PAS_AUTH_AND_RESET))
+ return false;
+
+ return true;
+}
+
static int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
{
struct qcom_scm_desc desc = {
@@ -2837,6 +2804,11 @@ static int qcom_scm_probe(struct platform_device *pdev)
__get_convention();
+ if (qcom_scm_is_pas_available()) {
+ qcom_pas_ops_scm.dev = scm->dev;
+ qcom_pas_ops_register(&qcom_pas_ops_scm);
+ }
+
/*
* If "download mode" is requested, from this point on warmboot
* will cause the boot stages to enter download mode, unless
@@ -2876,6 +2848,7 @@ static void qcom_scm_shutdown(struct platform_device *pdev)
{
/* Clean shutdown, disable download mode to allow normal restart */
qcom_scm_set_download_mode(QCOM_DLOAD_NODUMP);
+ qcom_pas_ops_unregister();
}
static const struct of_device_id qcom_scm_dt_match[] = {
diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
index 5b4408fcc10b..8d3acadb0d68 100644
--- a/drivers/gpio/gpio-mvebu.c
+++ b/drivers/gpio/gpio-mvebu.c
@@ -1139,6 +1139,7 @@ static void mvebu_gpio_remove_irq_domain(void *data)
{
struct irq_domain *domain = data;
+ irq_domain_remove_generic_chips(domain);
irq_domain_remove(domain);
}
diff --git a/drivers/gpu/buddy.c b/drivers/gpu/buddy.c
index dc81fe0301ce..3c73ae87f3c5 100644
--- a/drivers/gpu/buddy.c
+++ b/drivers/gpu/buddy.c
@@ -1118,22 +1118,30 @@ static int __gpu_buddy_alloc_range(struct gpu_buddy *mm,
blocks, total_allocated_on_err);
}
+static int __alloc_contig_aligned_retry(struct gpu_buddy *mm,
+ u64 unaligned_offset,
+ u64 size,
+ u64 min_block_size,
+ struct list_head *blocks)
+{
+ u64 aligned_offset = round_down(unaligned_offset, min_block_size);
+
+ return __gpu_buddy_alloc_range(mm, aligned_offset, size, NULL, blocks);
+}
+
static int __alloc_contig_try_harder(struct gpu_buddy *mm,
u64 size,
u64 min_block_size,
struct list_head *blocks)
{
- u64 rhs_offset, lhs_offset, lhs_size, filled;
+ u64 rhs_offset, lhs_offset, filled;
struct gpu_buddy_block *block;
unsigned int tree, order;
- LIST_HEAD(blocks_lhs);
- unsigned long pages;
u64 modify_size;
int err;
modify_size = rounddown_pow_of_two(size);
- pages = modify_size >> ilog2(mm->chunk_size);
- order = fls(pages) - 1;
+ order = ilog2(modify_size) - ilog2(mm->chunk_size);
if (order == 0)
return -ENOSPC;
@@ -1149,31 +1157,48 @@ static int __alloc_contig_try_harder(struct gpu_buddy *mm,
while (iter) {
block = rbtree_get_free_block(iter);
- /* Allocate blocks traversing RHS */
rhs_offset = gpu_buddy_block_offset(block);
+
+ /* Allocate blocks traversing RHS */
err = __gpu_buddy_alloc_range(mm, rhs_offset, size,
&filled, blocks);
- if (!err || err != -ENOSPC)
+ if (err && err != -ENOSPC)
return err;
+ if (!err && IS_ALIGNED(rhs_offset, min_block_size))
+ return 0;
+ if (!err) {
+ /* Allocate the unaligned RHS offset using round_down */
+ gpu_buddy_free_list_internal(mm, blocks);
+ err = __alloc_contig_aligned_retry(mm, rhs_offset,
+ size,
+ min_block_size,
+ blocks);
+ if (!err)
+ return 0;
+ if (err != -ENOSPC) {
+ gpu_buddy_free_list_internal(mm, blocks);
+ return err;
+ }
+ goto next;
+ }
- lhs_size = max((size - filled), min_block_size);
- if (!IS_ALIGNED(lhs_size, min_block_size))
- lhs_size = round_up(lhs_size, min_block_size);
+ if (size - filled > rhs_offset)
+ goto next;
- /* Allocate blocks traversing LHS */
- lhs_offset = gpu_buddy_block_offset(block) - lhs_size;
- err = __gpu_buddy_alloc_range(mm, lhs_offset, lhs_size,
- NULL, &blocks_lhs);
- if (!err) {
- list_splice(&blocks_lhs, blocks);
+ lhs_offset = rhs_offset - (size - filled);
+
+ /* Allocate the unaligned LHS offset using round_down */
+ gpu_buddy_free_list_internal(mm, blocks);
+ err = __alloc_contig_aligned_retry(mm, lhs_offset, size,
+ min_block_size, blocks);
+ if (!err)
return 0;
- } else if (err != -ENOSPC) {
+ if (err != -ENOSPC) {
gpu_buddy_free_list_internal(mm, blocks);
return err;
}
- /* Free blocks for the next iteration */
+next:
gpu_buddy_free_list_internal(mm, blocks);
-
iter = rb_prev(iter);
}
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v11.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v11.c
index 8aa068a4d3e3..724beb96ed1a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v11.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v11.c
@@ -139,7 +139,8 @@ static uint32_t get_sdma_rlc_reg_offset(struct amdgpu_device *adev,
regSDMA1_QUEUE0_RB_CNTL) - regSDMA0_QUEUE0_RB_CNTL;
break;
default:
- BUG();
+ WARN(1, "Invalid SDMA engine id %d\n", engine_id);
+ break;
}
sdma_rlc_reg_offset = sdma_engine_reg_base
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12.c
index bf0bd7688ee4..e11ba3e91841 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12.c
@@ -90,7 +90,8 @@ static uint32_t get_sdma_rlc_reg_offset(struct amdgpu_device *adev,
regSDMA1_QUEUE0_RB_CNTL) - regSDMA0_QUEUE0_RB_CNTL;
break;
default:
- BUG();
+ WARN(1, "Invalid SDMA engine id %d\n", engine_id);
+ break;
}
sdma_rlc_reg_offset = sdma_engine_reg_base
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12_1.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12_1.c
index bcb180f9d3ff..38ca1aea33b2 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12_1.c
@@ -93,7 +93,8 @@ static uint32_t get_sdma_rlc_reg_offset(struct amdgpu_device *adev,
regSDMA1_SDMA_QUEUE0_RB_CNTL) - regSDMA0_SDMA_QUEUE0_RB_CNTL;
break;
default:
- BUG();
+ WARN(1, "Invalid SDMA engine id %d\n", engine_id);
+ break;
}
sdma_rlc_reg_offset = sdma_engine_reg_base
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c
index 6860a3a4d466..1e21e3444802 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c
@@ -917,8 +917,6 @@ int amdgpu_atomfirmware_get_clock_info(struct amdgpu_device *adev)
(crev != 6)) {
spll->reference_freq = le32_to_cpu(gfx_info->v22.rlc_gpu_timer_refclk);
ret = 0;
- } else {
- BUG();
}
}
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c
index babd23e5a27e..9bbe60968352 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c
@@ -76,10 +76,9 @@ static uint32_t amdgpu_cgs_read_ind_register(struct cgs_device *cgs_device,
DRM_ERROR("audio endpt register access not implemented.\n");
return 0;
default:
- BUG();
+ WARN(1, "Invalid indirect register space");
+ return 0;
}
- WARN(1, "Invalid indirect register space");
- return 0;
}
static void amdgpu_cgs_write_ind_register(struct cgs_device *cgs_device,
@@ -104,9 +103,8 @@ static void amdgpu_cgs_write_ind_register(struct cgs_device *cgs_device,
DRM_ERROR("audio endpt register access not implemented.\n");
return;
default:
- BUG();
+ WARN(1, "Invalid indirect register space");
}
- WARN(1, "Invalid indirect register space");
}
static uint32_t fw_type_convert(struct cgs_device *cgs_device, uint32_t fw_type)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
index d777375e5350..d58701908158 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
@@ -1118,7 +1118,8 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p)
if (fpriv->csa_va) {
bo_va = fpriv->csa_va;
- BUG_ON(!bo_va);
+ if (!bo_va)
+ return -ENOMEM;
r = amdgpu_vm_bo_update(adev, bo_va, false);
if (r)
return r;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c
index 6d9e96fabd58..4f1c711df5bd 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c
@@ -1478,7 +1478,8 @@ void amdgpu_ucode_ip_version_decode(struct amdgpu_device *adev, int block_type,
ip_name = "isp";
break;
default:
- BUG();
+ WARN(1, "invalid HWIP %d\n", block_type);
+ return;
}
maj = IP_VERSION_MAJ(version);
diff --git a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c
index b703ef1fe340..b951328d94cf 100644
--- a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c
+++ b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c
@@ -125,7 +125,8 @@ static int cik_sdma_init_microcode(struct amdgpu_device *adev)
case CHIP_MULLINS:
chip_name = "mullins";
break;
- default: BUG();
+ default:
+ return -EINVAL;
}
for (i = 0; i < adev->sdma.num_instances; i++) {
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
index 9d325867a1aa..55342962422b 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
@@ -5350,6 +5350,15 @@ static void gfx_v10_0_constants_init(struct amdgpu_device *adev)
gfx_v10_0_get_tcc_info(adev);
adev->gfx.config.pa_sc_tile_steering_override =
gfx_v10_0_init_pa_sc_tile_steering_override(adev);
+ /* Program DB_RING_CONTROL for multiple GFX pipes
+ * Default power up value is 1.
+ * Possible values:
+ * 0 - split occlusion counters between gfx pipes
+ * 1 - all occlusion counters to pipe 0
+ * 2 - all occlusion counters to pipe 1
+ */
+ WREG32_FIELD15(GC, 0, DB_RING_CONTROL, COUNTER_CONTROL,
+ (adev->gfx.me.num_pipe_per_me > 1) ? 0 : 1);
/* XXX SH_MEM regs */
/* where to put LDS, scratch, GPUVM in FSA64 space */
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
index 254a72f26ec5..2ef6bc818aba 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
@@ -51,7 +51,7 @@
#include "mes_userqueue.h"
#include "amdgpu_userq_fence.h"
-#define GFX11_NUM_GFX_RINGS 1
+#define GFX11_NUM_GFX_RINGS 2
#define GFX11_MEC_HPD_SIZE 2048
#define RLCG_UCODE_LOADING_START_ADDRESS 0x00002000L
@@ -1625,7 +1625,10 @@ static int gfx_v11_0_sw_init(struct amdgpu_ip_block *ip_block)
case IP_VERSION(11, 7, 0):
case IP_VERSION(11, 7, 1):
adev->gfx.me.num_me = 1;
- adev->gfx.me.num_pipe_per_me = 1;
+ if (adev->gfx.rs64_enable)
+ adev->gfx.me.num_pipe_per_me = 1;
+ else
+ adev->gfx.me.num_pipe_per_me = 2;
adev->gfx.me.num_queue_per_pipe = 2;
adev->gfx.mec.num_mec = 1;
adev->gfx.mec.num_pipe_per_mec = 4;
@@ -2191,6 +2194,15 @@ static void gfx_v11_0_constants_init(struct amdgpu_device *adev)
tmp = RREG32_SOC15(GC, 0, regTA_CNTL2);
adev->gfx.config.ta_cntl2_truncate_coord_mode =
REG_GET_FIELD(tmp, TA_CNTL2, TRUNCATE_COORD_MODE);
+ /* Program DB_RING_CONTROL for multiple GFX pipes
+ * Default power up value is 1.
+ * Possible values:
+ * 0 - split occlusion counters between gfx pipes
+ * 1 - all occlusion counters to pipe 0
+ * 2 - all occlusion counters to pipe 1
+ */
+ WREG32_FIELD15_PREREG(GC, 0, DB_RING_CONTROL, COUNTER_CONTROL,
+ (adev->gfx.me.num_pipe_per_me > 1) ? 0 : 1);
/* XXX SH_MEM regs */
/* where to put LDS, scratch, GPUVM in FSA64 space */
@@ -5357,6 +5369,7 @@ static void gfx_v11_0_ring_emit_gds_switch(struct amdgpu_ring *ring,
static int gfx_v11_0_early_init(struct amdgpu_ip_block *ip_block)
{
struct amdgpu_device *adev = ip_block->adev;
+ int r;
switch (amdgpu_user_queue) {
case -1:
@@ -5377,6 +5390,11 @@ static int gfx_v11_0_early_init(struct amdgpu_ip_block *ip_block)
adev->gfx.funcs = &gfx_v11_0_gfx_funcs;
+ gfx_v11_0_set_imu_funcs(adev);
+ r = gfx_v11_0_init_microcode(adev);
+ if (r)
+ return r;
+
if (adev->gfx.disable_kq) {
/* We need one GFX ring temporarily to set up
* the clear state.
@@ -5384,7 +5402,11 @@ static int gfx_v11_0_early_init(struct amdgpu_ip_block *ip_block)
adev->gfx.num_gfx_rings = 1;
adev->gfx.num_compute_rings = 0;
} else {
- adev->gfx.num_gfx_rings = GFX11_NUM_GFX_RINGS;
+ /* rs64 only supports one gfx pipe */
+ if (adev->gfx.rs64_enable)
+ adev->gfx.num_gfx_rings = 1;
+ else
+ adev->gfx.num_gfx_rings = GFX11_NUM_GFX_RINGS;
adev->gfx.num_compute_rings = min(amdgpu_gfx_get_num_kcq(adev),
AMDGPU_MAX_COMPUTE_RINGS);
}
@@ -5395,13 +5417,12 @@ static int gfx_v11_0_early_init(struct amdgpu_ip_block *ip_block)
gfx_v11_0_set_gds_init(adev);
gfx_v11_0_set_rlc_funcs(adev);
gfx_v11_0_set_mqd_funcs(adev);
- gfx_v11_0_set_imu_funcs(adev);
gfx_v11_0_init_rlcg_reg_access_ctrl(adev);
amdgpu_init_rlc_reg_funcs(adev);
- return gfx_v11_0_init_microcode(adev);
+ return 0;
}
static bool gfx_v11_0_is_rlc_enabled(struct amdgpu_device *adev)
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
index 8221a77b6b75..6fedb6df8db9 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
@@ -1827,6 +1827,15 @@ static void gfx_v12_0_constants_init(struct amdgpu_device *adev)
gfx_v12_0_get_cu_info(adev, &adev->gfx.cu_info);
gfx_v12_0_get_tcc_info(adev);
adev->gfx.config.pa_sc_tile_steering_override = 0;
+ /* Program DB_RING_CONTROL for multiple GFX pipes
+ * Default power up value is 1.
+ * Possible values:
+ * 0 - split occlusion counters between gfx pipes
+ * 1 - all occlusion counters to pipe 0
+ * 2 - all occlusion counters to pipe 1
+ */
+ WREG32_FIELD15_PREREG(GC, 0, DB_RING_CONTROL, COUNTER_CONTROL,
+ (adev->gfx.me.num_pipe_per_me > 1) ? 0 : 1);
/* XXX SH_MEM regs */
/* where to put LDS, scratch, GPUVM in FSA64 space */
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
index a914dd8183b5..b49098931d19 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
@@ -124,7 +124,7 @@ static int gmc_v6_0_init_microcode(struct amdgpu_device *adev)
chip_name = "hainan";
break;
default:
- BUG();
+ return -EINVAL;
}
/* this memory configuration requires special firmware */
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c
index 397b08c7173a..c7253b908351 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c
@@ -138,7 +138,7 @@ static int sdma_v2_4_init_microcode(struct amdgpu_device *adev)
chip_name = "topaz";
break;
default:
- BUG();
+ return -EINVAL;
}
for (i = 0; i < adev->sdma.num_instances; i++) {
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
index 8ac1c9dae72e..05cce4bde73e 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
@@ -298,7 +298,8 @@ static int sdma_v3_0_init_microcode(struct amdgpu_device *adev)
case CHIP_STONEY:
chip_name = "stoney";
break;
- default: BUG();
+ default:
+ return -EINVAL;
}
for (i = 0; i < adev->sdma.num_instances; i++) {
diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c
index 6e455ad66d62..7100f30ffeff 100644
--- a/drivers/gpu/drm/amd/amdgpu/si.c
+++ b/drivers/gpu/drm/amd/amdgpu/si.c
@@ -2218,7 +2218,7 @@ static void si_init_golden_registers(struct amdgpu_device *adev)
default:
- BUG();
+ break;
}
}
@@ -2735,7 +2735,7 @@ int si_set_ip_blocks(struct amdgpu_device *adev)
amdgpu_device_ip_block_add(adev, &amdgpu_vkms_ip_block);
break;
default:
- BUG();
+ break;
}
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
index 411ee894f623..2c1a936459ac 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
@@ -3303,6 +3303,11 @@ static int kfd_ioctl_create_process(struct file *filep, struct kfd_process *p, v
}
filep->private_data = process;
+ ret = kfd_debugfs_add_process(process);
+ if (ret)
+ pr_warn("Failed to create debugfs entry for the kfd_process, ret = %d\n",
+ ret);
+
mutex_unlock(&kfd_processes_mutex);
ret = kfd_create_process_sysfs(process);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_debugfs.c b/drivers/gpu/drm/amd/amdkfd/kfd_debugfs.c
index 7d4e07452cdb..464836f2a53f 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_debugfs.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_debugfs.c
@@ -33,6 +33,7 @@ static struct list_head procs;
struct debugfs_proc_entry {
struct list_head list;
struct dentry *proc_dentry;
+ struct kfd_process *process;
pid_t pid;
};
@@ -140,34 +141,97 @@ static const struct file_operations kfd_debugfs_pasid_fops = {
.read = kfd_debugfs_pasid_read,
};
-void kfd_debugfs_add_process(struct kfd_process *p)
+/* This helper locates the debugfs entry of a kfd process */
+static struct debugfs_proc_entry *kfd_debugfs_find_process_entry(struct kfd_process *p)
{
+ struct debugfs_proc_entry *entry;
+
+ list_for_each_entry(entry, &procs, list) {
+ if (entry->process == p)
+ return entry;
+ }
+
+ return NULL;
+}
+
+/* This helper creates pasid file of a kfd process under debugfs */
+static void kfd_debugfs_create_pasid_files(struct kfd_process *p,
+ struct dentry *dir)
+{
+ char name[MAX_DEBUGFS_FILENAME_LEN];
+ struct kfd_process_device *pdd;
int i;
+
+ /* create pasid file for each GPU */
+ for (i = 0; i < p->n_pdds; i++) {
+ pdd = p->pdds[i];
+ snprintf(name, MAX_DEBUGFS_FILENAME_LEN, "pasid_%u", pdd->dev->id);
+ debugfs_create_file((const char *)name, S_IFREG | 0444,
+ dir, pdd, &kfd_debugfs_pasid_fops);
+ }
+}
+
+int kfd_debugfs_add_process(struct kfd_process *p)
+{
+ struct debugfs_proc_entry *primary_entry;
char name[MAX_DEBUGFS_FILENAME_LEN];
+ struct kfd_process *primary_process;
struct debugfs_proc_entry *entry;
+ int ret;
entry = kzalloc_obj(*entry);
if (!entry)
- return;
+ return -ENOMEM;
- list_add(&entry->list, &procs);
+ entry->process = p;
entry->pid = p->lead_thread->pid;
- snprintf(name, MAX_DEBUGFS_FILENAME_LEN, "%d",
- (int)entry->pid);
- entry->proc_dentry = debugfs_create_dir(name, debugfs_proc);
- /* Create debugfs files for each GPU:
- * - proc/<pid>/pasid_<gpuid>
- */
- for (i = 0; i < p->n_pdds; i++) {
- struct kfd_process_device *pdd = p->pdds[i];
+ if (p->context_id == KFD_CONTEXT_ID_PRIMARY) {
+ snprintf(name, MAX_DEBUGFS_FILENAME_LEN, "%d",
+ (int)entry->pid);
+ entry->proc_dentry = debugfs_create_dir(name, debugfs_proc);
+ } else {
+ primary_process = kfd_lookup_process_by_mm(p->lead_thread->mm);
+ if (!primary_process) {
+ ret = -ESRCH;
+ goto err_free_entry;
+ }
- snprintf(name, MAX_DEBUGFS_FILENAME_LEN, "pasid_%u",
- pdd->dev->id);
- debugfs_create_file((const char *)name, S_IFREG | 0444,
- entry->proc_dentry, pdd,
- &kfd_debugfs_pasid_fops);
+ primary_entry = kfd_debugfs_find_process_entry(primary_process);
+ kfd_unref_process(primary_process);
+ if (!primary_entry) {
+ pr_warn("Failed to find the primary debugfs entry for pid %d\n",
+ entry->pid);
+ ret = -ENOENT;
+ goto err_free_entry;
+ }
+
+ snprintf(name, MAX_DEBUGFS_FILENAME_LEN, "context_%u",
+ p->context_id);
+ entry->proc_dentry = debugfs_create_dir(name,
+ primary_entry->proc_dentry);
}
+ if (IS_ERR_OR_NULL(entry->proc_dentry)) {
+ ret = entry->proc_dentry ? PTR_ERR(entry->proc_dentry) : -ENOMEM;
+ goto err_free_entry;
+ }
+
+ list_add(&entry->list, &procs);
+ kfd_debugfs_create_pasid_files(p, entry->proc_dentry);
+
+ return 0;
+
+err_free_entry:
+ kfree(entry);
+ return ret;
+}
+
+/* This helper removes a debugfs entry and its sub-entries */
+static void kfd_debugfs_remove_entry(struct debugfs_proc_entry *entry)
+{
+ debugfs_remove(entry->proc_dentry);
+ list_del(&entry->list);
+ kfree(entry);
}
void kfd_debugfs_remove_process(struct kfd_process *p)
@@ -175,13 +239,22 @@ void kfd_debugfs_remove_process(struct kfd_process *p)
struct debugfs_proc_entry *entry, *next;
mutex_lock(&kfd_processes_mutex);
+ if (p->context_id == KFD_CONTEXT_ID_PRIMARY) {
+ /* remove entries of secondary contexts */
+ list_for_each_entry_safe(entry, next, &procs, list) {
+ if (entry->pid != p->lead_thread->pid || entry->process == p)
+ continue;
+
+ kfd_debugfs_remove_entry(entry);
+ }
+ }
+
list_for_each_entry_safe(entry, next, &procs, list) {
- if (entry->pid != p->lead_thread->pid)
+ if (entry->process != p)
continue;
- debugfs_remove_recursive(entry->proc_dentry);
- list_del(&entry->list);
- kfree(entry);
+ kfd_debugfs_remove_entry(entry);
}
+
mutex_unlock(&kfd_processes_mutex);
}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
index 97402e6c8f83..cc42feb24277 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
@@ -3777,6 +3777,12 @@ out:
dqm_unlock(dqm);
return r;
}
+
+size_t mqd_size_from_queue_type(struct device_queue_manager *dqm, enum kfd_queue_type type)
+{
+ return dqm->mqd_mgrs[get_mqd_type_from_queue_type(type)]->mqd_size;
+}
+
#if defined(CONFIG_DEBUG_FS)
static void seq_reg_dump(struct seq_file *m,
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h
index 2229f8b2f446..c9f9f7a87111 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h
@@ -335,6 +335,8 @@ bool kfd_dqm_is_queue_in_process(struct device_queue_manager *dqm,
int doorbell_off, u32 *queue_format);
int kfd_reset_queue_mes(struct device_queue_manager *dqm, int queue_type,
int pipe, int queue, unsigned int db);
+size_t mqd_size_from_queue_type(struct device_queue_manager *dqm,
+ enum kfd_queue_type type);
static inline unsigned int get_sh_mem_bases_32(struct kfd_process_device *pdd)
{
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_events.c
index dae01e2bb464..f5fd78f0df7d 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_events.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.c
@@ -61,6 +61,9 @@ static int allocate_event_notification_slot(struct kfd_process *p,
return -ENOMEM;
if (restore_id) {
+ if (*restore_id >= KFD_SIGNAL_EVENT_LIMIT)
+ return -EINVAL;
+
id = idr_alloc(&p->event_idr, ev, *restore_id, *restore_id + 1,
GFP_KERNEL);
} else {
@@ -158,7 +161,7 @@ static int create_signal_event(struct file *devkfd, struct kfd_process *p,
ret = allocate_event_notification_slot(p, ev, restore_id);
if (ret) {
- pr_warn("Signal event wasn't created because out of kernel memory\n");
+ pr_warn("Failed to create signal event notification slot\n");
return ret;
}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
index 86a944d36aaf..88191a4c1657 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
@@ -441,7 +441,8 @@ enum kfd_queue_type {
KFD_QUEUE_TYPE_SDMA,
KFD_QUEUE_TYPE_HIQ,
KFD_QUEUE_TYPE_SDMA_XGMI,
- KFD_QUEUE_TYPE_SDMA_BY_ENG_ID
+ KFD_QUEUE_TYPE_SDMA_BY_ENG_ID,
+ KFD_QUEUE_TYPE_MAX,
};
enum kfd_queue_format {
@@ -1650,14 +1651,14 @@ int kfd_debugfs_hang_hws(struct kfd_node *dev);
int pm_debugfs_hang_hws(struct packet_manager *pm);
int dqm_debugfs_hang_hws(struct device_queue_manager *dqm);
-void kfd_debugfs_add_process(struct kfd_process *p);
+int kfd_debugfs_add_process(struct kfd_process *p);
void kfd_debugfs_remove_process(struct kfd_process *p);
#else
static inline void kfd_debugfs_init(void) {}
static inline void kfd_debugfs_fini(void) {}
-static inline void kfd_debugfs_add_process(struct kfd_process *p) {}
+static inline int kfd_debugfs_add_process(struct kfd_process *p) { return 0; }
static inline void kfd_debugfs_remove_process(struct kfd_process *p) {}
#endif
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
index 7a604b8c8886..eb508fe3ded7 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
@@ -948,7 +948,7 @@ static void kfd_process_free_id(struct kfd_process *process)
{
struct kfd_process *primary_process;
- if (process->context_id != KFD_CONTEXT_ID_PRIMARY)
+ if (process->context_id == KFD_CONTEXT_ID_PRIMARY)
return;
primary_process = kfd_lookup_process_by_mm(process->lead_thread->mm);
@@ -1013,7 +1013,10 @@ struct kfd_process *kfd_create_process(struct task_struct *thread)
if (ret)
pr_warn("Failed to create sysfs entry for the kfd_process");
- kfd_debugfs_add_process(process);
+ ret = kfd_debugfs_add_process(process);
+ if (ret)
+ pr_warn("Failed to create debugfs entry for the kfd_process, ret = %d\n",
+ ret);
init_waitqueue_head(&process->wait_irq_drain);
}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
index acbdca91cde5..97e77a5a35e5 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
@@ -265,6 +265,11 @@ static int init_user_queue(struct process_queue_manager *pqm,
(*q)->process = pqm->process;
if (dev->kfd->shared_resources.enable_mes) {
+ if (!q_properties->wptr_bo) {
+ pr_debug("Queue initialization with shared MES requires queue buffers to be initialized\n");
+ return -EINVAL;
+ }
+
retval = amdgpu_amdkfd_alloc_kernel_mem(dev->adev,
AMDGPU_MES_GANG_CTX_SIZE,
AMDGPU_GEM_DOMAIN_GTT,
@@ -1003,6 +1008,23 @@ int kfd_criu_restore_queue(struct kfd_process *p,
goto exit;
}
+ pdd = kfd_process_device_data_by_id(p, q_data->gpu_id);
+ if (!pdd) {
+ pr_err("Failed to get pdd\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (q_data->type >= KFD_QUEUE_TYPE_MAX) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (q_data->mqd_size != mqd_size_from_queue_type(pdd->dev->dqm, q_data->type)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
*priv_data_offset += sizeof(*q_data);
q_extra_data_size = (uint64_t)q_data->ctl_stack_size + q_data->mqd_size;
@@ -1025,13 +1047,6 @@ int kfd_criu_restore_queue(struct kfd_process *p,
*priv_data_offset += q_extra_data_size;
- pdd = kfd_process_device_data_by_id(p, q_data->gpu_id);
- if (!pdd) {
- pr_err("Failed to get pdd\n");
- ret = -EINVAL;
- goto exit;
- }
-
/*
* data stored in this order:
* mqd[xcc0], mqd[xcc1],..., ctl_stack[xcc0], ctl_stack[xcc1]...
@@ -1042,24 +1057,10 @@ int kfd_criu_restore_queue(struct kfd_process *p,
memset(&qp, 0, sizeof(qp));
set_queue_properties_from_criu(&qp, q_data, NUM_XCC(pdd->dev->xcc_mask));
- ret = kfd_queue_acquire_buffers(pdd, &qp);
- if (ret) {
- pr_debug("failed to acquire user queue buffers for CRIU\n");
- goto exit;
- }
-
- ret = kfd_queue_acquire_buffers(pdd, &qp);
- if (ret) {
- pr_debug("failed to acquire user queue buffers for CRIU\n");
- goto exit;
- }
-
print_queue_properties(&qp);
ret = pqm_create_queue(&p->pqm, pdd->dev, &qp, &queue_id, q_data, mqd, ctl_stack, NULL);
if (ret) {
- kfd_queue_unref_bo_vas(pdd, &qp);
- kfd_queue_release_buffers(pdd, &qp);
pr_err("Failed to create new queue err:%d\n", ret);
goto exit;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
index d6cf643205ab..0fbcaf884419 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
@@ -1621,19 +1621,23 @@ static int smu_v14_0_2_get_power_limit(struct smu_context *smu,
table_context->power_play_table;
PPTable_t *pptable = table_context->driver_pptable;
CustomSkuTable_t *skutable = &pptable->CustomSkuTable;
- int16_t od_percent_upper = 0, od_percent_lower = 0;
+ uint32_t pp_limit = smu->adev->pm.ac_power ?
+ skutable->SocketPowerLimitAc[PPT_THROTTLER_PPT0] :
+ skutable->SocketPowerLimitDc[PPT_THROTTLER_PPT0];
uint32_t msg_limit = pptable->SkuTable.MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
- uint32_t power_limit;
+ uint32_t min_limit = min_t(uint32_t, pp_limit, msg_limit);
+ uint32_t max_limit = max_t(uint32_t, pp_limit, msg_limit);
+ int16_t od_percent_upper = 0, od_percent_lower = 0;
+ int ret;
- if (smu_v14_0_get_current_power_limit(smu, &power_limit))
- power_limit = smu->adev->pm.ac_power ?
- skutable->SocketPowerLimitAc[PPT_THROTTLER_PPT0] :
- skutable->SocketPowerLimitDc[PPT_THROTTLER_PPT0];
+ if (current_power_limit) {
+ ret = smu_v14_0_get_current_power_limit(smu, current_power_limit);
+ if (ret)
+ *current_power_limit = pp_limit;
+ }
- if (current_power_limit)
- *current_power_limit = power_limit;
if (default_power_limit)
- *default_power_limit = power_limit;
+ *default_power_limit = pp_limit;
if (powerplay_table) {
if (smu->od_enabled &&
@@ -1647,15 +1651,15 @@ static int smu_v14_0_2_get_power_limit(struct smu_context *smu,
}
dev_dbg(smu->adev->dev, "od percent upper:%d, od percent lower:%d (default power: %d)\n",
- od_percent_upper, od_percent_lower, power_limit);
+ od_percent_upper, od_percent_lower, pp_limit);
if (max_power_limit) {
- *max_power_limit = msg_limit * (100 + od_percent_upper);
+ *max_power_limit = max_limit * (100 + od_percent_upper);
*max_power_limit /= 100;
}
if (min_power_limit) {
- *min_power_limit = power_limit * (100 + od_percent_lower);
+ *min_power_limit = min_limit * (100 + od_percent_lower);
*min_power_limit /= 100;
}
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 3316bb00a662..d4664ed468b2 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -225,16 +225,106 @@ static void drm_fb_helper_resume_worker(struct work_struct *work)
console_unlock();
}
+static int find_crtc_index_atomic(struct drm_fb_helper *helper)
+{
+ struct drm_device *dev = helper->dev;
+ int crtc_index = -EINVAL;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_plane *plane;
+ int ret = 0;
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+retry:
+ drm_for_each_plane(plane, dev) {
+ const struct drm_plane_state *plane_state;
+
+ if (plane->type != DRM_PLANE_TYPE_PRIMARY)
+ continue;
+
+ ret = drm_modeset_lock(&plane->mutex, &ctx);
+ if (ret)
+ goto err_drm_modeset_lock;
+ plane_state = plane->state;
+
+ if (plane_state->fb == helper->fb && plane_state->crtc) {
+ struct drm_crtc *crtc = plane_state->crtc;
+
+ ret = drm_modeset_lock(&crtc->mutex, &ctx);
+ if (ret)
+ goto err_drm_modeset_lock;
+ if (crtc->state->active)
+ crtc_index = crtc->index;
+ drm_modeset_unlock(&crtc->mutex);
+ }
+ drm_modeset_unlock(&plane->mutex);
+
+ if (crtc_index >= 0)
+ break;
+ }
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+
+ return crtc_index;
+
+err_drm_modeset_lock:
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&ctx);
+ goto retry;
+ }
+ return ret;
+}
+
+static int find_crtc_index_legacy(struct drm_fb_helper *helper)
+{
+ struct drm_device *dev = helper->dev;
+ struct drm_crtc *crtc;
+
+ drm_for_each_crtc(crtc, dev) {
+ struct drm_plane *plane = crtc->primary;
+
+ if (!crtc->enabled)
+ continue;
+ if (!plane || plane->fb != helper->fb)
+ continue; /* CRTC doesn't display fbdev emulation */
+
+ return crtc->index;
+ }
+
+ return -EINVAL;
+}
+
+static int drm_fb_helper_find_crtc_index(struct drm_fb_helper *helper)
+{
+ struct drm_device *dev = helper->dev;
+ int crtc_index;
+
+ mutex_lock(&dev->mode_config.mutex);
+
+ if (drm_drv_uses_atomic_modeset(dev))
+ crtc_index = find_crtc_index_atomic(helper);
+ else
+ crtc_index = find_crtc_index_legacy(helper);
+
+ mutex_unlock(&dev->mode_config.mutex);
+
+ return crtc_index;
+}
+
static void drm_fb_helper_fb_dirty(struct drm_fb_helper *helper)
{
struct drm_device *dev = helper->dev;
struct drm_clip_rect *clip = &helper->damage_clip;
struct drm_clip_rect clip_copy;
+ int crtc_index;
unsigned long flags;
int ret;
mutex_lock(&helper->lock);
- drm_client_modeset_wait_for_vblank(&helper->client, 0);
+ crtc_index = drm_fb_helper_find_crtc_index(helper);
+ if (crtc_index >= 0)
+ drm_client_modeset_wait_for_vblank(&helper->client, crtc_index);
mutex_unlock(&helper->lock);
if (drm_WARN_ON_ONCE(dev, !helper->funcs->fb_dirty))
diff --git a/drivers/gpu/drm/drm_gpusvm.c b/drivers/gpu/drm/drm_gpusvm.c
index 958cb605aedd..fcfe635bc195 100644
--- a/drivers/gpu/drm/drm_gpusvm.c
+++ b/drivers/gpu/drm/drm_gpusvm.c
@@ -48,6 +48,47 @@
* event. As mentioned above, ranges are tracked in a notifier's Red-Black
* tree.
*
+ * - Pages:
+ * struct drm_gpusvm_pages holds the DMA mapping state for a range of
+ * CPU virtual addresses: the DMA mapped device addresses,
+ * the device private pagemap, the IOVA state, the per mapping
+ * notifier sequence number, and the drm_device that owns the DMA
+ * mappings.
+ * A driver embeds one or more struct drm_gpusvm_pages alongside its
+ * struct drm_gpusvm_range, choosing one of two layouts:
+ *
+ * 1:1 - one drm_gpusvm_pages per range (one drm_device). Simplest
+ * layout; to mirror a VA range on several devices a driver uses a
+ * separate range (and notifier) per device, so the HMM fault is taken
+ * once per device.
+ *
+ * N:1 - one drm_gpusvm_pages per drm_device, all sharing one range and
+ * notifier; only the per-device DMA mapping differs. The instances must
+ * sit in contiguous memory so a single drm_gpusvm_range_set_unmapped()
+ * can mark them all. A driver can keep one instance inline for the single
+ * device case and switch to a heap array only when more devices join,
+ * e.g.:
+ *
+ * .. code-block:: c
+ *
+ * struct driver_range {
+ * struct drm_gpusvm_range base;
+ * unsigned int num_pages; // 1: inline_pages, >1: pages[]
+ * union {
+ * struct drm_gpusvm_pages inline_pages;
+ * struct drm_gpusvm_pages *pages;
+ * };
+ * };
+ *
+ * In the N:1 case the driver allocates the pages array with a zeroing
+ * allocator (e.g. kcalloc(num_pages, ...)), initialises each entry with
+ * drm_gpusvm_init_pages(), and frees each entry with
+ * drm_gpusvm_free_pages() plus the array itself, from its range free
+ * callback. Each drm_gpusvm_pages is mapped independently by their own
+ * drm_device.
+ * Each drm_gpusvm_pages must be zero-initialised and initialised with
+ * drm_gpusvm_init_pages(), called once per entry.
+ *
* - Operations:
* Define the interface for driver-specific GPU SVM operations such as
* range allocation, notifier allocation, and invalidations.
@@ -92,7 +133,7 @@
* range RB tree and list, as well as the range's DMA mappings and sequence
* number. GPU SVM manages all necessary locking and unlocking operations,
* except for the recheck range's pages being valid
- * (drm_gpusvm_range_pages_valid) when the driver is committing GPU bindings.
+ * (drm_gpusvm_pages_valid) when the driver is committing GPU bindings.
* This lock corresponds to the ``driver->update`` lock mentioned in
* Documentation/mm/hmm.rst. Future revisions may transition from a GPU SVM
* global lock to a per-notifier lock if finer-grained locking is deemed
@@ -140,15 +181,20 @@
*
* .. code-block:: c
*
- * int driver_bind_range(struct drm_gpusvm *gpusvm, struct drm_gpusvm_range *range)
+ * struct driver_range {
+ * struct drm_gpusvm_range base;
+ * struct drm_gpusvm_pages pages;
+ * };
+ *
+ * int driver_bind_range(struct drm_gpusvm *gpusvm, struct driver_range *drange)
* {
* int err = 0;
*
- * driver_alloc_and_setup_memory_for_bind(gpusvm, range);
+ * driver_alloc_and_setup_memory_for_bind(gpusvm, drange);
*
* drm_gpusvm_notifier_lock(gpusvm);
- * if (drm_gpusvm_range_pages_valid(range))
- * driver_commit_bind(gpusvm, range);
+ * if (drm_gpusvm_pages_valid(gpusvm, &drange->pages))
+ * driver_commit_bind(gpusvm, drange);
* else
* err = -EAGAIN;
* drm_gpusvm_notifier_unlock(gpusvm);
@@ -160,6 +206,8 @@
* unsigned long gpuva_start, unsigned long gpuva_end)
* {
* struct drm_gpusvm_ctx ctx = {};
+ * struct driver_range *drange;
+ * struct drm_gpusvm_range *range;
* int err;
*
* driver_svm_lock();
@@ -174,6 +222,7 @@
* err = PTR_ERR(range);
* goto unlock;
* }
+ * drange = container_of(range, struct driver_range, base);
*
* if (driver_migration_policy(range)) {
* err = drm_pagemap_populate_mm(driver_choose_drm_pagemap(),
@@ -183,7 +232,10 @@
* goto retry;
* }
*
- * err = drm_gpusvm_range_get_pages(gpusvm, range, &ctx);
+ * err = drm_gpusvm_get_pages(gpusvm, &drange->pages,
+ * gpusvm->mm, &range->notifier->notifier,
+ * drm_gpusvm_range_start(range),
+ * drm_gpusvm_range_end(range), &ctx);
* if (err == -EOPNOTSUPP || err == -EFAULT || err == -EPERM) { // CPU mappings changed
* if (err == -EOPNOTSUPP)
* drm_gpusvm_range_evict(gpusvm, range);
@@ -192,7 +244,7 @@
* goto unlock;
* }
*
- * err = driver_bind_range(gpusvm, range);
+ * err = driver_bind_range(gpusvm, drange);
* if (err == -EAGAIN) // CPU mappings changed
* goto retry
*
@@ -205,6 +257,21 @@
*
* .. code-block:: c
*
+ * // The driver owns the drm_gpusvm_pages lifecycle. ops->range_free is
+ * // the final fallback: drm_gpusvm_free_pages() unmaps any
+ * // lingering DMA mapping and a no-op if already unmapped and frees the
+ * // dma_addr array. The normal flow is to DMA unmap before
+ * // drm_gpusvm_range_remove() (before the range leaves the tree).
+ * void driver_range_free(struct drm_gpusvm_range *range)
+ * {
+ * struct driver_range *drange =
+ * container_of(range, struct driver_range, base);
+ *
+ * drm_gpusvm_free_pages(range->gpusvm, &drange->pages,
+ * drm_gpusvm_range_size(range) >> PAGE_SHIFT);
+ * kfree(drange);
+ * }
+ *
* void __driver_garbage_collector(struct drm_gpusvm *gpusvm,
* struct drm_gpusvm_range *range)
* {
@@ -215,6 +282,14 @@
* drm_gpusvm_range_evict(gpusvm, range);
*
* driver_unbind_range(range);
+ * // The pages must be DMA unmapped before drm_gpusvm_range_remove()
+ * // , so a range is never off the MMU interval tree while still DMA
+ * // mapped as the original drmsvm design flow. Otherwise a concurrent CPU
+ * // munmap's notifier could miss this range and free pages still mapped
+ * // for device DMA. This is the normal unmap point.
+ * drm_gpusvm_unmap_pages(gpusvm, &drange->pages,
+ * drm_gpusvm_range_size(range) >> PAGE_SHIFT,
+ * &(struct drm_gpusvm_ctx){ .in_notifier = false });
* drm_gpusvm_range_remove(gpusvm, range);
* }
*
@@ -236,17 +311,22 @@
* {
* struct drm_gpusvm_ctx ctx = { .in_notifier = true, };
* struct drm_gpusvm_range *range = NULL;
+ * struct driver_range *drange;
*
* driver_invalidate_device_pages(gpusvm, mmu_range->start, mmu_range->end);
*
* drm_gpusvm_for_each_range(range, notifier, mmu_range->start,
* mmu_range->end) {
- * drm_gpusvm_range_unmap_pages(gpusvm, range, &ctx);
+ * drange = container_of(range, struct driver_range, base);
+ *
+ * drm_gpusvm_unmap_pages(gpusvm, &drange->pages,
+ * drm_gpusvm_range_size(range) >> PAGE_SHIFT,
+ * &ctx);
*
* if (mmu_range->event != MMU_NOTIFY_UNMAP)
* continue;
*
- * drm_gpusvm_range_set_unmapped(range, mmu_range);
+ * drm_gpusvm_range_set_unmapped(range, &drange->pages, 1, mmu_range);
* driver_garbage_collector_add(gpusvm, range);
* }
* }
@@ -359,7 +439,6 @@ static const struct mmu_interval_notifier_ops drm_gpusvm_notifier_ops = {
* drm_gpusvm_init() - Initialize the GPU SVM.
* @gpusvm: Pointer to the GPU SVM structure.
* @name: Name of the GPU SVM.
- * @drm: Pointer to the DRM device structure.
* @mm: Pointer to the mm_struct for the address space.
* @mm_start: Start address of GPU SVM.
* @mm_range: Range of the GPU SVM.
@@ -373,7 +452,9 @@ static const struct mmu_interval_notifier_ops drm_gpusvm_notifier_ops = {
* This function initializes the GPU SVM.
*
* Note: If only using the simple drm_gpusvm_pages API (get/unmap/free),
- * then only @gpusvm, @name, and @drm are expected. However, the same base
+ * then only @gpusvm and @name are expected. The @drm drm_device for dma
+ * mappings is bound per-pages via drm_gpusvm_init_pages() before the first
+ * drm_gpusvm_get_pages() call. However, the same base
* @gpusvm can also be used with both modes together in which case the full
* setup is needed, where the core drm_gpusvm_pages API will simply never use
* the other fields.
@@ -381,7 +462,7 @@ static const struct mmu_interval_notifier_ops drm_gpusvm_notifier_ops = {
* Return: 0 on success, a negative error code on failure.
*/
int drm_gpusvm_init(struct drm_gpusvm *gpusvm,
- const char *name, struct drm_device *drm,
+ const char *name,
struct mm_struct *mm,
unsigned long mm_start, unsigned long mm_range,
unsigned long notifier_size,
@@ -399,7 +480,6 @@ int drm_gpusvm_init(struct drm_gpusvm *gpusvm,
}
gpusvm->name = name;
- gpusvm->drm = drm;
gpusvm->mm = mm;
gpusvm->mm_start = mm_start;
gpusvm->mm_range = mm_range;
@@ -640,8 +720,7 @@ drm_gpusvm_range_alloc(struct drm_gpusvm *gpusvm,
range->itree.start = ALIGN_DOWN(fault_addr, chunk_size);
range->itree.last = ALIGN(fault_addr + 1, chunk_size) - 1;
INIT_LIST_HEAD(&range->entry);
- range->pages.notifier_seq = LONG_MAX;
- range->pages.flags.migrate_devmem = migrate_devmem ? 1 : 0;
+ range->flags.migrate_devmem = migrate_devmem ? 1 : 0;
return range;
}
@@ -929,7 +1008,7 @@ retry:
* mallocs 16k but the CPU VMA is ~128k which results in 64k SVM
* ranges. When migrating the SVM ranges, some processes fail in
* drm_pagemap_migrate_to_devmem with 'migrate.cpages != npages'
- * and then upon drm_gpusvm_range_get_pages device pages from
+ * and then upon drm_gpusvm_get_pages device pages from
* other processes are collected + faulted in which creates all
* sorts of problems. Unsure exactly how this happening, also
* problem goes away if 'xe_exec_system_allocator --r
@@ -1135,11 +1214,16 @@ static void __drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm,
unsigned long npages)
{
struct drm_pagemap *dpagemap = svm_pages->dpagemap;
- struct device *dev = gpusvm->drm->dev;
+ struct device *dev;
unsigned long i, j;
lockdep_assert_held(&gpusvm->notifier_lock);
+ if (!svm_pages->drm)
+ return;
+
+ dev = svm_pages->drm->dev;
+
if (svm_pages->flags.has_dma_mapping) {
struct drm_gpusvm_pages_flags flags = {
.__flags = svm_pages->flags.__flags,
@@ -1222,12 +1306,17 @@ EXPORT_SYMBOL_GPL(drm_gpusvm_free_pages);
* This function removes the specified GPU SVM range and also removes the parent
* GPU SVM notifier if no more ranges remain in the notifier. The caller must
* hold a lock to protect range and notifier removal.
+ *
+ * This function does not unmap or free the drm_gpusvm_pages, the driver owns
+ * that lifecycle. The caller must DMA unmap the range's pages before calling
+ * this function, so a range is never removed from the MMU interval tree while
+ * still DMA mapped. Typically the driver calls drm_gpusvm_unmap_pages() first.
+ * And the range_free callback's drm_gpusvm_free_pages() is a final fallback safe
+ * net.
*/
void drm_gpusvm_range_remove(struct drm_gpusvm *gpusvm,
struct drm_gpusvm_range *range)
{
- unsigned long npages = npages_in_range(drm_gpusvm_range_start(range),
- drm_gpusvm_range_end(range));
struct drm_gpusvm_notifier *notifier;
drm_gpusvm_driver_lock_held(gpusvm);
@@ -1239,8 +1328,6 @@ void drm_gpusvm_range_remove(struct drm_gpusvm *gpusvm,
return;
drm_gpusvm_notifier_lock(gpusvm);
- __drm_gpusvm_unmap_pages(gpusvm, &range->pages, npages);
- __drm_gpusvm_free_pages(gpusvm, &range->pages);
__drm_gpusvm_range_remove(notifier, range);
drm_gpusvm_notifier_unlock(gpusvm);
@@ -1319,34 +1406,14 @@ EXPORT_SYMBOL_GPL(drm_gpusvm_range_put);
*
* Return: True if GPU SVM range has valid pages, False otherwise
*/
-static bool drm_gpusvm_pages_valid(struct drm_gpusvm *gpusvm,
- struct drm_gpusvm_pages *svm_pages)
+bool drm_gpusvm_pages_valid(struct drm_gpusvm *gpusvm,
+ struct drm_gpusvm_pages *svm_pages)
{
lockdep_assert_held(&gpusvm->notifier_lock);
return svm_pages->flags.has_devmem_pages || svm_pages->flags.has_dma_mapping;
}
-
-/**
- * drm_gpusvm_range_pages_valid() - GPU SVM range pages valid
- * @gpusvm: Pointer to the GPU SVM structure
- * @range: Pointer to the GPU SVM range structure
- *
- * This function determines if a GPU SVM range pages are valid. Expected be
- * called holding gpusvm->notifier_lock and as the last step before committing a
- * GPU binding. This is akin to a notifier seqno check in the HMM documentation
- * but due to wider notifiers (i.e., notifiers which span multiple ranges) this
- * function is required for finer grained checking (i.e., per range) if pages
- * are valid.
- *
- * Return: True if GPU SVM range has valid pages, False otherwise
- */
-bool drm_gpusvm_range_pages_valid(struct drm_gpusvm *gpusvm,
- struct drm_gpusvm_range *range)
-{
- return drm_gpusvm_pages_valid(gpusvm, &range->pages);
-}
-EXPORT_SYMBOL_GPL(drm_gpusvm_range_pages_valid);
+EXPORT_SYMBOL_GPL(drm_gpusvm_pages_valid);
/**
* drm_gpusvm_pages_valid_unlocked() - GPU SVM pages valid unlocked
@@ -1421,6 +1488,9 @@ int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
DMA_BIDIRECTIONAL;
struct dma_iova_state *state = &svm_pages->state;
+ if (!svm_pages->drm)
+ return -EINVAL;
+
retry:
if (time_after(jiffies, timeout))
return -EBUSY;
@@ -1520,7 +1590,7 @@ map_pages:
pagemap = page_pgmap(page);
dpagemap = drm_pagemap_page_to_dpagemap(page);
- if (drm_WARN_ON(gpusvm->drm, !dpagemap)) {
+ if (drm_WARN_ON(svm_pages->drm, !dpagemap)) {
/*
* Raced. This is not supposed to happen
* since hmm_range_fault() should've migrated
@@ -1532,10 +1602,10 @@ map_pages:
}
svm_pages->dma_addr[j] =
dpagemap->ops->device_map(dpagemap,
- gpusvm->drm->dev,
+ svm_pages->drm->dev,
page, order,
dma_dir);
- if (dma_mapping_error(gpusvm->drm->dev,
+ if (dma_mapping_error(svm_pages->drm->dev,
svm_pages->dma_addr[j].addr)) {
err = -EFAULT;
goto err_unmap;
@@ -1555,11 +1625,11 @@ map_pages:
}
if (!i)
- dma_iova_try_alloc(gpusvm->drm->dev, state,
+ dma_iova_try_alloc(svm_pages->drm->dev, state,
0, npages * PAGE_SIZE);
if (dma_use_iova(state)) {
- err = dma_iova_link(gpusvm->drm->dev, state,
+ err = dma_iova_link(svm_pages->drm->dev, state,
hmm_pfn_to_phys(pfns[i]),
svm_pages->state_offset,
PAGE_SIZE << order,
@@ -1570,11 +1640,11 @@ map_pages:
addr = state->addr + svm_pages->state_offset;
svm_pages->state_offset += PAGE_SIZE << order;
} else {
- addr = dma_map_page(gpusvm->drm->dev,
+ addr = dma_map_page(svm_pages->drm->dev,
page, 0,
PAGE_SIZE << order,
dma_dir);
- if (dma_mapping_error(gpusvm->drm->dev, addr)) {
+ if (dma_mapping_error(svm_pages->drm->dev, addr)) {
err = -EFAULT;
goto err_unmap;
}
@@ -1590,7 +1660,7 @@ map_pages:
}
if (dma_use_iova(state)) {
- err = dma_iova_sync(gpusvm->drm->dev, state, 0,
+ err = dma_iova_sync(svm_pages->drm->dev, state, 0,
svm_pages->state_offset);
if (err)
goto err_unmap;
@@ -1626,28 +1696,6 @@ err_free:
EXPORT_SYMBOL_GPL(drm_gpusvm_get_pages);
/**
- * drm_gpusvm_range_get_pages() - Get pages for a GPU SVM range
- * @gpusvm: Pointer to the GPU SVM structure
- * @range: Pointer to the GPU SVM range structure
- * @ctx: GPU SVM context
- *
- * This function gets pages for a GPU SVM range and ensures they are mapped for
- * DMA access.
- *
- * Return: 0 on success, negative error code on failure.
- */
-int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm,
- struct drm_gpusvm_range *range,
- const struct drm_gpusvm_ctx *ctx)
-{
- return drm_gpusvm_get_pages(gpusvm, &range->pages, gpusvm->mm,
- &range->notifier->notifier,
- drm_gpusvm_range_start(range),
- drm_gpusvm_range_end(range), ctx);
-}
-EXPORT_SYMBOL_GPL(drm_gpusvm_range_get_pages);
-
-/**
* drm_gpusvm_unmap_pages() - Unmap GPU svm pages
* @gpusvm: Pointer to the GPU SVM structure
* @svm_pages: Pointer to the GPU SVM pages structure
@@ -1678,29 +1726,6 @@ void drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm,
EXPORT_SYMBOL_GPL(drm_gpusvm_unmap_pages);
/**
- * drm_gpusvm_range_unmap_pages() - Unmap pages associated with a GPU SVM range
- * @gpusvm: Pointer to the GPU SVM structure
- * @range: Pointer to the GPU SVM range structure
- * @ctx: GPU SVM context
- *
- * This function unmaps pages associated with a GPU SVM range. If @in_notifier
- * is set, it is assumed that gpusvm->notifier_lock is held in write mode; if it
- * is clear, it acquires gpusvm->notifier_lock in read mode. Must be called on
- * each GPU SVM range attached to notifier in gpusvm->ops->invalidate for IOMMU
- * security model.
- */
-void drm_gpusvm_range_unmap_pages(struct drm_gpusvm *gpusvm,
- struct drm_gpusvm_range *range,
- const struct drm_gpusvm_ctx *ctx)
-{
- unsigned long npages = npages_in_range(drm_gpusvm_range_start(range),
- drm_gpusvm_range_end(range));
-
- return drm_gpusvm_unmap_pages(gpusvm, &range->pages, npages, ctx);
-}
-EXPORT_SYMBOL_GPL(drm_gpusvm_range_unmap_pages);
-
-/**
* drm_gpusvm_range_evict() - Evict GPU SVM range
* @gpusvm: Pointer to the GPU SVM structure
* @range: Pointer to the GPU SVM range to be removed
@@ -1784,20 +1809,40 @@ EXPORT_SYMBOL_GPL(drm_gpusvm_has_mapping);
/**
* drm_gpusvm_range_set_unmapped() - Mark a GPU SVM range as unmapped
* @range: Pointer to the GPU SVM range structure.
+ * @pages: Pointer to the GPU SVM pages structure(s).
+ * @pages_count: Number of GPU SVM pages structure(s) passed in.
* @mmu_range: Pointer to the MMU notifier range structure.
*
* This function marks a GPU SVM range as unmapped and sets the partial_unmap flag
* if the range partially falls within the provided MMU notifier range.
*/
void drm_gpusvm_range_set_unmapped(struct drm_gpusvm_range *range,
+ struct drm_gpusvm_pages *pages,
+ unsigned int pages_count,
const struct mmu_notifier_range *mmu_range)
{
+ struct drm_gpusvm_range_flags range_flags = {
+ .__flags = range->flags.__flags,
+ };
+ unsigned int i;
+
lockdep_assert_held_write(&range->gpusvm->notifier_lock);
- range->pages.flags.unmapped = true;
+ range_flags.unmapped = true;
+ for (i = 0; i < pages_count; ++i) {
+ struct drm_gpusvm_pages_flags flags = {
+ .__flags = pages[i].flags.__flags,
+ };
+
+ flags.unmapped = true;
+ /* WRITE_ONCE pairs with READ_ONCE for opportunistic checks */
+ WRITE_ONCE(pages[i].flags.__flags, flags.__flags);
+ }
if (drm_gpusvm_range_start(range) < mmu_range->start ||
drm_gpusvm_range_end(range) > mmu_range->end)
- range->pages.flags.partial_unmap = true;
+ range_flags.partial_unmap = true;
+ /* WRITE_ONCE pairs with READ_ONCE for opportunistic checks */
+ WRITE_ONCE(range->flags.__flags, range_flags.__flags);
}
EXPORT_SYMBOL_GPL(drm_gpusvm_range_set_unmapped);
diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c
index d03ada82eac9..96eef327bf7e 100644
--- a/drivers/gpu/drm/drm_of.c
+++ b/drivers/gpu/drm/drm_of.c
@@ -7,6 +7,7 @@
#include <linux/of_graph.h>
#include <drm/drm_bridge.h>
+#include <drm/drm_connector.h>
#include <drm/drm_crtc.h>
#include <drm/drm_device.h>
#include <drm/drm_encoder.h>
@@ -221,6 +222,49 @@ int drm_of_encoder_active_endpoint(struct device_node *node,
EXPORT_SYMBOL_GPL(drm_of_encoder_active_endpoint);
/**
+ * drm_of_get_panel_orientation - look up the orientation of the panel through
+ * the "rotation" binding from a device tree node
+ * @np: device tree node of the panel
+ * @orientation: orientation enum to be filled in
+ *
+ * Looks up the rotation of a panel in the device tree. The orientation of the
+ * panel is expressed as a property name "rotation" in the device tree. The
+ * rotation in the device tree is counter clockwise.
+ *
+ * Return: 0 when a valid rotation value (0, 90, 180, or 270) is read or the
+ * rotation property doesn't exist. Return a negative error code on failure.
+ */
+int drm_of_get_panel_orientation(const struct device_node *np,
+ enum drm_panel_orientation *orientation)
+{
+ int rotation, ret;
+
+ ret = of_property_read_u32(np, "rotation", &rotation);
+ if (ret == -EINVAL) {
+ /* Don't return an error if there's no rotation property. */
+ *orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
+ return 0;
+ }
+
+ if (ret < 0)
+ return ret;
+
+ if (rotation == 0)
+ *orientation = DRM_MODE_PANEL_ORIENTATION_NORMAL;
+ else if (rotation == 90)
+ *orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP;
+ else if (rotation == 180)
+ *orientation = DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP;
+ else if (rotation == 270)
+ *orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP;
+ else
+ return -EINVAL;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(drm_of_get_panel_orientation);
+
+/**
* drm_of_find_panel_or_bridge - return connected panel or bridge device
* @np: device tree node containing encoder output ports
* @port: port in the device tree node
diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c
index 2c5649e433df..d7c6f4824b2d 100644
--- a/drivers/gpu/drm/drm_panel.c
+++ b/drivers/gpu/drm/drm_panel.c
@@ -28,6 +28,7 @@
#include <linux/of.h>
#include <drm/drm_crtc.h>
+#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <drm/drm_print.h>
@@ -491,49 +492,6 @@ struct drm_panel *of_drm_find_panel(const struct device_node *np)
return ERR_PTR(-EPROBE_DEFER);
}
EXPORT_SYMBOL(of_drm_find_panel);
-
-/**
- * of_drm_get_panel_orientation - look up the orientation of the panel through
- * the "rotation" binding from a device tree node
- * @np: device tree node of the panel
- * @orientation: orientation enum to be filled in
- *
- * Looks up the rotation of a panel in the device tree. The orientation of the
- * panel is expressed as a property name "rotation" in the device tree. The
- * rotation in the device tree is counter clockwise.
- *
- * Return: 0 when a valid rotation value (0, 90, 180, or 270) is read or the
- * rotation property doesn't exist. Return a negative error code on failure.
- */
-int of_drm_get_panel_orientation(const struct device_node *np,
- enum drm_panel_orientation *orientation)
-{
- int rotation, ret;
-
- ret = of_property_read_u32(np, "rotation", &rotation);
- if (ret == -EINVAL) {
- /* Don't return an error if there's no rotation property. */
- *orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
- return 0;
- }
-
- if (ret < 0)
- return ret;
-
- if (rotation == 0)
- *orientation = DRM_MODE_PANEL_ORIENTATION_NORMAL;
- else if (rotation == 90)
- *orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP;
- else if (rotation == 180)
- *orientation = DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP;
- else if (rotation == 270)
- *orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP;
- else
- return -EINVAL;
-
- return 0;
-}
-EXPORT_SYMBOL(of_drm_get_panel_orientation);
#endif
/* Find panel by fwnode. This should be identical to of_drm_find_panel(). */
diff --git a/drivers/gpu/drm/i915/.kunitconfig b/drivers/gpu/drm/i915/.kunitconfig
new file mode 100644
index 000000000000..1b47fe62b285
--- /dev/null
+++ b/drivers/gpu/drm/i915/.kunitconfig
@@ -0,0 +1,9 @@
+CONFIG_EXPERT=y
+CONFIG_MODULES=y
+CONFIG_KUNIT=y
+CONFIG_PCI=y
+CONFIG_DEBUG_FS=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DRM=y
+CONFIG_DRM_I915=y
+CONFIG_DRM_I915_KUNIT_TEST=y
diff --git a/drivers/gpu/drm/i915/Kconfig.debug b/drivers/gpu/drm/i915/Kconfig.debug
index 52a3a59b4ba2..dc43dcfbadb6 100644
--- a/drivers/gpu/drm/i915/Kconfig.debug
+++ b/drivers/gpu/drm/i915/Kconfig.debug
@@ -220,6 +220,18 @@ config DRM_I915_SELFTEST_BROKEN
If in doubt, say "N".
+config DRM_I915_KUNIT_TEST
+ tristate "KUnit tests for the drm i915 driver" if !KUNIT_ALL_TESTS
+ depends on DRM_I915 && KUNIT && DEBUG_FS
+ default KUNIT_ALL_TESTS
+ help
+ Choose this option to allow the driver to perform selftests under
+ the kunit framework
+
+ Recommended for driver developers only.
+
+ If in doubt, say "N".
+
config DRM_I915_LOW_LEVEL_TRACEPOINTS
bool "Enable low level request tracing events"
depends on DRM_I915
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index c4de717505d7..a83fa8be0aba 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -386,6 +386,8 @@ i915-y += \
i915-$(CONFIG_DRM_I915_DP_TUNNEL) += \
display/intel_dp_tunnel.o
+obj-$(CONFIG_DRM_I915_KUNIT_TEST) += display/tests/
+
i915-$(CONFIG_DRM_I915_GVT) += \
display/intel_gvt_api.o
diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c
index 9729f1837d2c..eae76e961105 100644
--- a/drivers/gpu/drm/i915/display/intel_audio.c
+++ b/drivers/gpu/drm/i915/display/intel_audio.c
@@ -38,6 +38,7 @@
#include "intel_de.h"
#include "intel_display_types.h"
#include "intel_display_wa.h"
+#include "intel_dp.h"
#include "intel_lpe_audio.h"
/**
@@ -696,6 +697,13 @@ static void ibx_audio_codec_enable(struct intel_encoder *encoder,
mutex_unlock(&display->audio.mutex);
}
+static
+bool intel_audio_needs_cpu_transcoder_id(const struct intel_crtc_state *crtc_state)
+{
+ return intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST) ||
+ intel_dp_is_uhbr(crtc_state);
+}
+
bool intel_audio_compute_config(struct intel_encoder *encoder,
struct intel_crtc_state *crtc_state,
struct drm_connector_state *conn_state)
@@ -762,6 +770,8 @@ void intel_audio_codec_enable(struct intel_encoder *encoder,
audio_state = &display->audio.state[cpu_transcoder];
audio_state->encoder = encoder;
+ audio_state->needs_cpu_transcoder_id =
+ intel_audio_needs_cpu_transcoder_id(crtc_state);
BUILD_BUG_ON(sizeof(audio_state->eld) != sizeof(crtc_state->eld));
memcpy(audio_state->eld, crtc_state->eld, sizeof(audio_state->eld));
@@ -769,8 +779,12 @@ void intel_audio_codec_enable(struct intel_encoder *encoder,
if (acomp && acomp->base.audio_ops &&
acomp->base.audio_ops->pin_eld_notify) {
- /* audio drivers expect cpu_transcoder = -1 to indicate Non-MST cases */
- if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST))
+ /*
+ * Audio drivers expect cpu_transcoder = -1 to indicate
+ * Non-MST/HBR cases. MST and UHBR SST are addressed by
+ * a real cpu_transcoder.
+ */
+ if (!intel_audio_needs_cpu_transcoder_id(crtc_state))
cpu_transcoder = -1;
acomp->base.audio_ops->pin_eld_notify(acomp->base.audio_ops->audio_ptr,
(int)port, (int)cpu_transcoder);
@@ -819,14 +833,19 @@ void intel_audio_codec_disable(struct intel_encoder *encoder,
audio_state = &display->audio.state[cpu_transcoder];
audio_state->encoder = NULL;
+ audio_state->needs_cpu_transcoder_id = false;
memset(audio_state->eld, 0, sizeof(audio_state->eld));
mutex_unlock(&display->audio.mutex);
if (acomp && acomp->base.audio_ops &&
acomp->base.audio_ops->pin_eld_notify) {
- /* audio drivers expect cpu_transcoder = -1 to indicate Non-MST cases */
- if (!intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_DP_MST))
+ /*
+ * Audio drivers expect cpu_transcoder = -1 to indicate
+ * Non-MST/HBR cases. MST and UHBR SST are addressed by
+ * a real cpu_transcoder.
+ */
+ if (!intel_audio_needs_cpu_transcoder_id(old_crtc_state))
cpu_transcoder = -1;
acomp->base.audio_ops->pin_eld_notify(acomp->base.audio_ops->audio_ptr,
(int)port, (int)cpu_transcoder);
@@ -1118,18 +1137,24 @@ static int intel_audio_component_get_cdclk_freq(struct device *kdev)
}
/*
- * get the intel audio state according to the parameter port and cpu_transcoder
- * MST & (cpu_transcoder >= 0): return the audio.state[cpu_transcoder].encoder],
- * when port is matched
- * MST & (cpu_transcoder < 0): this is invalid
- * Non-MST & (cpu_transcoder >= 0): only cpu_transcoder = 0 (the first device entry)
- * will get the right intel_encoder with port matched
- * Non-MST & (cpu_transcoder < 0): get the right intel_encoder with port matched
+ * Get the intel audio state for a given (port, cpu_transcoder).
+ *
+ * Streams are addressed either by a real cpu_transcoder (DP MST and UHBR SST,
+ * i.e. entries whose stored needs_cpu_transcoder_id is true) or by port alone
+ * (legacy SST). Both the signalling side (pin_eld_notify()) and the lookup
+ * side use the same predicate, so the two are symmetric.
+ *
+ * cpu_transcoder >= 0 & needs_cpu_transcoder_id: return audio.state[cpu_transcoder]
+ * when the port matches.
+ * cpu_transcoder < 0 & !needs_cpu_transcoder_id: return the first port-matching
+ * entry.
+ * cpu_transcoder = 0 & !needs_cpu_transcoder_id: falls to the port-only
+ * loop so the first device entry of a legacy SST port is still found.
*/
static struct intel_audio_state *find_audio_state(struct intel_display *display,
int port, int cpu_transcoder)
{
- /* MST */
+ /* MST, or UHBR SST. */
if (cpu_transcoder >= 0) {
struct intel_audio_state *audio_state;
struct intel_encoder *encoder;
@@ -1142,11 +1167,11 @@ static struct intel_audio_state *find_audio_state(struct intel_display *display,
encoder = audio_state->encoder;
if (encoder && encoder->port == port &&
- encoder->type == INTEL_OUTPUT_DP_MST)
+ audio_state->needs_cpu_transcoder_id)
return audio_state;
}
- /* Non-MST */
+ /* Legacy SST. */
if (cpu_transcoder > 0)
return NULL;
@@ -1158,7 +1183,7 @@ static struct intel_audio_state *find_audio_state(struct intel_display *display,
encoder = audio_state->encoder;
if (encoder && encoder->port == port &&
- encoder->type != INTEL_OUTPUT_DP_MST)
+ !audio_state->needs_cpu_transcoder_id)
return audio_state;
}
diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index 90c05ad08f86..214454f419e9 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -45,6 +45,7 @@
#include <drm/drm_probe_helper.h>
#include <drm/drm_rect.h>
#include <drm/drm_vblank.h>
+#include <drm/intel/step.h>
#include "g4x_dp.h"
#include "g4x_hdmi.h"
@@ -2737,6 +2738,10 @@ void intel_set_transcoder_timings(const struct intel_crtc_state *crtc_state,
HSYNC_START(adjusted_mode->crtc_hsync_start - 1) |
HSYNC_END(adjusted_mode->crtc_hsync_end - 1));
+ if (display->platform.novalake &&
+ IS_DISPLAY_STEP(display, STEP_A0, STEP_C0))
+ crtc_vtotal = 1;
+
intel_de_write(display, TRANS_VTOTAL(display, transcoder),
VACTIVE(crtc_vdisplay - 1) |
VTOTAL(crtc_vtotal - 1));
@@ -2830,6 +2835,10 @@ void intel_set_transcoder_timings_lrr(const struct intel_crtc_state *crtc_state,
* The double buffer latch point for TRANS_VTOTAL
* is the transcoder's undelayed vblank.
*/
+ if (display->platform.novalake &&
+ IS_DISPLAY_STEP(display, STEP_A0, STEP_C0))
+ crtc_vtotal = 1;
+
intel_de_write(display, TRANS_VTOTAL(display, transcoder),
VACTIVE(crtc_vdisplay - 1) |
VTOTAL(crtc_vtotal - 1));
diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h b/drivers/gpu/drm/i915/display/intel_display_core.h
index 17f7d3abdb9c..7e988b7b1fe7 100644
--- a/drivers/gpu/drm/i915/display/intel_display_core.h
+++ b/drivers/gpu/drm/i915/display/intel_display_core.h
@@ -97,6 +97,8 @@ struct intel_wm_funcs {
struct intel_audio_state {
struct intel_encoder *encoder;
u8 eld[MAX_ELD_BYTES];
+ /* MST, or SST on UHBR link */
+ bool needs_cpu_transcoder_id;
};
struct intel_audio {
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index ade7e51e7590..0922d23b284c 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -354,44 +354,6 @@ static int intel_dp_get_max_common_lane_count(struct intel_dp *intel_dp)
return min3(source_max, sink_max, lane_max);
}
-int intel_dp_max_lane_count(struct intel_dp *intel_dp)
-{
- struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
- struct intel_dp_link_config max_link_limits;
- struct intel_dp_link_config forced_params;
- int lane_count;
-
- intel_dp_link_caps_get_max_limits(link_caps, &max_link_limits);
- intel_dp_link_caps_get_forced_params(link_caps, &forced_params);
-
- if (forced_params.lane_count)
- lane_count = forced_params.lane_count;
- else
- lane_count = max_link_limits.lane_count;
-
- switch (lane_count) {
- case 1:
- case 2:
- case 4:
- return lane_count;
- default:
- MISSING_CASE(lane_count);
- return 1;
- }
-}
-
-static int intel_dp_min_lane_count(struct intel_dp *intel_dp)
-{
- struct intel_dp_link_config forced_params;
-
- intel_dp_link_caps_get_forced_params(intel_dp->link.caps, &forced_params);
-
- if (forced_params.lane_count)
- return forced_params.lane_count;
-
- return 1;
-}
-
int intel_dp_link_bw_overhead(int link_clock, int lane_count, int hdisplay,
int dsc_slice_count, int bpp_x16, unsigned long flags)
{
@@ -701,7 +663,8 @@ static bool intel_dp_set_common_link_params(struct intel_dp *intel_dp)
intel_dp_get_common_rates(intel_dp, common_rates, &num_common_rates);
if (intel_dp_link_caps_update(intel_dp->link.caps,
common_rates, num_common_rates,
- intel_dp_get_max_common_lane_count(intel_dp)))
+ intel_dp_get_max_common_lane_count(intel_dp),
+ intel_dp->reset_link_params))
params_changed = true;
return params_changed;
@@ -1330,6 +1293,7 @@ intel_dp_mode_valid_format(struct intel_connector *connector,
struct intel_dp *intel_dp = intel_attached_dp(connector);
enum intel_output_format output_format;
int max_rate, mode_rate, max_lanes, max_link_clock;
+ struct intel_dp_link_config max_bw_config;
u16 dsc_max_compressed_bpp = 0;
enum drm_mode_status status;
bool dsc = false;
@@ -1342,8 +1306,9 @@ intel_dp_mode_valid_format(struct intel_connector *connector,
output_format = intel_dp_output_format(connector, sink_format);
- max_link_clock = intel_dp_max_link_rate(intel_dp);
- max_lanes = intel_dp_max_lane_count(intel_dp);
+ intel_dp_link_caps_get_max_bw_config(intel_dp->link.caps, &max_bw_config);
+ max_link_clock = max_bw_config.rate;
+ max_lanes = max_bw_config.lane_count;
max_rate = intel_dp_max_link_data_rate(intel_dp, max_link_clock, max_lanes);
@@ -1537,39 +1502,6 @@ static void intel_dp_print_rates(struct intel_dp *intel_dp)
intel_dp_link_caps_print_common_rates(intel_dp->link.caps);
}
-int
-intel_dp_max_link_rate(struct intel_dp *intel_dp)
-{
- struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
- struct intel_dp_link_config max_link_limits;
- struct intel_dp_link_config forced_params;
- int len;
-
- intel_dp_link_caps_get_forced_params(link_caps, &forced_params);
-
- if (forced_params.rate)
- return forced_params.rate;
-
- intel_dp_link_caps_get_max_limits(link_caps, &max_link_limits);
- len = intel_dp_common_len_rate_limit(link_caps, max_link_limits.rate);
-
- return intel_dp_common_rate(link_caps, len - 1);
-}
-
-static int
-intel_dp_min_link_rate(struct intel_dp *intel_dp)
-{
- struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
- struct intel_dp_link_config forced_params;
-
- intel_dp_link_caps_get_forced_params(intel_dp->link.caps, &forced_params);
-
- if (forced_params.rate)
- return forced_params.rate;
-
- return intel_dp_common_rate(link_caps, 0);
-}
-
int intel_dp_rate_select(struct intel_dp *intel_dp, int rate)
{
struct intel_display *display = to_intel_display(intel_dp);
@@ -1751,43 +1683,42 @@ intel_dp_compute_link_config_wide(struct intel_dp *intel_dp,
const struct drm_connector_state *conn_state,
const struct link_config_limits *limits)
{
+ struct intel_connector *connector = to_intel_connector(conn_state->connector);
+ int bpp, clock = intel_dp_mode_clock(pipe_config, conn_state);
struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
- int bpp, i, lane_count, clock = intel_dp_mode_clock(pipe_config, conn_state);
- int link_rate, link_avail;
+ struct intel_dp_link_caps_order order =
+ intel_dp_link_caps_connector_compute_order(connector);
+ int link_avail;
for (bpp = fxp_q4_to_int(limits->link.max_bpp_x16);
bpp >= fxp_q4_to_int(limits->link.min_bpp_x16);
bpp -= 2 * 3) {
int link_bpp_x16 =
intel_dp_output_format_link_bpp_x16(pipe_config->output_format, bpp);
+ struct intel_dp_link_config link_config;
+ struct intel_dp_link_caps_iter iter;
- for (i = 0; i < intel_dp_link_caps_num_common_rates(intel_dp->link.caps); i++) {
- link_rate = intel_dp_common_rate(link_caps, i);
- if (link_rate < limits->min_rate ||
- link_rate > limits->max_rate)
- continue;
-
- for (lane_count = limits->min_lane_count;
- lane_count <= limits->max_lane_count;
- lane_count <<= 1) {
- const struct drm_display_mode *adjusted_mode =
+ intel_dp_link_caps_iter_start(&iter, link_caps, order, limits->link_config_filter);
+ for_each_dp_link_config(&iter, &link_config) {
+ const struct drm_display_mode *adjusted_mode =
&pipe_config->hw.adjusted_mode;
- int mode_rate =
- intel_dp_link_required(link_rate, lane_count,
- clock, adjusted_mode->hdisplay,
- link_bpp_x16, 0);
-
- link_avail = intel_dp_max_link_data_rate(intel_dp,
- link_rate,
- lane_count);
-
- if (mode_rate <= link_avail) {
- pipe_config->lane_count = lane_count;
- pipe_config->pipe_bpp = bpp;
- pipe_config->port_clock = link_rate;
-
- return 0;
- }
+ int mode_rate;
+
+ mode_rate = intel_dp_link_required(link_config.rate,
+ link_config.lane_count,
+ clock, adjusted_mode->hdisplay,
+ link_bpp_x16, 0);
+
+ link_avail = intel_dp_max_link_data_rate(intel_dp,
+ link_config.rate,
+ link_config.lane_count);
+
+ if (mode_rate <= link_avail) {
+ pipe_config->lane_count = link_config.lane_count;
+ pipe_config->pipe_bpp = bpp;
+ pipe_config->port_clock = link_config.rate;
+
+ return 0;
}
}
}
@@ -1986,60 +1917,56 @@ static int dsc_compute_link_config(struct intel_dp *intel_dp,
const struct link_config_limits *limits,
int dsc_bpp_x16)
{
- struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
- int link_rate, lane_count;
- int i;
-
- for (i = 0; i < intel_dp_link_caps_num_common_rates(intel_dp->link.caps); i++) {
- link_rate = intel_dp_common_rate(link_caps, i);
- if (link_rate < limits->min_rate || link_rate > limits->max_rate)
- continue;
+ struct intel_connector *connector = to_intel_connector(conn_state->connector);
+ struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
+ struct intel_dp_link_caps_order order =
+ intel_dp_link_caps_connector_compute_order(connector);
+ struct intel_dp_link_config link_config;
+ struct intel_dp_link_caps_iter iter;
- for (lane_count = limits->min_lane_count;
- lane_count <= limits->max_lane_count;
- lane_count <<= 1) {
+ intel_dp_link_caps_iter_start(&iter, link_caps, order, limits->link_config_filter);
+ for_each_dp_link_config(&iter, &link_config) {
+ /*
+ * FIXME: intel_dp_mtp_tu_compute_config() requires
+ * ->lane_count and ->port_clock set before we know
+ * they'll work. If we end up failing altogether,
+ * they'll remain in crtc state. This shouldn't matter,
+ * as we'd then bail out from compute config, but it's
+ * just ugly.
+ */
+ pipe_config->lane_count = link_config.lane_count;
+ pipe_config->port_clock = link_config.rate;
- /*
- * FIXME: intel_dp_mtp_tu_compute_config() requires
- * ->lane_count and ->port_clock set before we know
- * they'll work. If we end up failing altogether,
- * they'll remain in crtc state. This shouldn't matter,
- * as we'd then bail out from compute config, but it's
- * just ugly.
- */
- pipe_config->lane_count = lane_count;
- pipe_config->port_clock = link_rate;
-
- if (drm_dp_is_uhbr_rate(link_rate)) {
- int ret;
-
- ret = intel_dp_mtp_tu_compute_config(intel_dp,
- pipe_config,
- conn_state,
- dsc_bpp_x16,
- dsc_bpp_x16,
- 0, true);
- if (ret)
- continue;
- } else {
- unsigned long bw_overhead_flags =
- pipe_config->fec_enable ? DRM_DP_BW_OVERHEAD_FEC : 0;
- int line_slice_count =
- intel_dsc_line_slice_count(&pipe_config->dsc.slice_config);
-
- if (!is_bw_sufficient_for_dsc_config(intel_dp,
- link_rate, lane_count,
- adjusted_mode->crtc_clock,
- adjusted_mode->hdisplay,
- line_slice_count,
- dsc_bpp_x16,
- bw_overhead_flags))
- continue;
- }
+ if (drm_dp_is_uhbr_rate(link_config.rate)) {
+ int ret;
- return 0;
+ ret = intel_dp_mtp_tu_compute_config(intel_dp,
+ pipe_config,
+ conn_state,
+ dsc_bpp_x16,
+ dsc_bpp_x16,
+ 0, true);
+ if (ret)
+ continue;
+ } else {
+ unsigned long bw_overhead_flags =
+ pipe_config->fec_enable ? DRM_DP_BW_OVERHEAD_FEC : 0;
+ int line_slice_count =
+ intel_dsc_line_slice_count(&pipe_config->dsc.slice_config);
+
+ if (!is_bw_sufficient_for_dsc_config(intel_dp,
+ link_config.rate,
+ link_config.lane_count,
+ adjusted_mode->crtc_clock,
+ adjusted_mode->hdisplay,
+ line_slice_count,
+ dsc_bpp_x16,
+ bw_overhead_flags))
+ continue;
}
+
+ return 0;
}
return -EINVAL;
@@ -2250,7 +2177,7 @@ static int dsc_compute_compressed_bpp(struct intel_dp *intel_dp,
int pipe_bpp)
{
struct intel_display *display = to_intel_display(intel_dp);
- const struct intel_connector *connector = to_intel_connector(conn_state->connector);
+ struct intel_connector *connector = to_intel_connector(conn_state->connector);
int min_bpp_x16, max_bpp_x16, bpp_step_x16;
int bpp_x16;
int ret;
@@ -2262,8 +2189,19 @@ static int dsc_compute_compressed_bpp(struct intel_dp *intel_dp,
max_bpp_x16 = align_max_compressed_bpp_x16(connector, pipe_config->output_format,
pipe_bpp, max_bpp_x16);
if (intel_dp_is_edp(intel_dp)) {
- pipe_config->port_clock = limits->max_rate;
- pipe_config->lane_count = limits->max_lane_count;
+ struct intel_dp_link_config max_link_config;
+
+ /*
+ * FIXME: Clarify why eDP does not use the regular SST BW
+ * check and instead always uses the maximum link config,
+ * regardless of intel_dp::use_max_params. Then unify this eDP
+ * path with the regular DP path.
+ */
+ if (!intel_dp_get_connector_max_link_config(connector, limits, &max_link_config))
+ return -EINVAL;
+
+ pipe_config->port_clock = max_link_config.rate;
+ pipe_config->lane_count = max_link_config.lane_count;
pipe_config->dsc.compressed_bpp_x16 = max_bpp_x16;
@@ -2576,6 +2514,20 @@ bool intel_dp_mode_valid_with_dsc(struct intel_connector *connector,
bw_overhead_flags);
}
+bool
+intel_dp_get_connector_max_link_config(struct intel_connector *connector,
+ const struct link_config_limits *limits,
+ struct intel_dp_link_config *max_link_config)
+{
+ struct intel_dp *intel_dp = intel_attached_dp(connector);
+ struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
+ struct intel_dp_link_caps_order order =
+ intel_dp_link_caps_connector_compute_order(connector);
+
+ return intel_dp_link_caps_get_max_config(link_caps, order.key, limits->link_config_filter,
+ max_link_config);
+}
+
/*
* Calculate the output link min, max bpp values in limits based on the pipe bpp
* range, crtc_state and dsc mode. Return true on success.
@@ -2592,6 +2544,7 @@ intel_dp_compute_config_link_bpp_limits(struct intel_connector *connector,
&crtc_state->hw.adjusted_mode;
const struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
const struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
+ struct intel_dp_link_config max_link_config;
int max_link_bpp_x16;
max_link_bpp_x16 = min(crtc_state->max_link_bpp_x16,
@@ -2621,14 +2574,17 @@ intel_dp_compute_config_link_bpp_limits(struct intel_connector *connector,
limits->link.max_bpp_x16 = max_link_bpp_x16;
+ if (!intel_dp_get_connector_max_link_config(connector, limits, &max_link_config))
+ return false;
+
drm_dbg_kms(display->drm,
- "[ENCODER:%d:%s][CRTC:%d:%s] DP link limits: pixel clock %d kHz DSC %s max lanes %d max rate %d max pipe_bpp %d min link_bpp " FXP_Q4_FMT " max link_bpp " FXP_Q4_FMT "\n",
+ "[ENCODER:%d:%s][CRTC:%d:%s] DP link limits: pixel clock %d kHz DSC %s max link %dx%d max pipe_bpp %d min link_bpp " FXP_Q4_FMT " max link_bpp " FXP_Q4_FMT "\n",
encoder->base.base.id, encoder->base.name,
crtc->base.base.id, crtc->base.name,
adjusted_mode->crtc_clock,
str_on_off(dsc),
- limits->max_lane_count,
- limits->max_rate,
+ max_link_config.lane_count,
+ max_link_config.rate,
limits->pipe.max_bpp,
FXP_Q4_ARGS(limits->link.min_bpp_x16),
FXP_Q4_ARGS(limits->link.max_bpp_x16));
@@ -2679,17 +2635,12 @@ intel_dp_compute_config_limits(struct intel_dp *intel_dp,
struct link_config_limits *limits)
{
struct intel_display *display = to_intel_display(intel_dp);
+ struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
bool is_mst = intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST);
struct intel_connector *connector =
to_intel_connector(conn_state->connector);
- limits->min_rate = intel_dp_min_link_rate(intel_dp);
- limits->max_rate = intel_dp_max_link_rate(intel_dp);
-
- limits->min_rate = min(limits->min_rate, limits->max_rate);
-
- limits->min_lane_count = intel_dp_min_lane_count(intel_dp);
- limits->max_lane_count = intel_dp_max_lane_count(intel_dp);
+ limits->link_config_filter = INTEL_DP_LINK_CAPS_FILTER_ALL;
limits->pipe.min_bpp = intel_dp_min_bpp(crtc_state->output_format);
if (is_mst) {
@@ -2754,6 +2705,9 @@ intel_dp_compute_config_limits(struct intel_dp *intel_dp,
crtc_state->pipe_bpp, limits->pipe.max_bpp);
if (is_mst || intel_dp->use_max_params) {
+ struct intel_dp_link_caps_filter new_filter = INTEL_DP_LINK_CAPS_FILTER_NONE;
+ struct intel_dp_link_config max_config;
+
/*
* For MST we always configure max link bw - the spec doesn't
* seem to suggest we should do otherwise.
@@ -2765,11 +2719,17 @@ intel_dp_compute_config_limits(struct intel_dp *intel_dp,
* configuration, and typically on older panels these
* values correspond to the native resolution of the panel.
*/
- limits->min_lane_count = limits->max_lane_count;
- limits->min_rate = limits->max_rate;
+ if (!intel_dp_get_connector_max_link_config(connector, limits, &max_config))
+ return false;
+
+ if (!intel_dp_link_caps_filter_add(link_caps, &new_filter, &max_config))
+ return false;
+
+ limits->link_config_filter = new_filter;
}
- intel_dp_test_compute_config(intel_dp, crtc_state, limits);
+ if (!intel_dp_test_compute_config(connector, crtc_state, limits))
+ return false;
return intel_dp_compute_config_link_bpp_limits(connector,
crtc_state,
@@ -3652,6 +3612,11 @@ void intel_dp_set_link_params(struct intel_dp *intel_dp,
void intel_dp_reset_link_params(struct intel_dp *intel_dp)
{
+ /*
+ * TODO: Remove the following reset of link capabilities, as
+ * this isn't needed after intel_dp_link_caps_update(reset=true)
+ * was called.
+ */
intel_dp_link_caps_reset(intel_dp->link.caps);
intel_dp->link.mst_probed_lane_count = 0;
intel_dp->link.mst_probed_rate = 0;
diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h
index 02b691df6755..0ec519fa1236 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.h
+++ b/drivers/gpu/drm/i915/display/intel_dp.h
@@ -8,6 +8,8 @@
#include <linux/types.h>
+#include "intel_dp_link_caps.h"
+
enum intel_output_format;
enum pipe;
enum port;
@@ -22,11 +24,11 @@ struct intel_crtc_state;
struct intel_digital_port;
struct intel_display;
struct intel_dp;
+struct intel_dp_link_config;
struct intel_encoder;
struct link_config_limits {
- int min_rate, max_rate;
- int min_lane_count, max_lane_count;
+ struct intel_dp_link_caps_filter link_config_filter;
struct {
/* Uncompressed DSC input or link output bpp in 1 bpp units */
int min_bpp, max_bpp;
@@ -103,8 +105,6 @@ void intel_dp_mst_suspend(struct intel_display *display);
void intel_dp_mst_resume(struct intel_display *display);
int intel_dp_rate_limit_len(const int *rates, int len, int max_rate);
int intel_dp_max_source_lane_count(struct intel_digital_port *dig_port);
-int intel_dp_max_link_rate(struct intel_dp *intel_dp);
-int intel_dp_max_lane_count(struct intel_dp *intel_dp);
int intel_dp_config_required_rate(const struct intel_crtc_state *crtc_state);
int intel_dp_rate_select(struct intel_dp *intel_dp, int rate);
int intel_dp_rate_index(const int *rates, int len, int rate);
@@ -144,6 +144,9 @@ int intel_dp_dsc_compute_max_bpp(const struct intel_connector *connector,
u8 dsc_max_bpc);
int intel_dp_compute_min_compressed_bpp_x16(struct intel_connector *connector,
enum intel_output_format output_format);
+bool intel_dp_get_connector_max_link_config(struct intel_connector *connector,
+ const struct link_config_limits *limits,
+ struct intel_dp_link_config *max_link_config);
bool intel_dp_mode_valid_with_dsc(struct intel_connector *connector,
int link_clock, int lane_count,
int mode_clock, int mode_hdisplay,
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 1c34ba6c49c3..7b6cc6055da8 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -16,9 +16,91 @@
#include "intel_display_core.h"
#include "intel_display_types.h"
+#include "intel_display_utils.h"
#include "intel_dp.h"
#include "intel_dp_link_caps.h"
+/**
+ * DOC: DisplayPort link capabilities
+ *
+ * The Intel DP link caps API tracks the supported and allowed
+ * DisplayPort link configurations for a DP encoder and its attached
+ * connectors, and provides helpers to iterate over the allowed
+ * configurations and constrain them by filtering, disabling, or
+ * limiting them to maximum link parameters.
+ *
+ * Locking
+ * -------
+ *
+ * All accesses to this API must be serialized. The only exception
+ * is intel_dp_link_caps_get_max_limits(), which allow lockless
+ * lookup. Such lookups may observe an out-of-sync &struct
+ * intel_dp_link_config tuple, i.e. a rate from one state and a lane
+ * count from another.
+ *
+ * The Intel i915/xe drivers ensure the above serialization by holding
+ * &drm_mode_config.connection_mutex and, while holding the lock,
+ * waiting for any pending asynchronous atomic commits. This also allows
+ * use of the API from the tails of asynchronous atomic commits, which
+ * cannot hold the lock.
+ *
+ * Iterating and restricting link configurations
+ * ---------------------------------------------
+ *
+ * The link configuration iterators can iterate the ``allowed
+ * configurations`` during modeset configuration selection or link
+ * training fallback handling in a configurable order.
+ *
+ * The iteration order can depend on connector type (eDP, DP SST,
+ * DP MST) and modeset-specific conditions or driver policies, such
+ * as DSC vs. non-DSC modes, power saving vs. better user experience,
+ * or policy changes after a link training failure.
+ *
+ * The configurations exposed via the iterators can be additionally
+ * constrained in the following ways:
+ *
+ * - Filtered for a given modeset based on modeset-specific conditions.
+ * Examples for such conditions include driver policies preferring
+ * power saving or better user experience, post-link training failure
+ * preference changes, or sink automated test requests limiting the
+ * usable configurations.
+ *
+ * - Disabled permanently for the connected sink. Examples of reasons
+ * to disable a configuration include a link training failure for a
+ * given configuration or a driver workaround preventing the use of
+ * a particular configuration.
+ *
+ * - Limited via a maximum link rate and lane count. For example, after
+ * a link training failure, subsequent modesets may be limited to
+ * configurations at or below the failed parameters.
+ *
+ * This mechanism exists for backward compatibility only. Eventually,
+ * it will be removed in favor of relying solely on individually
+ * disabled configurations, as described above.
+ *
+ * Terminology
+ * -----------
+ *
+ * ``Common link capabilities`` (or ``common caps``) refer to the link
+ * rates and maximum lane count supported by both the source and the
+ * sink, i.e. the intersection of their respective capabilities.
+ *
+ * ``Supported configurations`` are all configurations defined by the
+ * ``Common link capabilities``' link rates and maximum lane count.
+ *
+ * ``Disabled configurations`` are ``Supported configurations`` disabled
+ * via this API.
+ *
+ * ``Enabled configurations`` are ``Supported configurations`` that are
+ * not disabled.
+ *
+ * ``Forced configurations`` are ``Enabled configurations`` forced via
+ * forced link parameter debugfs entries.
+ *
+ * ``Allowed configurations`` are the ``Enabled configurations``, or if
+ * forcing is in effect the ``Forced configurations``, constrained by a
+ * maximum rate and lane count set via the API.
+ */
struct intel_dp_link_caps {
struct intel_dp *dp;
@@ -42,6 +124,44 @@ struct intel_dp_link_caps {
} configs[INTEL_DP_MAX_LINK_CONFIGS];
/*
+ * Indices to intel_dp_link_caps::configs[] in rate/lane count,
+ * lane_count/rate order.
+ */
+ u8 rate_lane_map[INTEL_DP_MAX_LINK_CONFIGS];
+ u8 lane_rate_map[INTEL_DP_MAX_LINK_CONFIGS];
+
+ /*
+ * Filter of configurations enabled for the current sink
+ * connection.
+ *
+ * Each bit in the filter's configuration mask corresponds to a
+ * configuration index in the intel_dp_link_caps::configs[] array.
+ *
+ * All configurations start out enabled in the filter after a
+ * new sink is connected. Users disable configurations afterwards
+ * via the link caps API. All configurations get re-enabled
+ * internally in the following cases:
+ * - when forcing a link rate or lane count
+ * - when intel_dp_link_caps_update(reset=true) is called after
+ * a new sink is connected
+ * - when intel_dp_link_caps_update(reset=false) with changed
+ * link capabilities is called
+ * - when intel_dp_link_caps_reset() is called after a new sink
+ * is connected
+ */
+ struct intel_dp_link_caps_filter enabled_configs;
+
+ /*
+ * Allowed configurations are the supported configurations defined by
+ * config_table.rates and config_table.max_lane_count, constrained by
+ * config_table.enabled_configs and the forced_params and
+ * max_limits values below.
+ *
+ * See get_allowed_config_filter() for the filter of these
+ * configurations.
+ */
+
+ /*
* Forced parameters requested via debugfs. Remains set across sink
* disconnects.
*/
@@ -58,16 +178,78 @@ struct intel_dp_link_caps {
*/
struct intel_dp_link_config max_limits;
};
+static_assert(BITS_PER_TYPE(((struct intel_dp_link_caps_filter *)NULL)->config_mask) >=
+ ARRAY_SIZE(((struct intel_dp_link_caps *)NULL)->configs));
+
+static struct intel_dp_link_caps_order bw_desc_config_order(void)
+{
+ struct intel_dp_link_caps_order order = {
+ .key = INTEL_DP_LINK_CAPS_ORDER_KEY_BW,
+ .dir = INTEL_DP_LINK_CAPS_ORDER_DIR_DESC,
+ };
+
+ return order;
+}
+
+static enum intel_dp_link_caps_order_key
+connector_compute_order_key(bool is_mst)
+{
+ if (is_mst)
+ return INTEL_DP_LINK_CAPS_ORDER_KEY_BW;
+ else
+ return INTEL_DP_LINK_CAPS_ORDER_KEY_RATE_LANE;
+}
+
+static enum intel_dp_link_caps_order_key
+connector_fallback_order_key(bool is_mst)
+{
+ if (is_mst)
+ return INTEL_DP_LINK_CAPS_ORDER_KEY_BW;
+ else
+ return INTEL_DP_LINK_CAPS_ORDER_KEY_LANE_RATE;
+}
+
+static enum intel_dp_link_caps_order_direction
+connector_compute_order_dir(bool is_mst, bool use_max_params)
+{
+ if (is_mst || use_max_params)
+ return INTEL_DP_LINK_CAPS_ORDER_DIR_DESC;
+ else
+ return INTEL_DP_LINK_CAPS_ORDER_DIR_ASC;
+}
+
+struct intel_dp_link_caps_order
+intel_dp_link_caps_connector_compute_order(struct intel_connector *connector)
+{
+ struct intel_dp *intel_dp = intel_attached_dp(connector);
+ struct intel_dp_link_caps_order order = {
+ .key = connector_compute_order_key(connector->mst.dp),
+ .dir = connector_compute_order_dir(connector->mst.dp, intel_dp->use_max_params)
+ };
+
+ return order;
+}
+
+struct intel_dp_link_caps_order
+intel_dp_link_caps_connector_fallback_order(bool is_mst)
+{
+ struct intel_dp_link_caps_order order = {
+ .key = connector_fallback_order_key(is_mst),
+ .dir = INTEL_DP_LINK_CAPS_ORDER_DIR_DESC,
+ };
+
+ return order;
+}
/* Get length of common rates array potentially limited by max_rate. */
-int intel_dp_common_len_rate_limit(struct intel_dp_link_caps *link_caps,
- int max_rate)
+static int intel_dp_common_len_rate_limit(struct intel_dp_link_caps *link_caps,
+ int max_rate)
{
return intel_dp_rate_limit_len(link_caps->rates,
link_caps->num_rates, max_rate);
}
-int intel_dp_common_rate(struct intel_dp_link_caps *link_caps, int index)
+static int intel_dp_common_rate(struct intel_dp_link_caps *link_caps, int index)
{
struct intel_display *display = to_intel_display(link_caps->dp);
@@ -78,24 +260,12 @@ int intel_dp_common_rate(struct intel_dp_link_caps *link_caps, int index)
return link_caps->rates[index];
}
-int intel_dp_link_caps_common_rate_idx(struct intel_dp_link_caps *link_caps, int rate)
-{
- return intel_dp_rate_index(link_caps->rates,
- link_caps->num_rates,
- rate);
-}
-
/* Theoretical max between source and sink */
-int intel_dp_max_common_rate(struct intel_dp_link_caps *link_caps)
+static int intel_dp_max_common_rate(struct intel_dp_link_caps *link_caps)
{
return intel_dp_common_rate(link_caps, link_caps->num_rates - 1);
}
-int intel_dp_link_caps_num_common_rates(struct intel_dp_link_caps *link_caps)
-{
- return link_caps->num_rates;
-}
-
void intel_dp_link_caps_print_common_rates(struct intel_dp_link_caps *link_caps)
{
struct intel_display *display = to_intel_display(link_caps->dp);
@@ -108,7 +278,7 @@ void intel_dp_link_caps_print_common_rates(struct intel_dp_link_caps *link_caps)
drm_dbg_kms(display->drm, "common rates: %s\n", seq_buf_str(&s));
}
-int intel_dp_link_caps_max_common_lane_count(struct intel_dp_link_caps *link_caps)
+static int intel_dp_link_caps_max_common_lane_count(struct intel_dp_link_caps *link_caps)
{
return link_caps->max_lane_count;
}
@@ -154,20 +324,353 @@ static int intel_dp_link_config_lane_count(const struct intel_dp_link_config_ent
return 1 << lce->lane_count_exp;
}
-static void set_max_link_limits_no_update(struct intel_dp_link_caps *link_caps,
- const struct intel_dp_link_config *max_link_limits)
+static void
+to_intel_dp_link_config(struct intel_dp_link_caps *link_caps,
+ int config_idx, struct intel_dp_link_config *config)
+{
+ const struct intel_dp_link_config_entry *lce = &link_caps->configs[config_idx];
+
+ config->rate = intel_dp_link_config_rate(link_caps, lce);
+ config->lane_count = intel_dp_link_config_lane_count(lce);
+}
+
+static int
+iter_pos_to_idx(struct intel_dp_link_caps *link_caps,
+ struct intel_dp_link_caps_order config_order,
+ int iter_pos)
+{
+ int config_idx;
+
+ if (!in_range(iter_pos, 0, link_caps->num_configs))
+ return -1;
+
+ switch (config_order.dir) {
+ case INTEL_DP_LINK_CAPS_ORDER_DIR_ASC:
+ break;
+ case INTEL_DP_LINK_CAPS_ORDER_DIR_DESC:
+ iter_pos = link_caps->num_configs - 1 - iter_pos;
+
+ break;
+ default:
+ MISSING_CASE(config_order.dir);
+
+ return -1;
+ }
+
+ switch (config_order.key) {
+ case INTEL_DP_LINK_CAPS_ORDER_KEY_BW:
+ config_idx = iter_pos;
+
+ break;
+ case INTEL_DP_LINK_CAPS_ORDER_KEY_RATE_LANE:
+ config_idx = link_caps->rate_lane_map[iter_pos];
+
+ break;
+ case INTEL_DP_LINK_CAPS_ORDER_KEY_LANE_RATE:
+ config_idx = link_caps->lane_rate_map[iter_pos];
+
+ break;
+ default:
+ MISSING_CASE(config_order.key);
+
+ return -1;
+ }
+
+ return config_idx;
+}
+
+static bool iter_get_next_config(struct intel_dp_link_caps_iter *iter,
+ struct intel_dp_link_config *config)
+{
+ while (true) {
+ int config_idx;
+
+ iter->pos++;
+
+ config_idx = iter_pos_to_idx(iter->link_caps, iter->order, iter->pos);
+ if (config_idx < 0) {
+ iter->pos = -1;
+ *config = INTEL_DP_LINK_CONFIG_NULL;
+
+ break;
+ }
+
+ if (!(BIT(config_idx) & iter->filter.config_mask))
+ continue;
+
+ to_intel_dp_link_config(iter->link_caps, config_idx, config);
+
+ break;
+ }
+
+ return iter->pos >= 0;
+}
+
+static void iter_start(struct intel_dp_link_caps_iter *iter,
+ struct intel_dp_link_caps *link_caps,
+ struct intel_dp_link_caps_order order,
+ struct intel_dp_link_caps_filter filter)
+{
+ iter->link_caps = link_caps;
+ iter->pos = -1;
+ iter->order = order;
+ iter->filter = filter;
+
+ iter->get_next_config = iter_get_next_config;
+}
+
+static struct intel_dp_link_caps_filter
+calc_allowed_config_filter(struct intel_dp_link_caps *link_caps,
+ struct intel_dp_link_caps_filter enabled_configs,
+ const struct intel_dp_link_config *max_limits,
+ const struct intel_dp_link_config *forced_params)
+{
+ struct intel_dp_link_caps_filter allowed_configs = INTEL_DP_LINK_CAPS_FILTER_NONE;
+ struct intel_dp_link_caps_order order = bw_desc_config_order();
+ struct intel_dp_link_caps_iter iter;
+ struct intel_dp_link_config config;
+
+ iter_start(&iter, link_caps, order, enabled_configs);
+ for_each_dp_link_config(&iter, &config) {
+ if (forced_params->rate &&
+ forced_params->rate != config.rate)
+ continue;
+
+ if (forced_params->lane_count &&
+ forced_params->lane_count != config.lane_count)
+ continue;
+
+ if (config.rate > max_limits->rate)
+ continue;
+
+ if (config.lane_count > max_limits->lane_count)
+ continue;
+
+ allowed_configs.config_mask |= BIT(iter_pos_to_idx(link_caps, order, iter.pos));
+ }
+ intel_dp_link_caps_iter_end(&iter);
+
+ return allowed_configs;
+}
+
+/*
+ * get_allowed_config_filter - get filter for the currently allowed configs
+ * @link_caps: link capabilities state
+ *
+ * Return:
+ * Filter of link configurations allowed after applying the current
+ * maximum link limits, and further narrowing them by removing any disabled
+ * configuration and limiting to forced link parameters.
+ *
+ * See also:
+ * - intel_dp_link_caps_get_max_limits()
+ * - intel_dp_link_caps_get_forced_params()
+ */
+static struct intel_dp_link_caps_filter
+get_allowed_config_filter(struct intel_dp_link_caps *link_caps)
+{
+ struct intel_dp_link_config forced_params;
+
+ intel_dp_link_caps_get_forced_params(link_caps, &forced_params);
+
+ return calc_allowed_config_filter(link_caps, link_caps->enabled_configs,
+ &link_caps->max_limits, &forced_params);
+}
+
+void intel_dp_link_caps_iter_start(struct intel_dp_link_caps_iter *iter,
+ struct intel_dp_link_caps *link_caps,
+ struct intel_dp_link_caps_order order,
+ struct intel_dp_link_caps_filter filter)
+{
+ filter.config_mask &= get_allowed_config_filter(link_caps).config_mask;
+
+ iter_start(iter, link_caps, order, filter);
+}
+
+void intel_dp_link_caps_iter_end(struct intel_dp_link_caps_iter *iter)
+{
+ memset(iter, 0, sizeof(*iter));
+}
+
+/**
+ * intel_dp_link_caps_get_max_config - get the maximum config in a given order
+ * @link_caps: link capabilities state
+ * @order_key: ordering key used to rank candidate configurations
+ * @filter: filter for candidate configurations
+ * @max_config: returned maximum link configuration
+ *
+ * Find the last configuration among the currently allowed
+ * configurations filtered by @filter in the iteration order
+ * selected by @order_key, and store it in @max_config.
+ *
+ * See also:
+ * - &enum intel_dp_link_caps_order_key
+ *
+ * Returns:
+ * %true if a maximum config is returned
+ * %false otherwise.
+ */
+bool intel_dp_link_caps_get_max_config(struct intel_dp_link_caps *link_caps,
+ enum intel_dp_link_caps_order_key order_key,
+ struct intel_dp_link_caps_filter filter,
+ struct intel_dp_link_config *max_config)
+{
+ struct intel_dp_link_caps_order order = {
+ .key = order_key,
+ .dir = INTEL_DP_LINK_CAPS_ORDER_DIR_DESC
+ };
+ struct intel_dp_link_config iter_config;
+ struct intel_dp_link_caps_iter iter;
+ bool found = false;
+
+ intel_dp_link_caps_iter_start(&iter, link_caps, order, filter);
+ for_each_dp_link_config(&iter, &iter_config) {
+ found = true;
+ break;
+ }
+ intel_dp_link_caps_iter_end(&iter);
+
+ if (!found)
+ return false;
+
+ *max_config = iter_config;
+
+ return true;
+}
+
+/**
+ * intel_dp_link_caps_get_max_bw_config - get maximum BW link configuration
+ * @link_caps: link capabilities state
+ * @max_config: returned maximum link configuration
+ *
+ * Return the maximum BW link configuration among the currently
+ * allowed configurations.
+ */
+void intel_dp_link_caps_get_max_bw_config(struct intel_dp_link_caps *link_caps,
+ struct intel_dp_link_config *max_config)
+{
+ if (!intel_dp_link_caps_get_max_config(link_caps,
+ bw_desc_config_order().key, INTEL_DP_LINK_CAPS_FILTER_ALL,
+ max_config))
+ *max_config = INTEL_DP_LINK_CONFIG_NULL;
+}
+
+static int find_config_idx(struct intel_dp_link_caps *link_caps,
+ struct intel_dp_link_caps_filter filter,
+ const struct intel_dp_link_config *link_config)
+{
+ struct intel_dp_link_caps_order order = bw_desc_config_order();
+ struct intel_dp_link_config iter_config;
+ struct intel_dp_link_caps_iter iter;
+ int pos = -1;
+
+ intel_dp_link_caps_iter_start(&iter, link_caps, order, filter);
+ for_each_dp_link_config(&iter, &iter_config) {
+ if (iter_config.rate == link_config->rate &&
+ iter_config.lane_count == link_config->lane_count) {
+ pos = iter.pos;
+
+ break;
+ }
+ }
+ intel_dp_link_caps_iter_end(&iter);
+
+ if (pos < 0)
+ return pos;
+
+ return iter_pos_to_idx(link_caps, order, pos);
+}
+
+bool intel_dp_link_caps_filter_add(struct intel_dp_link_caps *link_caps,
+ struct intel_dp_link_caps_filter *filter,
+ const struct intel_dp_link_config *config)
+{
+ int idx;
+
+ idx = find_config_idx(link_caps, get_allowed_config_filter(link_caps), config);
+ if (idx < 0)
+ return false;
+
+ filter->config_mask |= BIT(idx);
+
+ return true;
+}
+
+static bool intel_dp_link_caps_filter_remove(struct intel_dp_link_caps *link_caps,
+ struct intel_dp_link_caps_filter *filter,
+ const struct intel_dp_link_config *config)
+{
+ int idx;
+
+ idx = find_config_idx(link_caps, get_allowed_config_filter(link_caps), config);
+ if (idx < 0)
+ return false;
+
+ filter->config_mask &= ~BIT(idx);
+
+ return true;
+}
+
+static void set_max_link_limits(struct intel_dp_link_caps *link_caps,
+ const struct intel_dp_link_config *max_link_limits)
{
link_caps->max_limits = *max_link_limits;
}
-static void reset_max_link_limits_no_update(struct intel_dp_link_caps *link_caps)
+static void reset_max_link_limits(struct intel_dp_link_caps *link_caps)
{
struct intel_dp_link_config max_link_limits = {
.rate = intel_dp_max_common_rate(link_caps),
.lane_count = intel_dp_link_caps_max_common_lane_count(link_caps),
};
- set_max_link_limits_no_update(link_caps, &max_link_limits);
+ set_max_link_limits(link_caps, &max_link_limits);
+}
+
+static void reset_max_link_limits_reenable_all(struct intel_dp_link_caps *link_caps)
+{
+ link_caps->enabled_configs = INTEL_DP_LINK_CAPS_FILTER_ALL;
+ reset_max_link_limits(link_caps);
+}
+
+/**
+ * intel_dp_link_caps_disable_config - disable a configuration
+ * @link_caps: link capabilities state
+ * @config: configuration to disable
+ *
+ * Disable the configuration identified by @config. This removes the
+ * configuration from the set of allowed configurations. The disabling
+ * shouldn't leave the remaining configuration set empty.
+ *
+ * The configuration remains disallowed until intel_dp_link_caps() with
+ * reset=%true or changed sink capabilities is called, or
+ * intel_dp_link_caps_reset() is called. Each of these happens after a
+ * new sink is connected or the currently connected sink changes its
+ * capabilities.
+ *
+ * Return:
+ * - %true if @config was valid and the derived state was updated.
+ * - %false if @config was invalid or the remaining configuration set
+ * would remain empty.
+ */
+bool intel_dp_link_caps_disable_config(struct intel_dp_link_caps *link_caps,
+ const struct intel_dp_link_config *config)
+{
+ struct intel_dp_link_caps_filter enabled_configs = link_caps->enabled_configs;
+ struct intel_dp_link_config forced_params;
+
+ if (!intel_dp_link_caps_filter_remove(link_caps, &enabled_configs, config))
+ return false;
+
+ intel_dp_link_caps_get_forced_params(link_caps, &forced_params);
+
+ if (!calc_allowed_config_filter(link_caps, enabled_configs,
+ &link_caps->max_limits, &forced_params).config_mask)
+ return false;
+
+ link_caps->enabled_configs = enabled_configs;
+
+ return true;
}
/**
@@ -197,6 +700,25 @@ void intel_dp_link_caps_get_max_limits(struct intel_dp_link_caps *link_caps,
*max_link_limits = link_caps->max_limits;
}
+static bool max_link_limits_valid(struct intel_dp_link_caps *link_caps,
+ const struct intel_dp_link_config *max_link_limits)
+{
+ struct intel_dp_link_caps_filter allowed_configs;
+ struct intel_dp_link_config forced_params;
+
+ if (max_link_limits->lane_count > INTEL_DP_MAX_LANE_COUNT ||
+ !is_power_of_2(max_link_limits->lane_count))
+ return false;
+
+ /* TODO: Validate max_link_limits->rate against the source supported rates. */
+
+ intel_dp_link_caps_get_forced_params(link_caps, &forced_params);
+ allowed_configs = calc_allowed_config_filter(link_caps, link_caps->enabled_configs,
+ max_link_limits, &forced_params);
+
+ return allowed_configs.config_mask != 0;
+}
+
/**
* intel_dp_link_caps_set_max_limits - set the current maximum link limits
* @link_caps: link capabilities state
@@ -205,6 +727,10 @@ void intel_dp_link_caps_get_max_limits(struct intel_dp_link_caps *link_caps,
* Set the current maximum rate and lane count limits to @max_link_limits,
* constraining the set of allowed configurations.
*
+ * The new limits must leave at least one configuration allowed: the limits
+ * must not be below the currently active forced parameters or below all the
+ * configurations that remain after disabled configurations are excluded.
+ *
* Unlike intel_dp_link_caps_get_max_limits(), the caller must serialize
* this call against concurrent queries and updates to @link_caps, in line
* with the rest of the API.
@@ -217,9 +743,11 @@ void intel_dp_link_caps_get_max_limits(struct intel_dp_link_caps *link_caps,
bool intel_dp_link_caps_set_max_limits(struct intel_dp_link_caps *link_caps,
const struct intel_dp_link_config *max_link_limits)
{
- set_max_link_limits_no_update(link_caps, max_link_limits);
+ if (!max_link_limits_valid(link_caps, max_link_limits))
+ return false;
+
+ set_max_link_limits(link_caps, max_link_limits);
- /* TODO: validate max_link_limits */
return true;
}
@@ -232,7 +760,7 @@ bool intel_dp_link_caps_set_max_limits(struct intel_dp_link_caps *link_caps,
*/
void intel_dp_link_caps_reset_max_limits(struct intel_dp_link_caps *link_caps)
{
- reset_max_link_limits_no_update(link_caps);
+ reset_max_link_limits(link_caps);
}
static int intel_dp_link_config_bw(struct intel_dp_link_caps *link_caps,
@@ -259,14 +787,70 @@ static int link_config_cmp_by_bw(const void *a, const void *b, const void *p)
intel_dp_link_config_rate(link_caps, lce_b);
}
-/* Return %true if the supported link parameters have changed. */
+static int link_config_cmp_by_rate_lane(const void *a, const void *b, const void *p)
+{
+ const struct intel_dp_link_caps *link_caps = p;
+ u8 *lce_a_idx = (u8 *)a;
+ u8 *lce_b_idx = (u8 *)b;
+ const struct intel_dp_link_config_entry *lce_a = &link_caps->configs[*lce_a_idx];
+ const struct intel_dp_link_config_entry *lce_b = &link_caps->configs[*lce_b_idx];
+
+ if (lce_a->link_rate_idx != lce_b->link_rate_idx)
+ return lce_a->link_rate_idx - lce_b->link_rate_idx;
+
+ return lce_a->lane_count_exp - lce_b->lane_count_exp;
+}
+
+static int link_config_cmp_by_lane_rate(const void *a, const void *b, const void *p)
+{
+ const struct intel_dp_link_caps *link_caps = p;
+ u8 *lce_a_idx = (u8 *)a;
+ u8 *lce_b_idx = (u8 *)b;
+ const struct intel_dp_link_config_entry *lce_a = &link_caps->configs[*lce_a_idx];
+ const struct intel_dp_link_config_entry *lce_b = &link_caps->configs[*lce_b_idx];
+
+ if (lce_a->lane_count_exp != lce_b->lane_count_exp)
+ return lce_a->lane_count_exp - lce_b->lane_count_exp;
+
+ return lce_a->link_rate_idx - lce_b->link_rate_idx;
+}
+
+/**
+ * intel_dp_link_caps_update - rebuild the supported link configuration state
+ * @link_caps: link capabilities state
+ * @rates: supported common link rates
+ * @num_rates: number of entries in @rates
+ * @max_lane_count: supported maximum lane count
+ * @reset: reset limits and disabled configs
+ *
+ * Rebuild the supported link configuration state from @rates and
+ * @max_lane_count.
+ *
+ * If @reset is %true, reset the maximum link limits to the maximum
+ * supported rate and lane count, and re-enable all configurations.
+ *
+ * This function is called regularly, at least after a sink is connected,
+ * but it may also be called later whenever the sink capabilities may have
+ * changed, for example in response to HPD IRQ / RX_CAP_CHANGED signaling.
+ *
+ * In the Intel driver this function is currently called whenever the
+ * connector detect handler runs, after reading the sink capabilities. This
+ * may change if those capabilities are cached until the sink is
+ * disconnected, or until RX_CAP_CHANGED is signaled. In any case, this
+ * function should be called whenever the sink capabilities were read out
+ * and may have changed.
+ *
+ * Returns:
+ * - %true if the link capabilities have changed, %false otherwise.
+ */
bool intel_dp_link_caps_update(struct intel_dp_link_caps *link_caps,
- const int *rates, int num_rates, int max_lane_count)
+ const int *rates, int num_rates, int max_lane_count,
+ bool reset)
{
struct intel_dp *intel_dp = link_caps->dp;
struct intel_display *display = to_intel_display(intel_dp);
struct intel_dp_link_config_entry *lce;
- bool link_params_changed = false;
+ bool link_params_changed = reset;
int num_common_lane_configs;
int i;
int j;
@@ -313,41 +897,25 @@ bool intel_dp_link_caps_update(struct intel_dp_link_caps *link_caps,
link_config_cmp_by_bw, NULL,
intel_dp);
- return link_params_changed;
-}
-
-void intel_dp_link_config_get(struct intel_dp_link_caps *link_caps,
- int idx, int *link_rate, int *lane_count)
-{
- struct intel_display *display = to_intel_display(link_caps->dp);
- const struct intel_dp_link_config_entry *lce;
-
- if (drm_WARN_ON(display->drm, idx < 0 || idx >= link_caps->num_configs))
- idx = 0;
-
- lce = &link_caps->configs[idx];
-
- *link_rate = intel_dp_link_config_rate(link_caps, lce);
- *lane_count = intel_dp_link_config_lane_count(lce);
-}
+ for (i = 0; i < link_caps->num_configs; i++) {
+ link_caps->rate_lane_map[i] = i;
+ link_caps->lane_rate_map[i] = i;
+ }
-int intel_dp_link_config_index(struct intel_dp_link_caps *link_caps,
- int link_rate, int lane_count)
-{
- int link_rate_idx = intel_dp_rate_index(link_caps->rates, link_caps->num_rates,
- link_rate);
- int lane_count_exp = ilog2(lane_count);
- int i;
+ sort_r(link_caps->rate_lane_map, link_caps->num_configs,
+ sizeof(link_caps->rate_lane_map[0]),
+ link_config_cmp_by_rate_lane, NULL,
+ link_caps);
- for (i = 0; i < link_caps->num_configs; i++) {
- const struct intel_dp_link_config_entry *lce = &link_caps->configs[i];
+ sort_r(link_caps->lane_rate_map, link_caps->num_configs,
+ sizeof(link_caps->lane_rate_map[0]),
+ link_config_cmp_by_lane_rate, NULL,
+ link_caps);
- if (lce->lane_count_exp == lane_count_exp &&
- lce->link_rate_idx == link_rate_idx)
- return i;
- }
+ if (link_params_changed)
+ reset_max_link_limits_reenable_all(link_caps);
- return -1;
+ return link_params_changed;
}
/**
@@ -364,8 +932,7 @@ int intel_dp_link_config_index(struct intel_dp_link_caps *link_caps,
*/
void intel_dp_link_caps_reset(struct intel_dp_link_caps *link_caps)
{
- /* TODO: Update the maximum link information. */
- reset_max_link_limits_no_update(link_caps);
+ reset_max_link_limits_reenable_all(link_caps);
}
static int i915_dp_force_link_rate_show(struct seq_file *m, void *data)
@@ -628,6 +1195,43 @@ static int i915_dp_max_lane_count_show(void *data, u64 *val)
}
DEFINE_DEBUGFS_ATTRIBUTE(i915_dp_max_lane_count_fops, i915_dp_max_lane_count_show, NULL, "%llu\n");
+static int intel_dp_allowed_link_configs_show(struct seq_file *m, void *data)
+{
+ struct intel_connector *connector = to_intel_connector(m->private);
+ struct intel_display *display = to_intel_display(connector);
+ struct intel_dp *intel_dp = intel_attached_dp(connector);
+ struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
+ struct intel_dp_link_config link_config;
+ struct intel_dp_link_caps_iter iter;
+ int err;
+ int i;
+
+ err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex);
+ if (err)
+ return err;
+
+ intel_dp_flush_connector_commits(connector);
+
+ i = 0;
+ intel_dp_link_caps_iter_start(&iter,
+ link_caps,
+ intel_dp_link_caps_connector_compute_order(connector),
+ INTEL_DP_LINK_CAPS_FILTER_ALL);
+ for_each_dp_link_config(&iter, &link_config) {
+ seq_printf(m, "%s%dx%d",
+ i ? " " : "",
+ link_config.lane_count, link_config.rate);
+ i++;
+ }
+ intel_dp_link_caps_iter_end(&iter);
+
+ drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
+
+ seq_putc(m, '\n');
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(intel_dp_allowed_link_configs);
/**
* intel_dp_link_caps_debugfs_add - add link caps debugfs files for a connector
@@ -654,6 +1258,9 @@ void intel_dp_link_caps_debugfs_add(struct intel_connector *connector)
debugfs_create_file("i915_dp_max_lane_count", 0444, root,
connector, &i915_dp_max_lane_count_fops);
+
+ debugfs_create_file("intel_dp_allowed_link_configs", 0444, root,
+ connector, &intel_dp_allowed_link_configs_fops);
}
struct intel_dp_link_caps *intel_dp_link_caps_init(struct intel_dp *intel_dp)
@@ -665,6 +1272,7 @@ struct intel_dp_link_caps *intel_dp_link_caps_init(struct intel_dp *intel_dp)
return NULL;
link_caps->dp = intel_dp;
+ link_caps->enabled_configs = INTEL_DP_LINK_CAPS_FILTER_ALL;
return link_caps;
}
@@ -673,3 +1281,32 @@ void intel_dp_link_caps_cleanup(struct intel_dp_link_caps *link_caps)
{
kfree(link_caps);
}
+
+#if IS_ENABLED(CONFIG_KUNIT)
+
+#define __INIT_MEMBER(__name, __fn) \
+ .__name = __fn,
+
+#define INTEL_DP_LINK_CAPS_TEST_OPS_INIT \
+ INTEL_DP_LINK_CAPS_TEST_OPS_MEMBERS(__INIT_MEMBER)
+
+#ifdef I915
+
+const struct intel_dp_link_caps_test_ops i915_display_dp_link_caps_test_ops = {
+ INTEL_DP_LINK_CAPS_TEST_OPS_INIT
+};
+EXPORT_SYMBOL(i915_display_dp_link_caps_test_ops);
+
+#else
+
+const struct intel_dp_link_caps_test_ops intel_display_dp_link_caps_test_ops = {
+ INTEL_DP_LINK_CAPS_TEST_OPS_INIT
+};
+EXPORT_SYMBOL(intel_display_dp_link_caps_test_ops);
+
+#endif /* I915 */
+
+#undef INTEL_DP_LINK_CAPS_TEST_OPS_INIT
+#undef __INIT_MEMBER
+
+#endif /* CONFIG_KUNIT */
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index af9028e7cb98..a0a88efb9546 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -4,6 +4,7 @@
#ifndef __INTEL_DP_LINK_CAPS_H__
#define __INTEL_DP_LINK_CAPS_H__
+#include <linux/bitops.h>
#include <linux/types.h>
struct intel_connector;
@@ -11,23 +12,132 @@ struct intel_dp;
struct intel_dp_link_caps;
struct intel_dp_link_config;
-int intel_dp_common_len_rate_limit(struct intel_dp_link_caps *link_caps,
- int max_rate);
-int intel_dp_common_rate(struct intel_dp_link_caps *link_caps, int index);
-int intel_dp_link_caps_common_rate_idx(struct intel_dp_link_caps *link_caps, int rate);
-int intel_dp_max_common_rate(struct intel_dp_link_caps *link_caps);
-int intel_dp_link_caps_num_common_rates(struct intel_dp_link_caps *link_caps);
-int intel_dp_link_caps_max_common_lane_count(struct intel_dp_link_caps *link_caps);
+/**
+ * enum intel_dp_link_caps_order_key - key used to order configurations
+ * @INTEL_DP_LINK_CAPS_ORDER_KEY_BW:
+ * Order configurations by bandwidth, then by link rate.
+ * @INTEL_DP_LINK_CAPS_ORDER_KEY_RATE_LANE:
+ * Order configurations by link rate, then by lane count.
+ * @INTEL_DP_LINK_CAPS_ORDER_KEY_LANE_RATE:
+ * Order configurations by lane count, then by link rate.
+ * @INTEL_DP_LINK_CAPS_ORDER_KEY_NUM:
+ * Number of ordering keys.
+ *
+ * Selects how a caller wants the configuration table to be ordered,
+ * together with an &enum intel_dp_link_caps_order_direction, for
+ * iteration queries.
+ *
+ * See also:
+ * - &struct intel_dp_link_caps_order
+ * - intel_dp_link_caps_get_max_config()
+ */
+enum intel_dp_link_caps_order_key {
+ INTEL_DP_LINK_CAPS_ORDER_KEY_BW,
+ INTEL_DP_LINK_CAPS_ORDER_KEY_RATE_LANE,
+ INTEL_DP_LINK_CAPS_ORDER_KEY_LANE_RATE,
+
+ INTEL_DP_LINK_CAPS_ORDER_KEY_NUM
+};
+
+/**
+ * enum intel_dp_link_caps_order_direction - iteration direction
+ * @INTEL_DP_LINK_CAPS_ORDER_DIR_ASC:
+ * Iterate in ascending order according to the selected ordering key.
+ * @INTEL_DP_LINK_CAPS_ORDER_DIR_DESC:
+ * Iterate in descending order according to the selected ordering key.
+ * @INTEL_DP_LINK_CAPS_ORDER_DIR_NUM:
+ * Number of ordering directions.
+ *
+ * Selects the direction associated with an
+ * &enum intel_dp_link_caps_order_key for iteration queries.
+ *
+ * See also:
+ * - &struct intel_dp_link_caps_order
+ */
+enum intel_dp_link_caps_order_direction {
+ INTEL_DP_LINK_CAPS_ORDER_DIR_ASC,
+ INTEL_DP_LINK_CAPS_ORDER_DIR_DESC,
+
+ INTEL_DP_LINK_CAPS_ORDER_DIR_NUM
+};
+
+/**
+ * struct intel_dp_link_caps_order - configuration ordering
+ * @key:
+ * Key used to order configurations.
+ * @dir:
+ * Direction of the selected ordering.
+ *
+ * Describes an iteration order for link configurations.
+ *
+ * See also:
+ * - for_each_dp_link_config()
+ */
+struct intel_dp_link_caps_order {
+ enum intel_dp_link_caps_order_key key;
+ enum intel_dp_link_caps_order_direction dir;
+};
+
+struct intel_dp_link_caps_filter {
+ u32 config_mask;
+};
+
+#define INTEL_DP_LINK_CAPS_FILTER_NONE \
+ ((struct intel_dp_link_caps_filter){ .config_mask = 0 })
+#define INTEL_DP_LINK_CAPS_FILTER_ALL \
+ ((struct intel_dp_link_caps_filter){ .config_mask = (u32)-1 })
+
+struct intel_dp_link_caps_iter {
+ struct intel_dp_link_caps *link_caps;
+ int pos;
+ struct intel_dp_link_caps_order order;
+ struct intel_dp_link_caps_filter filter;
+
+ bool (*get_next_config)(struct intel_dp_link_caps_iter *iter,
+ struct intel_dp_link_config *config);
+};
+
+/**
+ * for_each_dp_link_config - iterate allowed link configurations
+ * @__iter:
+ * &struct intel_dp_link_caps_iter being iterated
+ * @__config:
+ * pointer to &struct intel_dp_link_config filled for each match
+ */
+#define for_each_dp_link_config(__iter, __config) \
+ while ((__iter)->get_next_config((__iter), (__config)))
+
+void intel_dp_link_caps_iter_start(struct intel_dp_link_caps_iter *iter,
+ struct intel_dp_link_caps *link_caps,
+ struct intel_dp_link_caps_order order,
+ struct intel_dp_link_caps_filter filter);
+
+void intel_dp_link_caps_iter_end(struct intel_dp_link_caps_iter *iter);
+
+struct intel_dp_link_caps_order
+intel_dp_link_caps_connector_compute_order(struct intel_connector *connector);
+struct intel_dp_link_caps_order
+intel_dp_link_caps_connector_fallback_order(bool is_mst);
void intel_dp_link_caps_print_common_rates(struct intel_dp_link_caps *link_caps);
void intel_dp_link_caps_get_forced_params(struct intel_dp_link_caps *link_caps,
struct intel_dp_link_config *forced_params);
-int intel_dp_link_config_index(struct intel_dp_link_caps *link_caps,
- int link_rate, int lane_count);
-void intel_dp_link_config_get(struct intel_dp_link_caps *link_caps,
- int idx, int *link_rate, int *lane_count);
+bool intel_dp_link_caps_filter_add(struct intel_dp_link_caps *link_caps,
+ struct intel_dp_link_caps_filter *filter,
+ const struct intel_dp_link_config *config);
+
+bool intel_dp_link_caps_get_max_config(struct intel_dp_link_caps *link_caps,
+ enum intel_dp_link_caps_order_key order_key,
+ struct intel_dp_link_caps_filter filter,
+ struct intel_dp_link_config *max_config);
+
+void intel_dp_link_caps_get_max_bw_config(struct intel_dp_link_caps *link_caps,
+ struct intel_dp_link_config *max_config);
+
+bool intel_dp_link_caps_disable_config(struct intel_dp_link_caps *link_caps,
+ const struct intel_dp_link_config *config);
void intel_dp_link_caps_get_max_limits(struct intel_dp_link_caps *link_caps,
struct intel_dp_link_config *max_link_limits);
@@ -36,7 +146,8 @@ bool intel_dp_link_caps_set_max_limits(struct intel_dp_link_caps *link_caps,
void intel_dp_link_caps_reset_max_limits(struct intel_dp_link_caps *link_caps);
bool intel_dp_link_caps_update(struct intel_dp_link_caps *link_caps,
- const int *rates, int num_rates, int max_lane_count);
+ const int *rates, int num_rates, int max_lane_count,
+ bool reset);
void intel_dp_link_caps_reset(struct intel_dp_link_caps *link_caps);
void intel_dp_link_caps_debugfs_add(struct intel_connector *connector);
@@ -44,4 +155,41 @@ void intel_dp_link_caps_debugfs_add(struct intel_connector *connector);
struct intel_dp_link_caps *intel_dp_link_caps_init(struct intel_dp *intel_dp);
void intel_dp_link_caps_cleanup(struct intel_dp_link_caps *link_caps);
+#if IS_ENABLED(CONFIG_KUNIT)
+
+#define INTEL_DP_LINK_CAPS_TEST_OPS_MEMBERS(__X) \
+ __X(connector_compute_order, intel_dp_link_caps_connector_compute_order) \
+ __X(connector_fallback_order, intel_dp_link_caps_connector_fallback_order) \
+ __X(iter_start, intel_dp_link_caps_iter_start) \
+ __X(iter_end, intel_dp_link_caps_iter_end) \
+ __X(set_max_limits, intel_dp_link_caps_set_max_limits) \
+ __X(get_max_limits, intel_dp_link_caps_get_max_limits) \
+ __X(get_max_bw_config, intel_dp_link_caps_get_max_bw_config) \
+ __X(reset_max_limits, intel_dp_link_caps_reset_max_limits) \
+ __X(disable_config, intel_dp_link_caps_disable_config) \
+ __X(update, intel_dp_link_caps_update) \
+ __X(init, intel_dp_link_caps_init) \
+ __X(cleanup, intel_dp_link_caps_cleanup)
+
+#define __DECLARE_MEMBER(__name, __fn) \
+ typeof(__fn) *__name;
+
+#define INTEL_DP_LINK_CAPS_TEST_OPS_DECLARE \
+ INTEL_DP_LINK_CAPS_TEST_OPS_MEMBERS(__DECLARE_MEMBER)
+
+struct intel_dp_link_caps_test_ops {
+ INTEL_DP_LINK_CAPS_TEST_OPS_DECLARE
+};
+
+#undef INTEL_DP_LINK_CAPS_TEST_OPS_DECLARE
+#undef __DECLARE_MEMBER
+
+#ifdef I915
+extern const struct intel_dp_link_caps_test_ops i915_display_dp_link_caps_test_ops;
+#else
+extern const struct intel_dp_link_caps_test_ops intel_display_dp_link_caps_test_ops;
+#endif /* I915 */
+
+#endif /* CONFIG_KUNIT */
+
#endif /* __INTEL_DP_LINK_CAPS_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index b521dd11b62a..fa55664c9d98 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -21,6 +21,8 @@
* IN THE SOFTWARE.
*/
+#include <kunit/visibility.h>
+
#include <linux/debugfs.h>
#include <linux/iopoll.h>
@@ -1846,124 +1848,62 @@ static bool intel_dp_can_link_train_fallback_for_edp(struct intel_dp *intel_dp,
return true;
}
-static bool reduce_link_params_in_bw_order(struct intel_dp *intel_dp,
- const struct intel_crtc_state *crtc_state,
- int *new_link_rate, int *new_lane_count)
+static bool reduce_link_params(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state,
+ int *new_link_rate, int *new_lane_count)
{
struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
- struct intel_dp_link_config forced_params;
- int link_rate;
- int lane_count;
- int i;
-
- intel_dp_link_caps_get_forced_params(link_caps, &forced_params);
+ bool is_mst = intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST);
+ struct intel_dp_link_caps_order order =
+ intel_dp_link_caps_connector_fallback_order(is_mst);
+ struct intel_dp_link_config old_config = {
+ .rate = crtc_state->port_clock,
+ .lane_count = crtc_state->lane_count,
+ };
+ struct intel_dp_link_caps_iter iter;
+ struct intel_dp_link_config config;
+ bool old_found = false;
+ bool new_found = false;
+
+ intel_dp_link_caps_iter_start(&iter, link_caps, order, INTEL_DP_LINK_CAPS_FILTER_ALL);
+ for_each_dp_link_config(&iter, &config) {
+ if (!old_found) {
+ if (config.rate == old_config.rate &&
+ config.lane_count == old_config.lane_count)
+ old_found = true;
- i = intel_dp_link_config_index(intel_dp->link.caps,
- crtc_state->port_clock, crtc_state->lane_count);
- for (i--; i >= 0; i--) {
- intel_dp_link_config_get(intel_dp->link.caps, i, &link_rate, &lane_count);
+ continue;
+ }
- if ((forced_params.rate &&
- forced_params.rate != link_rate) ||
- (forced_params.lane_count &&
- forced_params.lane_count != lane_count))
+ if (!is_mst &&
+ drm_dp_is_uhbr_rate(config.rate) !=
+ drm_dp_is_uhbr_rate(old_config.rate))
continue;
+ *new_link_rate = config.rate;
+ *new_lane_count = config.lane_count;
+ new_found = true;
+
break;
}
+ intel_dp_link_caps_iter_end(&iter);
- if (i < 0)
- return false;
-
- *new_link_rate = link_rate;
- *new_lane_count = lane_count;
-
- return true;
+ return new_found;
}
-static int reduce_link_rate(struct intel_dp *intel_dp, int current_rate)
-{
- struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
- struct intel_dp_link_config forced_params;
- int rate_index;
- int new_rate;
-
- intel_dp_link_caps_get_forced_params(link_caps, &forced_params);
- if (forced_params.rate)
- return -1;
-
- rate_index = intel_dp_link_caps_common_rate_idx(link_caps,
- current_rate);
-
- if (rate_index <= 0)
- return -1;
-
- new_rate = intel_dp_common_rate(link_caps, rate_index - 1);
-
- /* TODO: Make switching from UHBR to non-UHBR rates work. */
- if (drm_dp_is_uhbr_rate(current_rate) != drm_dp_is_uhbr_rate(new_rate))
- return -1;
-
- return new_rate;
-}
-
-static int reduce_lane_count(struct intel_dp *intel_dp, int current_lane_count)
-{
- struct intel_dp_link_config forced_params;
-
- intel_dp_link_caps_get_forced_params(intel_dp->link.caps, &forced_params);
- if (forced_params.lane_count)
- return -1;
-
- if (current_lane_count == 1)
- return -1;
-
- return current_lane_count >> 1;
-}
-
-static bool reduce_link_params_in_rate_lane_order(struct intel_dp *intel_dp,
- const struct intel_crtc_state *crtc_state,
- int *new_link_rate, int *new_lane_count)
-{
- struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
- int link_rate;
- int lane_count;
-
- lane_count = crtc_state->lane_count;
- link_rate = reduce_link_rate(intel_dp, crtc_state->port_clock);
- if (link_rate < 0) {
- lane_count = reduce_lane_count(intel_dp, crtc_state->lane_count);
- link_rate = intel_dp_max_common_rate(link_caps);
- }
-
- if (lane_count < 0)
- return false;
-
- *new_link_rate = link_rate;
- *new_lane_count = lane_count;
-
- return true;
-}
-
-static bool reduce_link_params(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state,
- int *new_link_rate, int *new_lane_count)
-{
- /* TODO: Use the same fallback logic on SST as on MST. */
- if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST))
- return reduce_link_params_in_bw_order(intel_dp, crtc_state,
- new_link_rate, new_lane_count);
- else
- return reduce_link_params_in_rate_lane_order(intel_dp, crtc_state,
- new_link_rate, new_lane_count);
-}
-
-static int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp,
- const struct intel_crtc_state *crtc_state)
+VISIBLE_IF_KUNIT
+int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state)
{
+ struct intel_display *display = to_intel_display(intel_dp);
struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
struct intel_dp_link_config max_link_limits;
+ struct intel_dp_link_config current_config = {
+ .rate = crtc_state->port_clock,
+ .lane_count = crtc_state->lane_count,
+ };
int new_link_rate;
int new_lane_count;
+ int err = -1;
if (intel_dp_is_edp(intel_dp) && !intel_dp->use_max_params) {
lt_dbg(intel_dp, DP_PHY_DPRX,
@@ -1972,16 +1912,49 @@ static int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp,
return 0;
}
+ /*
+ * Temporarily reset the max link limit before selecting the fallback
+ * config.
+ *
+ * After fallback, the current logic narrows the allowed configurations
+ * to the selected config's rate and lane count. That can make a later
+ * fallback candidate fall outside the current max_limit, so reset it
+ * before searching.
+ *
+ * TODO: Constrain the allowed configurations by only disabling individual
+ * configurations and remove setting maximum link parameters.
+ */
+ intel_dp_link_caps_get_max_limits(link_caps, &max_link_limits);
+ intel_dp_link_caps_reset_max_limits(link_caps);
+
+ /*
+ * TODO: Make fallback depend only on disabling the current config,
+ * once max_limit no longer constrains the allowed config set. Then
+ * disabling the current config will define the allowed configs for
+ * the subsequent modeset, so there will be no need to select a
+ * reduced config separately here.
+ */
if (!reduce_link_params(intel_dp, crtc_state, &new_link_rate, &new_lane_count))
- return -1;
+ goto out_restore_max_limits;
if (intel_dp_is_edp(intel_dp) &&
!intel_dp_can_link_train_fallback_for_edp(intel_dp, new_link_rate, new_lane_count)) {
lt_dbg(intel_dp, DP_PHY_DPRX,
"Retrying Link training for eDP with same parameters\n");
- return 0;
+
+ err = 0;
+
+ goto out_restore_max_limits;
}
+ /*
+ * Shouldn't fail: the current config was enabled, and reducing the
+ * link parameters should still leave the fallback config allowed.
+ */
+ if (drm_WARN_ON(display->drm,
+ !intel_dp_link_caps_disable_config(link_caps, &current_config)))
+ return -1;
+
lt_dbg(intel_dp, DP_PHY_DPRX,
"Reducing link parameters from %dx%d to %dx%d\n",
crtc_state->lane_count, crtc_state->port_clock,
@@ -1990,10 +1963,19 @@ static int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp,
max_link_limits.rate = new_link_rate;
max_link_limits.lane_count = new_lane_count;
- /* TODO: handle an update failure */
- intel_dp_link_caps_set_max_limits(link_caps, &max_link_limits);
+ err = 0;
- return 0;
+out_restore_max_limits:
+ /*
+ * Shouldn't fail: setting max_limits can only fail if they drop below
+ * the optionally forced rate/lane-count parameters, but the reduced
+ * config was chosen to satisfy those constraints.
+ */
+ if (drm_WARN_ON(display->drm,
+ !intel_dp_link_caps_set_max_limits(link_caps, &max_link_limits)))
+ err = -1;
+
+ return err;
}
static bool intel_dp_schedule_fallback_link_training(struct intel_atomic_state *state,
@@ -2834,3 +2816,32 @@ void intel_dp_link_training_cleanup(struct intel_dp_link_training *link_training
{
kfree(link_training);
}
+
+#if IS_ENABLED(CONFIG_KUNIT)
+
+#define __INIT_MEMBER(__name, __fn) \
+ .__name = __fn,
+
+#define INTEL_DP_LINK_TRAINING_TEST_OPS_INIT \
+ INTEL_DP_LINK_TRAINING_TEST_OPS_MEMBERS(__INIT_MEMBER)
+
+#ifdef I915
+
+const struct intel_dp_link_training_test_ops i915_display_dp_link_training_test_ops = {
+ INTEL_DP_LINK_TRAINING_TEST_OPS_INIT
+};
+EXPORT_SYMBOL(i915_display_dp_link_training_test_ops);
+
+#else
+
+const struct intel_dp_link_training_test_ops intel_display_dp_link_training_test_ops = {
+ INTEL_DP_LINK_TRAINING_TEST_OPS_INIT
+};
+EXPORT_SYMBOL(intel_display_dp_link_training_test_ops);
+
+#endif /* I915 */
+
+#undef INTEL_DP_LINK_TRAINING_TEST_OPS_INIT
+#undef __INIT_MEMBER
+
+#endif /* CONFIG_KUNIT */
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.h b/drivers/gpu/drm/i915/display/intel_dp_link_training.h
index ef16fcabd6da..581f2361fdfd 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.h
@@ -8,6 +8,8 @@
#include <drm/display/drm_dp_helper.h>
+#include "intel_dp_link_caps.h"
+
struct intel_atomic_state;
struct intel_connector;
struct intel_crtc_state;
@@ -71,4 +73,33 @@ void intel_dp_link_training_reset(struct intel_dp_link_training *link_training);
struct intel_dp_link_training *intel_dp_link_training_init(struct intel_dp *intel_dp);
void intel_dp_link_training_cleanup(struct intel_dp_link_training *link_training);
+#if IS_ENABLED(CONFIG_KUNIT)
+
+int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *crtc_state);
+
+#define INTEL_DP_LINK_TRAINING_TEST_OPS_MEMBERS(__X) \
+ __X(get_fallback_values, intel_dp_get_link_train_fallback_values)
+
+#define __DECLARE_MEMBER(__name, __fn) \
+ typeof(__fn) *__name;
+
+#define INTEL_DP_LINK_TRAINING_TEST_OPS_DECLARE \
+ INTEL_DP_LINK_TRAINING_TEST_OPS_MEMBERS(__DECLARE_MEMBER)
+
+struct intel_dp_link_training_test_ops {
+ INTEL_DP_LINK_TRAINING_TEST_OPS_DECLARE
+};
+
+#undef INTEL_DP_LINK_TRAINING_TEST_OPS_DECLARE
+#undef __DECLARE_MEMBER
+
+#ifdef I915
+extern const struct intel_dp_link_training_test_ops i915_display_dp_link_training_test_ops;
+#else
+extern const struct intel_dp_link_training_test_ops intel_display_dp_link_training_test_ops;
+#endif /* I915 */
+
+#endif /* CONFIG_KUNIT */
+
#endif /* __INTEL_DP_LINK_TRAINING_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c
index ecc90e8faee1..df6e54508e5d 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
@@ -47,6 +47,7 @@
#include "intel_display_wa.h"
#include "intel_dp.h"
#include "intel_dp_hdcp.h"
+#include "intel_dp_link_caps.h"
#include "intel_dp_link_training.h"
#include "intel_dp_mst.h"
#include "intel_dp_test.h"
@@ -444,8 +445,20 @@ static int mst_stream_compute_link_config(struct intel_dp *intel_dp,
struct drm_connector_state *conn_state,
const struct link_config_limits *limits)
{
- crtc_state->lane_count = limits->max_lane_count;
- crtc_state->port_clock = limits->max_rate;
+ struct intel_connector *connector = to_intel_connector(conn_state->connector);
+ struct intel_dp_link_config max_link_config;
+
+ /*
+ * FIXME: Use a proper iteration over the link configurations, instead
+ * of using only the max BW config. For instance UHBR rate configs may
+ * have additional limitations over non-UHBR ones, due to the DSC DPT
+ * bpp maximum limit.
+ */
+ if (!intel_dp_get_connector_max_link_config(connector, limits, &max_link_config))
+ return -EINVAL;
+
+ crtc_state->port_clock = max_link_config.rate;
+ crtc_state->lane_count = max_link_config.lane_count;
/*
* FIXME: allocate the BW according to link_bpp, which in the case of
@@ -464,6 +477,7 @@ static int mst_stream_dsc_compute_link_config(struct intel_dp *intel_dp,
{
struct intel_display *display = to_intel_display(intel_dp);
struct intel_connector *connector = to_intel_connector(conn_state->connector);
+ struct intel_dp_link_config max_link_config;
crtc_state->pipe_bpp = limits->pipe.max_bpp;
@@ -471,8 +485,17 @@ static int mst_stream_dsc_compute_link_config(struct intel_dp *intel_dp,
"DSC Sink supported compressed min bpp " FXP_Q4_FMT " compressed max bpp " FXP_Q4_FMT "\n",
FXP_Q4_ARGS(limits->link.min_bpp_x16), FXP_Q4_ARGS(limits->link.max_bpp_x16));
- crtc_state->lane_count = limits->max_lane_count;
- crtc_state->port_clock = limits->max_rate;
+ /*
+ * FIXME: Use a proper iteration over the link configurations, instead
+ * of using only the max BW config. For instance UHBR rate configs may
+ * have additional limitations over non-UHBR ones, due to the DSC DPT
+ * bpp maximum limit.
+ */
+ if (!intel_dp_get_connector_max_link_config(connector, limits, &max_link_config))
+ return -EINVAL;
+
+ crtc_state->port_clock = max_link_config.rate;
+ crtc_state->lane_count = max_link_config.lane_count;
return intel_dp_mtp_tu_compute_config(intel_dp, crtc_state, conn_state,
limits->link.min_bpp_x16,
@@ -488,6 +511,20 @@ static int mode_hblank_period_ns(const struct drm_display_mode *mode)
mode->crtc_clock);
}
+static int get_connector_max_rate(const struct intel_connector *connector,
+ const struct link_config_limits *limits)
+{
+ struct intel_dp *intel_dp = intel_attached_dp((struct intel_connector *)connector);
+ struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
+ struct intel_dp_link_config max_link_config;
+
+ intel_dp_link_caps_get_max_config(link_caps,
+ INTEL_DP_LINK_CAPS_ORDER_KEY_RATE_LANE,
+ limits->link_config_filter, &max_link_config);
+
+ return max_link_config.rate;
+}
+
static bool
hblank_expansion_quirk_needs_dsc(const struct intel_connector *connector,
const struct intel_crtc_state *crtc_state,
@@ -498,11 +535,13 @@ hblank_expansion_quirk_needs_dsc(const struct intel_connector *connector,
bool is_uhbr_sink = connector->mst.dp &&
drm_dp_128b132b_supported(connector->mst.dp->dpcd);
int hblank_limit = is_uhbr_sink ? 500 : 300;
+ int max_rate;
if (!connector->dp.dsc_hblank_expansion_quirk)
return false;
- if (is_uhbr_sink && !drm_dp_is_uhbr_rate(limits->max_rate))
+ max_rate = get_connector_max_rate(connector, limits);
+ if (is_uhbr_sink && !drm_dp_is_uhbr_rate(max_rate))
return false;
if (mode_hblank_period_ns(adjusted_mode) > hblank_limit)
@@ -524,6 +563,7 @@ adjust_limits_for_dsc_hblank_expansion_quirk(struct intel_dp *intel_dp,
struct intel_display *display = to_intel_display(connector);
const struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
int min_bpp_x16 = limits->link.min_bpp_x16;
+ int max_rate;
if (!hblank_expansion_quirk_needs_dsc(connector, crtc_state, limits))
return true;
@@ -550,11 +590,10 @@ adjust_limits_for_dsc_hblank_expansion_quirk(struct intel_dp *intel_dp,
return true;
}
- drm_WARN_ON(display->drm, limits->min_rate != limits->max_rate);
-
- if (limits->max_rate < 540000)
+ max_rate = get_connector_max_rate(connector, limits);
+ if (max_rate < 540000)
min_bpp_x16 = fxp_q4_from_int(13);
- else if (limits->max_rate < 810000)
+ else if (max_rate < 810000)
min_bpp_x16 = fxp_q4_from_int(10);
if (limits->link.min_bpp_x16 >= min_bpp_x16)
@@ -1476,6 +1515,7 @@ mst_connector_mode_valid_ctx(struct drm_connector *_connector,
unsigned long bw_overhead_flags =
DRM_DP_BW_OVERHEAD_MST | DRM_DP_BW_OVERHEAD_SSC_REF_CLK;
int min_link_bpp_x16 = fxp_q4_from_int(18);
+ struct intel_dp_link_config max_bw_config;
static bool supports_dsc;
int ret;
bool dsc = false;
@@ -1508,8 +1548,9 @@ mst_connector_mode_valid_ctx(struct drm_connector *_connector,
min_link_bpp_x16 = intel_dp_compute_min_compressed_bpp_x16(connector,
INTEL_OUTPUT_FORMAT_RGB);
- max_link_clock = intel_dp_max_link_rate(intel_dp);
- max_lanes = intel_dp_max_lane_count(intel_dp);
+ intel_dp_link_caps_get_max_bw_config(intel_dp->link.caps, &max_bw_config);
+ max_link_clock = max_bw_config.rate;
+ max_lanes = max_bw_config.lane_count;
max_rate = intel_dp_max_link_data_rate(intel_dp,
max_link_clock, max_lanes);
@@ -2135,14 +2176,19 @@ bool intel_dp_mst_crtc_needs_modeset(struct intel_atomic_state *state,
*/
void intel_dp_mst_prepare_probe(struct intel_dp *intel_dp)
{
- int link_rate = intel_dp_max_link_rate(intel_dp);
- int lane_count = intel_dp_max_lane_count(intel_dp);
+ struct intel_dp_link_config max_bw_config;
+ int link_rate;
+ int lane_count;
u8 rate_select;
u8 link_bw;
if (intel_dp->link.active)
return;
+ intel_dp_link_caps_get_max_bw_config(intel_dp->link.caps, &max_bw_config);
+ link_rate = max_bw_config.rate;
+ lane_count = max_bw_config.lane_count;
+
if (intel_mst_probed_link_params_valid(intel_dp, link_rate, lane_count))
return;
diff --git a/drivers/gpu/drm/i915/display/intel_dp_test.c b/drivers/gpu/drm/i915/display/intel_dp_test.c
index da7632536dac..0551a1ce60d3 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_test.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_test.c
@@ -28,12 +28,92 @@ void intel_dp_test_reset(struct intel_dp *intel_dp)
memset(&intel_dp->compliance, 0, sizeof(intel_dp->compliance));
}
+static bool set_filter_for_lane_count(struct intel_connector *connector,
+ struct intel_dp_link_caps *link_caps,
+ int lane_count,
+ struct link_config_limits *limits)
+{
+ struct intel_dp_link_config link_config;
+ struct intel_dp_link_caps_order order =
+ intel_dp_link_caps_connector_compute_order(connector);
+ struct intel_dp_link_caps_filter new_filter = INTEL_DP_LINK_CAPS_FILTER_NONE;
+ struct intel_dp_link_caps_iter iter;
+ bool found = false;
+
+ intel_dp_link_caps_iter_start(&iter, link_caps, order, limits->link_config_filter);
+ for_each_dp_link_config(&iter, &link_config) {
+ if (link_config.lane_count != lane_count)
+ continue;
+
+ intel_dp_link_caps_filter_add(link_caps, &new_filter, &link_config);
+ found = true;
+ }
+ intel_dp_link_caps_iter_end(&iter);
+
+ if (!found)
+ return false;
+
+ limits->link_config_filter = new_filter;
+
+ return true;
+}
+
+static bool set_filter_for_link_config(struct intel_connector *connector,
+ struct intel_dp_link_caps *link_caps,
+ const struct intel_dp_link_config *link_params,
+ struct link_config_limits *limits)
+{
+ struct intel_dp_link_caps_filter new_filter = INTEL_DP_LINK_CAPS_FILTER_NONE;
+
+ if (!intel_dp_link_caps_filter_add(link_caps, &new_filter, link_params))
+ return false;
+
+ limits->link_config_filter = new_filter;
+
+ return true;
+}
+
+static bool set_filter_for_link_params(struct intel_connector *connector,
+ int link_rate, int lane_count,
+ struct link_config_limits *limits)
+{
+ struct intel_dp *intel_dp = intel_attached_dp(connector);
+ struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
+ struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
+ struct intel_display *display = to_intel_display(intel_dp);
+ struct intel_dp_link_config requested_config;
+
+ requested_config.rate = link_rate;
+ requested_config.lane_count = lane_count;
+
+ if (set_filter_for_link_config(connector, link_caps, &requested_config, limits))
+ return true;
+
+ /*
+ * Preserve the legacy behavior: if the requested (rate, lane_count)
+ * combination is not an allowed config, fall back to all configs
+ * matching the requested lane count.
+ *
+ * TODO: Recheck whether this behavior is actually correct.
+ */
+ if (set_filter_for_lane_count(connector, link_caps, lane_count, limits))
+ return true;
+
+ drm_dbg_kms(display->drm,
+ "[ENCODER:%d:%s] Invalid autotest link config parameters: %dx%d\n",
+ encoder->base.base.id, encoder->base.name,
+ requested_config.lane_count,
+ requested_config.rate);
+
+ return false;
+}
+
/* Adjust link config limits based on compliance test requests. */
-void intel_dp_test_compute_config(struct intel_dp *intel_dp,
+bool intel_dp_test_compute_config(struct intel_connector *connector,
struct intel_crtc_state *pipe_config,
struct link_config_limits *limits)
{
- struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
+ struct intel_dp *intel_dp = intel_attached_dp(connector);
struct intel_display *display = to_intel_display(intel_dp);
/* For DP Compliance we override the computed bpp for the pipe */
@@ -49,23 +129,14 @@ void intel_dp_test_compute_config(struct intel_dp *intel_dp,
/* Use values requested by Compliance Test Request */
if (intel_dp->compliance.test_type == DP_TEST_LINK_TRAINING) {
- int index;
-
- /* Validate the compliance test data since max values
- * might have changed due to link train fallback.
- */
- if (intel_dp_link_params_valid(intel_dp, intel_dp->compliance.test_link_rate,
- intel_dp->compliance.test_lane_count)) {
- index = intel_dp_link_caps_common_rate_idx(link_caps,
- intel_dp->compliance.test_link_rate);
- if (index >= 0) {
- limits->min_rate = intel_dp->compliance.test_link_rate;
- limits->max_rate = intel_dp->compliance.test_link_rate;
- }
- limits->min_lane_count = intel_dp->compliance.test_lane_count;
- limits->max_lane_count = intel_dp->compliance.test_lane_count;
- }
+ if (!set_filter_for_link_params(connector,
+ intel_dp->compliance.test_link_rate,
+ intel_dp->compliance.test_lane_count,
+ limits))
+ return false;
}
+
+ return true;
}
/* Compliance test status bits */
diff --git a/drivers/gpu/drm/i915/display/intel_dp_test.h b/drivers/gpu/drm/i915/display/intel_dp_test.h
index dcc167e4c7f6..a08f37a63dc9 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_test.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_test.h
@@ -6,6 +6,7 @@
#include <linux/types.h>
+struct intel_connector;
struct intel_crtc_state;
struct intel_display;
struct intel_dp;
@@ -13,7 +14,7 @@ struct link_config_limits;
void intel_dp_test_reset(struct intel_dp *intel_dp);
void intel_dp_test_request(struct intel_dp *intel_dp);
-void intel_dp_test_compute_config(struct intel_dp *intel_dp,
+bool intel_dp_test_compute_config(struct intel_connector *connector,
struct intel_crtc_state *pipe_config,
struct link_config_limits *limits);
bool intel_dp_test_phy(struct intel_dp *intel_dp);
diff --git a/drivers/gpu/drm/i915/display/intel_dp_tunnel.c b/drivers/gpu/drm/i915/display/intel_dp_tunnel.c
index 76e9753766b9..49fa4c9699b6 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_tunnel.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_tunnel.c
@@ -58,10 +58,12 @@ static int kbytes_to_mbits(int kbytes)
static int get_current_link_bw(struct intel_dp *intel_dp)
{
struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
- int rate = intel_dp_max_common_rate(link_caps);
- int lane_count = intel_dp_link_caps_max_common_lane_count(link_caps);
+ struct intel_dp_link_config max_bw_config;
- return intel_dp_max_link_data_rate(intel_dp, rate, lane_count);
+ intel_dp_link_caps_get_max_bw_config(link_caps, &max_bw_config);
+
+ return intel_dp_max_link_data_rate(intel_dp, max_bw_config.rate,
+ max_bw_config.lane_count);
}
static int __update_tunnel_state(struct intel_dp *intel_dp, bool force_sink_update)
diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c
index bffbdee76ee1..51e4f3309b8b 100644
--- a/drivers/gpu/drm/i915/display/intel_vrr.c
+++ b/drivers/gpu/drm/i915/display/intel_vrr.c
@@ -5,6 +5,7 @@
*/
#include <drm/drm_print.h>
+#include <drm/intel/step.h>
#include "intel_alpm.h"
#include "intel_cmtg.h"
@@ -1106,6 +1107,11 @@ void intel_vrr_get_config(struct intel_crtc_state *crtc_state)
crtc_state->vrr.vmin += intel_vrr_vmin_flipline_offset(display);
}
+ if (display->platform.novalake &&
+ IS_DISPLAY_STEP(display, STEP_A0, STEP_C0))
+ crtc_state->hw.adjusted_mode.crtc_vtotal =
+ intel_vrr_vmin_vtotal(crtc_state);
+
if (HAS_AS_SDP(display)) {
trans_vrr_vsync =
intel_de_read(display,
diff --git a/drivers/gpu/drm/i915/display/tests/Makefile b/drivers/gpu/drm/i915/display/tests/Makefile
new file mode 100644
index 000000000000..ad250974160f
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/tests/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+
+subdir-ccflags-y += -I$(srctree)/drivers/gpu/drm/i915/display/
+
+obj-$(CONFIG_DRM_I915_KUNIT_TEST) += i915_display_test.o
+i915_display_test-y = \
+ intel_dp_link_test.o
diff --git a/drivers/gpu/drm/i915/display/tests/intel_dp_link_test.c b/drivers/gpu/drm/i915/display/tests/intel_dp_link_test.c
new file mode 100644
index 000000000000..e1c356ba11b5
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/tests/intel_dp_link_test.c
@@ -0,0 +1,1440 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+
+#include <kunit/test.h>
+
+#include <linux/compiler.h>
+#include <linux/device.h>
+#include <linux/log2.h>
+#include <linux/prandom.h>
+#include <linux/random.h>
+
+#include <drm/display/drm_dp_helper.h>
+
+#include <drm/intel/display_member.h>
+
+#include "intel_connector.h"
+#include "intel_display_core.h"
+#include "intel_display_types.h"
+#include "intel_dp_link_caps.h"
+#include "intel_dp_link_training.h"
+
+#define LINK_TEST_NUM_LANE_CONFIGS(__max_lane_count) \
+ (ilog2(__max_lane_count) + 1)
+
+#define LINK_TEST_NUM_CONFIGS(__num_rates, __max_lane_count) \
+ ((__num_rates) * LINK_TEST_NUM_LANE_CONFIGS(__max_lane_count))
+
+#define LINK_TEST_MAX_LANE_COUNT ((u32)4)
+#define LINK_TEST_MAX_CONFIGS LINK_TEST_NUM_CONFIGS(DP_MAX_SUPPORTED_RATES, \
+ LINK_TEST_MAX_LANE_COUNT)
+
+#define LINK_TEST_NUM_RANDOM_ITERATIONS 50
+
+struct test_ctx {
+ struct {
+ struct intel_display display;
+ struct device device;
+ struct __intel_generic_device generic_device;
+
+ struct intel_connector connector;
+ struct intel_digital_port dig_port;
+
+ struct intel_crtc_state crtc_state;
+ } dev;
+
+ const struct intel_dp_link_caps_test_ops *link_caps_ops;
+ const struct intel_dp_link_training_test_ops *link_training_ops;
+
+ struct rnd_state rnd;
+};
+
+struct link_rate_set {
+ const int *entries;
+ int size;
+};
+
+struct link_config_set {
+ struct intel_dp_link_config entries[LINK_TEST_MAX_CONFIGS];
+ int size;
+};
+
+struct test_config_table {
+ struct kunit *test;
+
+ struct link_rate_set rates;
+ int max_lane_count;
+ struct link_config_set disabled_configs;
+};
+
+static const int standard_dp_link_rates[] = {
+ 162000, 270000, 540000, 810000, 1000000, 1350000, 2000000
+};
+
+#define LINK_TEST_NUM_STANDARD_RATES (ARRAY_SIZE(standard_dp_link_rates))
+
+#define INIT_STANDARD_TABLE(__test, __num_rates, __max_lane_count) { \
+ .test = (__test), \
+ .rates = { \
+ .entries = standard_dp_link_rates, \
+ .size = (__num_rates), \
+ }, \
+ .max_lane_count = (__max_lane_count), \
+}
+
+static const struct link_config_set standard_dp_link_configs[] = {
+ [INTEL_DP_LINK_CAPS_ORDER_KEY_BW] = { /* MBps PBN */
+ .entries = {
+ { .rate = 162000, .lane_count = 1 }, /* 162.0 3.00 */
+ { .rate = 270000, .lane_count = 1 }, /* 270.0 5.00 */
+ { .rate = 162000, .lane_count = 2 }, /* 324.0 6.00 */
+ { .rate = 270000, .lane_count = 2 }, /* 540.0 10.00 */
+ { .rate = 540000, .lane_count = 1 }, /* 540.0 10.00 */
+ { .rate = 162000, .lane_count = 4 }, /* 648.0 12.00 */
+ { .rate = 810000, .lane_count = 1 }, /* 810.0 15.00 */
+ { .rate = 270000, .lane_count = 4 }, /* 1080.0 20.00 */
+ { .rate = 540000, .lane_count = 2 }, /* 1080.0 20.00 */
+ { .rate = 1000000, .lane_count = 1 }, /* 1208.9 22.39 */
+ { .rate = 810000, .lane_count = 2 }, /* 1620.0 30.00 */
+ { .rate = 1350000, .lane_count = 1 }, /* 1632.0 30.22 */
+ { .rate = 540000, .lane_count = 4 }, /* 2160.0 40.00 */
+ { .rate = 1000000, .lane_count = 2 }, /* 2417.8 44.77 */
+ { .rate = 2000000, .lane_count = 1 }, /* 2417.8 44.77 */
+ { .rate = 810000, .lane_count = 4 }, /* 3240.0 60.00 */
+ { .rate = 1350000, .lane_count = 2 }, /* 3264.0 60.44 */
+ { .rate = 1000000, .lane_count = 4 }, /* 4835.6 89.55 */
+ { .rate = 2000000, .lane_count = 2 }, /* 4835.6 89.55 */
+ { .rate = 1350000, .lane_count = 4 }, /* 6527.9 120.89 */
+ { .rate = 2000000, .lane_count = 4 }, /* 9671.1 179.09 */
+ },
+ .size = LINK_TEST_NUM_CONFIGS(ARRAY_SIZE(standard_dp_link_rates),
+ LINK_TEST_MAX_LANE_COUNT),
+ },
+ [INTEL_DP_LINK_CAPS_ORDER_KEY_RATE_LANE] = {
+ .entries = {
+ { .rate = 162000, .lane_count = 1 },
+ { .rate = 162000, .lane_count = 2 },
+ { .rate = 162000, .lane_count = 4 },
+
+ { .rate = 270000, .lane_count = 1 },
+ { .rate = 270000, .lane_count = 2 },
+ { .rate = 270000, .lane_count = 4 },
+
+ { .rate = 540000, .lane_count = 1 },
+ { .rate = 540000, .lane_count = 2 },
+ { .rate = 540000, .lane_count = 4 },
+
+ { .rate = 810000, .lane_count = 1 },
+ { .rate = 810000, .lane_count = 2 },
+ { .rate = 810000, .lane_count = 4 },
+
+ { .rate = 1000000, .lane_count = 1 },
+ { .rate = 1000000, .lane_count = 2 },
+ { .rate = 1000000, .lane_count = 4 },
+
+ { .rate = 1350000, .lane_count = 1 },
+ { .rate = 1350000, .lane_count = 2 },
+ { .rate = 1350000, .lane_count = 4 },
+
+ { .rate = 2000000, .lane_count = 1 },
+ { .rate = 2000000, .lane_count = 2 },
+ { .rate = 2000000, .lane_count = 4 },
+ },
+ .size = LINK_TEST_NUM_CONFIGS(ARRAY_SIZE(standard_dp_link_rates),
+ LINK_TEST_MAX_LANE_COUNT),
+ },
+ [INTEL_DP_LINK_CAPS_ORDER_KEY_LANE_RATE] = {
+ .entries = {
+ { .rate = 162000, .lane_count = 1 },
+ { .rate = 270000, .lane_count = 1 },
+ { .rate = 540000, .lane_count = 1 },
+ { .rate = 810000, .lane_count = 1 },
+ { .rate = 1000000, .lane_count = 1 },
+ { .rate = 1350000, .lane_count = 1 },
+ { .rate = 2000000, .lane_count = 1 },
+
+ { .rate = 162000, .lane_count = 2 },
+ { .rate = 270000, .lane_count = 2 },
+ { .rate = 540000, .lane_count = 2 },
+ { .rate = 810000, .lane_count = 2 },
+ { .rate = 1000000, .lane_count = 2 },
+ { .rate = 1350000, .lane_count = 2 },
+ { .rate = 2000000, .lane_count = 2 },
+
+ { .rate = 162000, .lane_count = 4 },
+ { .rate = 270000, .lane_count = 4 },
+ { .rate = 540000, .lane_count = 4 },
+ { .rate = 810000, .lane_count = 4 },
+ { .rate = 1000000, .lane_count = 4 },
+ { .rate = 1350000, .lane_count = 4 },
+ { .rate = 2000000, .lane_count = 4 },
+ },
+ .size = LINK_TEST_NUM_CONFIGS(ARRAY_SIZE(standard_dp_link_rates),
+ LINK_TEST_MAX_LANE_COUNT),
+ },
+};
+
+static int lookup_rate(const struct link_rate_set *rate_set, int rate)
+{
+ int i;
+
+ for (i = 0; i < rate_set->size; i++)
+ if (rate_set->entries[i] == rate)
+ return i;
+
+ return -1;
+}
+
+static bool has_rate(const struct link_rate_set *rate_set, int rate)
+{
+ return lookup_rate(rate_set, rate) >= 0;
+}
+
+static bool link_configs_match(const struct intel_dp_link_config *a,
+ const struct intel_dp_link_config *b)
+{
+ return a->rate == b->rate && a->lane_count == b->lane_count;
+}
+
+static int lookup_config(const struct link_config_set *config_set,
+ const struct intel_dp_link_config *config)
+{
+ int i;
+
+ for (i = 0; i < config_set->size; i++)
+ if (link_configs_match(&config_set->entries[i], config))
+ return i;
+
+ return -1;
+}
+
+static bool has_config(const struct link_config_set *config_set,
+ const struct intel_dp_link_config *config)
+{
+ return lookup_config(config_set, config) >= 0;
+}
+
+static void add_config(struct kunit *test,
+ struct link_config_set *config_set,
+ const struct intel_dp_link_config *config)
+{
+ KUNIT_ASSERT_LT(test, config_set->size, ARRAY_SIZE(config_set->entries));
+
+ config_set->entries[config_set->size] = *config;
+ config_set->size++;
+}
+
+static const struct intel_dp_link_caps_order config_orders[] = {
+ {
+ .key = INTEL_DP_LINK_CAPS_ORDER_KEY_BW,
+ .dir = INTEL_DP_LINK_CAPS_ORDER_DIR_ASC,
+ }, {
+ .key = INTEL_DP_LINK_CAPS_ORDER_KEY_BW,
+ .dir = INTEL_DP_LINK_CAPS_ORDER_DIR_DESC,
+ }, {
+ .key = INTEL_DP_LINK_CAPS_ORDER_KEY_RATE_LANE,
+ .dir = INTEL_DP_LINK_CAPS_ORDER_DIR_ASC,
+ }, {
+ .key = INTEL_DP_LINK_CAPS_ORDER_KEY_RATE_LANE,
+ .dir = INTEL_DP_LINK_CAPS_ORDER_DIR_DESC,
+ }, {
+ .key = INTEL_DP_LINK_CAPS_ORDER_KEY_LANE_RATE,
+ .dir = INTEL_DP_LINK_CAPS_ORDER_DIR_ASC,
+ }, {
+ .key = INTEL_DP_LINK_CAPS_ORDER_KEY_LANE_RATE,
+ .dir = INTEL_DP_LINK_CAPS_ORDER_DIR_DESC,
+ }
+};
+
+static const struct link_config_set *
+link_caps_config_order_key_to_set(struct kunit *test, enum intel_dp_link_caps_order_key key)
+{
+ return &standard_dp_link_configs[key];
+}
+
+/*
+ * TEST: Baseline with fixed reference table
+ * -----------------------------------------
+ * Verify the link_caps config iterator using fixed standard DP config tables.
+ */
+static void baseline_test_for_order(struct kunit *test,
+ struct intel_dp_link_caps *link_caps,
+ struct intel_dp_link_caps_order config_order)
+{
+ struct test_ctx *ctx = test->priv;
+ const struct link_config_set *config_set =
+ link_caps_config_order_key_to_set(test, config_order.key);
+ const struct intel_dp_link_caps_test_ops *ops = ctx->link_caps_ops;
+ struct intel_dp_link_config iter_config;
+ struct intel_dp_link_caps_iter iter;
+ int pos = 0;
+
+ ops->iter_start(&iter, link_caps, config_order, INTEL_DP_LINK_CAPS_FILTER_ALL);
+ for_each_dp_link_config(&iter, &iter_config) {
+ int idx = pos;
+
+ if (config_order.dir == INTEL_DP_LINK_CAPS_ORDER_DIR_DESC)
+ idx = config_set->size - idx - 1;
+
+ KUNIT_EXPECT_TRUE(test, link_configs_match(&iter_config,
+ &config_set->entries[idx]));
+
+ pos++;
+ }
+ ops->iter_end(&iter);
+}
+
+static void intel_dp_link_caps_test_baseline(struct kunit *test)
+{
+ struct test_ctx *ctx = test->priv;
+ struct intel_dp_link_caps *link_caps = ctx->dev.dig_port.dp.link.caps;
+ const struct intel_dp_link_caps_test_ops *ops =
+ ctx->link_caps_ops;
+ int i;
+
+ ops->update(link_caps,
+ standard_dp_link_rates, LINK_TEST_NUM_STANDARD_RATES,
+ LINK_TEST_MAX_LANE_COUNT,
+ true);
+
+ for (i = 0; i < ARRAY_SIZE(config_orders); i++)
+ baseline_test_for_order(test, link_caps, config_orders[i]);
+}
+
+static int get_num_configs(int num_rates, int max_lane_count)
+{
+ return num_rates * LINK_TEST_NUM_LANE_CONFIGS(max_lane_count);
+}
+
+static int rand_in_range(struct test_ctx *ctx, int min, int max)
+{
+ return min + (prandom_u32_state(&ctx->rnd) % (max - min + 1));
+}
+
+/*
+ * TEST: Update reset
+ * ------------------
+ * Verify that resetting link_caps with the DP standard rates/lane
+ * counts updates the configuration table accordingly for all
+ * combinations.
+ */
+static void verify_bw_asc_config_order(struct kunit *test,
+ const struct intel_dp_link_config *last_config,
+ const struct intel_dp_link_config *config)
+{
+ int config_bw = drm_dp_max_dprx_data_rate(config->rate,
+ config->lane_count);
+ int last_config_bw = drm_dp_max_dprx_data_rate(last_config->rate,
+ last_config->lane_count);
+
+ KUNIT_EXPECT_GE(test, config_bw, last_config_bw);
+ if (config_bw == last_config_bw)
+ KUNIT_EXPECT_GT(test, config->rate, last_config->rate);
+}
+
+static void verify_bw_desc_config_order(struct kunit *test,
+ const struct intel_dp_link_config *last_config,
+ const struct intel_dp_link_config *config)
+{
+ int config_bw = drm_dp_max_dprx_data_rate(config->rate,
+ config->lane_count);
+ int last_config_bw = drm_dp_max_dprx_data_rate(last_config->rate,
+ last_config->lane_count);
+
+ KUNIT_EXPECT_LE(test, config_bw, last_config_bw);
+ if (config_bw == last_config_bw)
+ KUNIT_EXPECT_LT(test, config->rate, last_config->rate);
+}
+
+static void verify_rate_lane_asc_config_order(struct kunit *test,
+ const struct intel_dp_link_config *last_config,
+ const struct intel_dp_link_config *config)
+{
+ KUNIT_EXPECT_GE(test, config->rate, last_config->rate);
+ if (config->rate == last_config->rate)
+ KUNIT_EXPECT_GT(test, config->lane_count, last_config->lane_count);
+}
+
+static void verify_rate_lane_desc_config_order(struct kunit *test,
+ const struct intel_dp_link_config *last_config,
+ const struct intel_dp_link_config *config)
+{
+ KUNIT_EXPECT_LE(test, config->rate, last_config->rate);
+ if (config->rate == last_config->rate)
+ KUNIT_EXPECT_LT(test, config->lane_count, last_config->lane_count);
+}
+
+static void verify_lane_rate_asc_config_order(struct kunit *test,
+ const struct intel_dp_link_config *last_config,
+ const struct intel_dp_link_config *config)
+{
+ KUNIT_EXPECT_GE(test, config->lane_count, last_config->lane_count);
+ if (config->lane_count == last_config->lane_count)
+ KUNIT_EXPECT_GT(test, config->rate, last_config->rate);
+}
+
+static void verify_lane_rate_desc_config_order(struct kunit *test,
+ const struct intel_dp_link_config *last_config,
+ const struct intel_dp_link_config *config)
+{
+ KUNIT_EXPECT_LE(test, config->lane_count, last_config->lane_count);
+ if (config->lane_count == last_config->lane_count)
+ KUNIT_EXPECT_LT(test, config->rate, last_config->rate);
+}
+
+static void verify_config_order(struct kunit *test,
+ struct intel_dp_link_caps_order config_order,
+ const struct intel_dp_link_config *last_config,
+ const struct intel_dp_link_config *config)
+{
+ switch (config_order.key) {
+ case INTEL_DP_LINK_CAPS_ORDER_KEY_BW:
+ if (config_order.dir == INTEL_DP_LINK_CAPS_ORDER_DIR_ASC)
+ verify_bw_asc_config_order(test, last_config, config);
+ else
+ verify_bw_desc_config_order(test, last_config, config);
+ break;
+ case INTEL_DP_LINK_CAPS_ORDER_KEY_RATE_LANE:
+ if (config_order.dir == INTEL_DP_LINK_CAPS_ORDER_DIR_ASC)
+ verify_rate_lane_asc_config_order(test, last_config, config);
+ else
+ verify_rate_lane_desc_config_order(test, last_config, config);
+ break;
+ case INTEL_DP_LINK_CAPS_ORDER_KEY_LANE_RATE:
+ if (config_order.dir == INTEL_DP_LINK_CAPS_ORDER_DIR_ASC)
+ verify_lane_rate_asc_config_order(test, last_config, config);
+ else
+ verify_lane_rate_desc_config_order(test, last_config, config);
+ break;
+ default:
+ KUNIT_FAIL_AND_ABORT(test, "Missing order key: %d", config_order.key);
+ }
+}
+
+static int expected_num_configs(const struct test_config_table *expected_table,
+ const struct intel_dp_link_config *max_limits)
+{
+ int num_configs = 0;
+ int lane_count;
+ int rate_idx;
+
+ for (rate_idx = 0; rate_idx < expected_table->rates.size; rate_idx++) {
+ for (lane_count = 1; lane_count <= expected_table->max_lane_count; lane_count <<= 1) {
+ struct intel_dp_link_config config = {
+ .rate = expected_table->rates.entries[rate_idx],
+ .lane_count = lane_count,
+ };
+
+ if (config.rate > max_limits->rate ||
+ config.lane_count > max_limits->lane_count)
+ continue;
+
+ if (has_config(&expected_table->disabled_configs, &config))
+ continue;
+
+ num_configs++;
+ }
+ }
+
+ return num_configs;
+}
+
+static void
+verify_link_caps_for_order(const struct test_config_table *expected_table,
+ struct intel_dp_link_caps *link_caps,
+ struct intel_dp_link_caps_order config_order,
+ const struct intel_dp_link_config *max_limits)
+{
+ struct kunit *test = expected_table->test;
+ struct test_ctx *ctx = test->priv;
+ const struct intel_dp_link_caps_test_ops *ops =
+ ctx->link_caps_ops;
+ struct intel_dp_link_config expected_max_bw_config = {};
+ struct intel_dp_link_config actual_max_bw_config;
+ struct intel_dp_link_config last_config = {};
+ struct intel_dp_link_config old_max_limits;
+ struct intel_dp_link_config iter_config;
+ struct intel_dp_link_caps_iter iter;
+ int num_actual_configs = 0;
+ int max_bw = 0;
+
+ ops->get_max_limits(link_caps, &old_max_limits);
+ ops->set_max_limits(link_caps, max_limits);
+
+ ops->iter_start(&iter, link_caps, config_order, INTEL_DP_LINK_CAPS_FILTER_ALL);
+ for_each_dp_link_config(&iter, &iter_config) {
+ int bw;
+
+ KUNIT_EXPECT_LE(test, iter_config.rate, max_limits->rate);
+ KUNIT_EXPECT_LE(test, iter_config.lane_count, max_limits->lane_count);
+
+ num_actual_configs++;
+
+ /*
+ * Verify the config's rate/lane-count values and its ordering relative
+ * to the previous config.
+ */
+ if (last_config.rate)
+ verify_config_order(test, config_order, &last_config, &iter_config);
+ last_config = iter_config;
+
+ KUNIT_EXPECT_TRUE(test, has_rate(&expected_table->rates,
+ iter_config.rate));
+ KUNIT_EXPECT_LE(test, iter_config.lane_count,
+ expected_table->max_lane_count);
+ KUNIT_EXPECT_TRUE(test, is_power_of_2(iter_config.lane_count));
+
+ /* Verify the config's disabled state */
+ KUNIT_EXPECT_FALSE(test, has_config(&expected_table->disabled_configs,
+ &iter_config));
+
+ /*
+ * Update the max limits for allowed configs, verified at the
+ * end for the whole config table.
+ */
+
+ bw = drm_dp_max_dprx_data_rate(iter_config.rate, iter_config.lane_count);
+ if (bw > max_bw ||
+ (bw == max_bw && iter_config.rate > expected_max_bw_config.rate)) {
+ max_bw = bw;
+ expected_max_bw_config = iter_config;
+ }
+ }
+ ops->iter_end(&iter);
+
+ KUNIT_EXPECT_EQ(test, num_actual_configs, expected_num_configs(expected_table, max_limits));
+
+ ops->get_max_bw_config(link_caps, &actual_max_bw_config);
+ KUNIT_EXPECT_TRUE(test, link_configs_match(&expected_max_bw_config,
+ &actual_max_bw_config));
+
+ KUNIT_ASSERT_TRUE(test, ops->set_max_limits(link_caps, &old_max_limits));
+}
+
+static bool max_limits_valid(const struct test_config_table *expected_table,
+ const struct intel_dp_link_config *max_limits)
+{
+ int lane_count;
+ int rate_idx;
+
+ for (rate_idx = 0; rate_idx < expected_table->rates.size; rate_idx++) {
+ for (lane_count = 1; lane_count <= expected_table->max_lane_count; lane_count <<= 1) {
+ struct intel_dp_link_config config = {
+ .rate = expected_table->rates.entries[rate_idx],
+ .lane_count = lane_count,
+ };
+
+ if (has_config(&expected_table->disabled_configs, &config))
+ continue;
+
+ if (config.rate <= max_limits->rate &&
+ config.lane_count <= max_limits->lane_count)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void get_max_limits(const struct test_config_table *expected_table,
+ struct intel_dp_link_config *max_limits)
+{
+ int lane_count;
+ int rate_idx;
+
+ max_limits->rate = 0;
+ max_limits->lane_count = 0;
+
+ for (rate_idx = 0; rate_idx < expected_table->rates.size; rate_idx++) {
+ for (lane_count = 1; lane_count <= expected_table->max_lane_count; lane_count <<= 1) {
+ struct intel_dp_link_config config = {
+ .rate = expected_table->rates.entries[rate_idx],
+ .lane_count = lane_count,
+ };
+
+ if (has_config(&expected_table->disabled_configs, &config))
+ continue;
+
+ max_limits->rate = max(max_limits->rate, config.rate);
+ max_limits->lane_count = max(max_limits->lane_count, config.lane_count);
+ }
+ }
+}
+
+static void verify_link_caps(const struct test_config_table *expected_table,
+ struct intel_dp_link_caps *link_caps)
+{
+ struct kunit *test = expected_table->test;
+ struct test_ctx *ctx = test->priv;
+ const struct intel_dp_link_caps_test_ops *ops = ctx->link_caps_ops;
+ struct intel_dp_link_config max_limits;
+ int i;
+
+ get_max_limits(expected_table, &max_limits);
+
+ for (i = 0; i < ARRAY_SIZE(config_orders); i++) {
+ int lane_count;
+ int rate_idx;
+
+ verify_link_caps_for_order(expected_table, link_caps, config_orders[i], &max_limits);
+ /*
+ * Verify iteration after setting the max limits to each
+ * configurations.
+ */
+ for (rate_idx = 0; rate_idx < expected_table->rates.size; rate_idx++) {
+ for (lane_count = 1; lane_count <= expected_table->max_lane_count; lane_count <<= 1) {
+ struct intel_dp_link_config config = {
+ .rate = expected_table->rates.entries[rate_idx],
+ .lane_count = lane_count,
+ };
+
+ if (!max_limits_valid(expected_table, &config)) {
+ /* Verify that invalid max limits are rejected. */
+ KUNIT_EXPECT_FALSE(test, ops->set_max_limits(link_caps, &config));
+
+ continue;
+ }
+
+ verify_link_caps_for_order(expected_table, link_caps, config_orders[i],
+ &config);
+ }
+ }
+ }
+}
+
+static void update_link_caps_and_verify(struct test_config_table *expected_table,
+ struct intel_dp_link_caps *link_caps,
+ bool reset)
+{
+ struct kunit *test = expected_table->test;
+ struct test_ctx *ctx = test->priv;
+ const struct intel_dp_link_caps_test_ops *ops =
+ ctx->link_caps_ops;
+ bool link_params_changed;
+
+ link_params_changed = ops->update(link_caps,
+ expected_table->rates.entries,
+ expected_table->rates.size,
+ expected_table->max_lane_count,
+ reset);
+ KUNIT_EXPECT_TRUE(test, !reset || link_params_changed);
+
+ /*
+ * ops->update() re-enables all configurations when called with
+ * reset=true, or changed link parameters.
+ */
+ if (link_params_changed)
+ expected_table->disabled_configs.size = 0;
+
+ verify_link_caps(expected_table, link_caps);
+}
+
+static void intel_dp_link_caps_test_update_reset(struct kunit *test)
+{
+ struct test_ctx *ctx = test->priv;
+ struct intel_dp_link_caps *link_caps = ctx->dev.dig_port.dp.link.caps;
+ int max_lane_count;
+ int num_rates;
+
+ for (max_lane_count = 1;
+ max_lane_count <= LINK_TEST_MAX_LANE_COUNT;
+ max_lane_count <<= 1) {
+ for (num_rates = 1;
+ num_rates <= LINK_TEST_NUM_STANDARD_RATES;
+ num_rates++) {
+ struct test_config_table expected_table =
+ INIT_STANDARD_TABLE(test, num_rates,
+ max_lane_count);
+
+ update_link_caps_and_verify(&expected_table, link_caps, true);
+ }
+ }
+}
+
+/*
+ * TEST: Update shrink and expand
+ * ------------------------------
+ * Verify that removing or adding supported rates/lane counts updates
+ * the configuration table accordingly.
+ */
+static void disable_configs_and_verify(struct kunit *test,
+ struct intel_dp_link_caps *link_caps,
+ struct test_config_table *expected_table,
+ const struct link_config_set *config_set)
+{
+ struct test_ctx *ctx = test->priv;
+ const struct intel_dp_link_caps_test_ops *ops =
+ ctx->link_caps_ops;
+ int i;
+
+ for (i = 0; i < config_set->size; i++) {
+ KUNIT_ASSERT_FALSE(test, has_config(&expected_table->disabled_configs,
+ &config_set->entries[i]));
+ add_config(test, &expected_table->disabled_configs, &config_set->entries[i]);
+
+ KUNIT_ASSERT_TRUE(test, ops->disable_config(link_caps, &config_set->entries[i]));
+
+ verify_link_caps(expected_table, link_caps);
+ }
+}
+
+static void disable_configs_for_shrink_and_verify(struct test_config_table *expected_table,
+ struct intel_dp_link_caps *link_caps)
+{
+ struct kunit *test = expected_table->test;
+ struct link_config_set config_set = {};
+ struct intel_dp_link_config max_config;
+
+ /*
+ * When configs shrink disable the config with the
+ * second-highest rate, lane params, so the disabled config
+ * stays around after the configs got shrunk.
+ */
+ KUNIT_ASSERT_GE(test, expected_table->rates.size, 2);
+ KUNIT_ASSERT_GE(test, expected_table->max_lane_count, 2);
+
+ max_config.rate = expected_table->rates.entries[expected_table->rates.size - 2];
+ max_config.lane_count = expected_table->max_lane_count >> 1;
+
+ add_config(test, &config_set, &max_config);
+ disable_configs_and_verify(test, link_caps, expected_table,
+ &config_set);
+}
+
+static void disable_configs_for_expand_and_verify(struct test_config_table *expected_table,
+ struct intel_dp_link_caps *link_caps)
+{
+ struct kunit *test = expected_table->test;
+ struct link_config_set config_set = {};
+ struct intel_dp_link_config max_config;
+
+ KUNIT_ASSERT_GE(test, expected_table->rates.size, 1);
+
+ max_config.rate = expected_table->rates.entries[expected_table->rates.size - 1];
+ max_config.lane_count = expected_table->max_lane_count;
+
+ add_config(test, &config_set, &max_config);
+ disable_configs_and_verify(test, link_caps, expected_table,
+ &config_set);
+}
+
+static void get_nth_rate_lane_config(const struct test_config_table *expected_table, int n,
+ struct intel_dp_link_config *config)
+{
+ int num_lane_configs = LINK_TEST_NUM_LANE_CONFIGS(expected_table->max_lane_count);
+ int rate_idx = n / num_lane_configs;
+ int lane_count_exp = n % num_lane_configs;
+
+ config->rate = expected_table->rates.entries[rate_idx];
+ config->lane_count = 1 << lane_count_exp;
+}
+
+static void test_update_rates_shrink(struct kunit *test, bool disable_configs)
+{
+ struct test_ctx *ctx = test->priv;
+ struct intel_dp_link_caps *link_caps = ctx->dev.dig_port.dp.link.caps;
+ struct test_config_table expected_table =
+ INIT_STANDARD_TABLE(test, LINK_TEST_NUM_STANDARD_RATES,
+ LINK_TEST_MAX_LANE_COUNT);
+
+ update_link_caps_and_verify(&expected_table, link_caps, true);
+
+ while (expected_table.rates.size > 1) {
+ if (disable_configs)
+ disable_configs_for_shrink_and_verify(&expected_table, link_caps);
+
+ expected_table.rates.size--;
+
+ update_link_caps_and_verify(&expected_table, link_caps, false);
+ }
+}
+
+static void intel_dp_link_caps_test_update_rates_shrink(struct kunit *test)
+{
+ test_update_rates_shrink(test, false);
+}
+
+static void intel_dp_link_caps_test_update_rates_shrink_disable(struct kunit *test)
+{
+ test_update_rates_shrink(test, true);
+}
+
+static void test_update_rates_expand(struct kunit *test, bool disable_configs)
+{
+ struct test_ctx *ctx = test->priv;
+ struct intel_dp_link_caps *link_caps = ctx->dev.dig_port.dp.link.caps;
+ struct test_config_table expected_table =
+ INIT_STANDARD_TABLE(test, 1, LINK_TEST_MAX_LANE_COUNT);
+
+ update_link_caps_and_verify(&expected_table, link_caps, true);
+
+ while (expected_table.rates.size < LINK_TEST_NUM_STANDARD_RATES) {
+ if (disable_configs)
+ disable_configs_for_expand_and_verify(&expected_table, link_caps);
+
+ expected_table.rates.size++;
+
+ update_link_caps_and_verify(&expected_table, link_caps, false);
+ }
+}
+
+static void intel_dp_link_caps_test_update_rates_expand(struct kunit *test)
+{
+ test_update_rates_expand(test, false);
+}
+
+static void intel_dp_link_caps_test_update_rates_expand_disable(struct kunit *test)
+{
+ test_update_rates_expand(test, true);
+}
+
+static void test_update_lanes_shrink(struct kunit *test, bool disable_configs)
+{
+ struct test_ctx *ctx = test->priv;
+ struct intel_dp_link_caps *link_caps = ctx->dev.dig_port.dp.link.caps;
+ struct test_config_table expected_table =
+ INIT_STANDARD_TABLE(test, LINK_TEST_NUM_STANDARD_RATES,
+ LINK_TEST_MAX_LANE_COUNT);
+
+ update_link_caps_and_verify(&expected_table, link_caps, true);
+
+ while (expected_table.max_lane_count > 1) {
+ if (disable_configs)
+ disable_configs_for_shrink_and_verify(&expected_table, link_caps);
+
+ expected_table.max_lane_count >>= 1;
+
+ update_link_caps_and_verify(&expected_table, link_caps, false);
+ }
+}
+
+static void intel_dp_link_caps_test_update_lanes_shrink(struct kunit *test)
+{
+ test_update_lanes_shrink(test, false);
+}
+
+static void intel_dp_link_caps_test_update_lanes_shrink_disable(struct kunit *test)
+{
+ test_update_lanes_shrink(test, true);
+}
+
+static void test_update_lanes_expand(struct kunit *test, bool disable_configs)
+{
+ struct test_ctx *ctx = test->priv;
+ struct intel_dp_link_caps *link_caps = ctx->dev.dig_port.dp.link.caps;
+ struct test_config_table expected_table =
+ INIT_STANDARD_TABLE(test, LINK_TEST_NUM_STANDARD_RATES, 1);
+
+ update_link_caps_and_verify(&expected_table, link_caps, true);
+
+ while (expected_table.max_lane_count < LINK_TEST_MAX_LANE_COUNT) {
+ if (disable_configs)
+ disable_configs_for_expand_and_verify(&expected_table, link_caps);
+
+ expected_table.max_lane_count <<= 1;
+
+ update_link_caps_and_verify(&expected_table, link_caps, false);
+ }
+}
+
+static void intel_dp_link_caps_test_update_lanes_expand(struct kunit *test)
+{
+ test_update_lanes_expand(test, false);
+}
+
+static void intel_dp_link_caps_test_update_lanes_expand_disable(struct kunit *test)
+{
+ test_update_lanes_expand(test, true);
+}
+
+static void disable_random_configs_and_verify(struct test_config_table *expected_table,
+ struct intel_dp_link_caps *link_caps)
+{
+ struct kunit *test = expected_table->test;
+ struct test_ctx *ctx = test->priv;
+ struct link_config_set config_set = {};
+ u32 disabled_config_mask;
+ int num_configs;
+ int i;
+
+ num_configs = get_num_configs(expected_table->rates.size,
+ expected_table->max_lane_count);
+ disabled_config_mask = prandom_u32_state(&ctx->rnd) &
+ GENMASK_U32(num_configs - 1, 0);
+
+ for (i = 0; i < num_configs; i++) {
+ struct intel_dp_link_config config;
+
+ /* At least one config must remain enabled. */
+ if (expected_table->disabled_configs.size +
+ config_set.size + 1 >= num_configs)
+ break;
+
+ if (!(BIT(i) & disabled_config_mask))
+ continue;
+
+ get_nth_rate_lane_config(expected_table, i, &config);
+ /* Don't disable a config twice. */
+ if (has_config(&expected_table->disabled_configs, &config))
+ continue;
+
+ add_config(test, &config_set, &config);
+ }
+
+ disable_configs_and_verify(test, link_caps, expected_table,
+ &config_set);
+}
+
+static void get_params_shrink_step(struct test_ctx *ctx,
+ int num_rates, int max_lane_count,
+ int *rates_step, int *lanes_step)
+{
+ int shrink_mask;
+
+ *rates_step = 0;
+ *lanes_step = 0;
+
+ if (num_rates == 1)
+ shrink_mask = BIT(0); /* shrink only lanes */
+ else if (max_lane_count == 1)
+ shrink_mask = BIT(1); /* shrink only rates */
+ else
+ shrink_mask = rand_in_range(ctx,
+ BIT(0),
+ BIT(0) | BIT(1)); /* shrink one or both params */
+
+ if (shrink_mask & BIT(1))
+ *rates_step = rand_in_range(ctx, 1, num_rates - 1);
+
+ if (shrink_mask & BIT(0))
+ *lanes_step = rand_in_range(ctx, 1, ilog2(max_lane_count));
+}
+
+static void get_params_expand_step(struct test_ctx *ctx,
+ int max_num_rates, int num_rates,
+ int max_supported_lane_count, int max_lane_count,
+ int *rates_step, int *lanes_step)
+{
+ int expand_mask;
+
+ *rates_step = 0;
+ *lanes_step = 0;
+
+ if (num_rates == max_num_rates)
+ expand_mask = BIT(0); /* expand only lanes */
+ else if (max_lane_count == max_supported_lane_count)
+ expand_mask = BIT(1); /* expand only rates */
+ else
+ expand_mask = rand_in_range(ctx,
+ BIT(0),
+ BIT(0) | BIT(1)); /* expand one or both params */
+
+ if (expand_mask & BIT(1))
+ *rates_step = rand_in_range(ctx, 1, max_num_rates - num_rates);
+
+ if (expand_mask & BIT(0))
+ *lanes_step = rand_in_range(ctx, 1, ilog2(max_supported_lane_count /
+ max_lane_count));
+}
+
+static void test_update_params_shrink_random(struct kunit *test, bool disable_configs)
+{
+ struct test_ctx *ctx = test->priv;
+ struct intel_dp_link_caps *link_caps = ctx->dev.dig_port.dp.link.caps;
+ struct test_config_table expected_table =
+ INIT_STANDARD_TABLE(test, LINK_TEST_NUM_STANDARD_RATES,
+ LINK_TEST_MAX_LANE_COUNT);
+
+ update_link_caps_and_verify(&expected_table, link_caps, true);
+
+ while (expected_table.rates.size > 1 || expected_table.max_lane_count > 1) {
+ int rates_step;
+ int lanes_step;
+
+ if (disable_configs)
+ disable_random_configs_and_verify(&expected_table, link_caps);
+
+ get_params_shrink_step(ctx,
+ expected_table.rates.size,
+ expected_table.max_lane_count,
+ &rates_step, &lanes_step);
+
+ expected_table.rates.size -= rates_step;
+ expected_table.max_lane_count >>= lanes_step;
+
+ update_link_caps_and_verify(&expected_table, link_caps, false);
+ }
+}
+
+static void intel_dp_link_caps_test_update_params_shrink_random(struct kunit *test)
+{
+ int i;
+
+ for (i = 0; i < LINK_TEST_NUM_RANDOM_ITERATIONS; i++)
+ test_update_params_shrink_random(test, false);
+}
+
+static void intel_dp_link_caps_test_update_params_shrink_disable_random(struct kunit *test)
+{
+ int i;
+
+ for (i = 0; i < LINK_TEST_NUM_RANDOM_ITERATIONS; i++)
+ test_update_params_shrink_random(test, true);
+}
+
+static void test_update_params_expand_random(struct kunit *test, bool disable_configs)
+{
+ struct test_ctx *ctx = test->priv;
+ struct intel_dp_link_caps *link_caps = ctx->dev.dig_port.dp.link.caps;
+ struct test_config_table expected_table =
+ INIT_STANDARD_TABLE(test, 1, 1);
+
+ update_link_caps_and_verify(&expected_table, link_caps, true);
+
+ while (expected_table.rates.size < LINK_TEST_NUM_STANDARD_RATES ||
+ expected_table.max_lane_count < LINK_TEST_MAX_LANE_COUNT) {
+ int rates_step;
+ int lanes_step;
+
+ if (disable_configs)
+ disable_random_configs_and_verify(&expected_table, link_caps);
+
+ get_params_expand_step(ctx,
+ LINK_TEST_NUM_STANDARD_RATES,
+ expected_table.rates.size,
+ LINK_TEST_MAX_LANE_COUNT,
+ expected_table.max_lane_count,
+ &rates_step, &lanes_step);
+
+ expected_table.rates.size += rates_step;
+ expected_table.max_lane_count <<= lanes_step;
+
+ update_link_caps_and_verify(&expected_table, link_caps, false);
+ }
+}
+
+static void intel_dp_link_caps_test_update_params_expand_random(struct kunit *test)
+{
+ int i;
+
+ for (i = 0; i < LINK_TEST_NUM_RANDOM_ITERATIONS; i++)
+ test_update_params_expand_random(test, false);
+}
+
+static void intel_dp_link_caps_test_update_params_expand_disable_random(struct kunit *test)
+{
+ int i;
+
+ for (i = 0; i < LINK_TEST_NUM_RANDOM_ITERATIONS; i++)
+ test_update_params_expand_random(test, true);
+}
+
+/*
+ * TEST: Fallback sequence
+ * -----------------------
+ * Verify the eDP fallback logic to set the maximum supported configuration
+ * as a preference.
+ *
+ * For DP SST and MST verify fallback selection from the connector's
+ * maximum configuration and iteration of the resulting allowed
+ * configurations.
+ */
+static void intel_dp_link_test_fallback_for_edp(struct kunit *test)
+{
+ struct test_ctx *ctx = test->priv;
+ struct intel_dp_link_caps *link_caps = ctx->dev.dig_port.dp.link.caps;
+ struct test_config_table expected_table =
+ INIT_STANDARD_TABLE(test, LINK_TEST_NUM_STANDARD_RATES,
+ LINK_TEST_MAX_LANE_COUNT);
+ struct intel_digital_port *dig_port = &ctx->dev.dig_port;
+ const struct intel_dp_link_training_test_ops *lt_ops =
+ ctx->link_training_ops;
+ const struct intel_dp_link_caps_test_ops *lc_ops =
+ ctx->link_caps_ops;
+ struct intel_dp_link_config min_config = {
+ .rate = expected_table.rates.entries[0],
+ .lane_count = 1,
+ };
+ struct intel_dp_link_config max_config = {
+ .rate = expected_table.rates.entries[expected_table.rates.size - 1],
+ .lane_count = LINK_TEST_MAX_LANE_COUNT,
+ };
+ struct intel_dp_link_caps_order order;
+ struct intel_dp_link_config iter_config;
+ struct intel_dp_link_caps_iter iter;
+ int fallback_err;
+
+ dig_port->base.type = INTEL_OUTPUT_EDP;
+ ctx->dev.dig_port.dp.use_max_params = false;
+
+ update_link_caps_and_verify(&expected_table, link_caps, true);
+
+ order = lc_ops->connector_compute_order(&ctx->dev.connector);
+
+ lc_ops->iter_start(&iter, link_caps, order, INTEL_DP_LINK_CAPS_FILTER_ALL);
+ for_each_dp_link_config(&iter, &iter_config)
+ break;
+ lc_ops->iter_end(&iter);
+
+ KUNIT_EXPECT_FALSE(test, ctx->dev.dig_port.dp.use_max_params);
+ KUNIT_EXPECT_TRUE(test, link_configs_match(&iter_config, &min_config));
+
+ ctx->dev.crtc_state.output_types = BIT(dig_port->base.type);
+ ctx->dev.crtc_state.port_clock = min_config.rate;
+ ctx->dev.crtc_state.lane_count = min_config.lane_count;
+
+ fallback_err = lt_ops->get_fallback_values(&ctx->dev.dig_port.dp, &ctx->dev.crtc_state);
+ KUNIT_EXPECT_EQ(test, fallback_err, 0);
+
+ /* The fallback should've changed the order. */
+ order = lc_ops->connector_compute_order(&ctx->dev.connector);
+
+ lc_ops->iter_start(&iter, link_caps, order, INTEL_DP_LINK_CAPS_FILTER_ALL);
+ for_each_dp_link_config(&iter, &iter_config)
+ break;
+ lc_ops->iter_end(&iter);
+
+ KUNIT_EXPECT_TRUE(test, ctx->dev.dig_port.dp.use_max_params);
+ KUNIT_EXPECT_TRUE(test, link_configs_match(&iter_config, &max_config));
+}
+
+static bool test_fallback_from_target(struct test_config_table *expected_table,
+ enum intel_output_type output_type, int max_rate,
+ const struct intel_dp_link_config *expected_target_config,
+ const struct intel_dp_link_config *expected_fallback_config)
+{
+ struct kunit *test = expected_table->test;
+ struct test_ctx *ctx = test->priv;
+ struct intel_dp_link_caps *link_caps = ctx->dev.dig_port.dp.link.caps;
+ struct intel_dp_link_config iter_config;
+ const struct intel_dp_link_training_test_ops *lt_ops =
+ ctx->link_training_ops;
+ const struct intel_dp_link_caps_test_ops *lc_ops =
+ ctx->link_caps_ops;
+ /* Modify default order direction for max config lookup. */
+ struct intel_dp_link_caps_order fallback_order =
+ lc_ops->connector_fallback_order(ctx->dev.connector.mst.dp);
+ struct intel_dp_link_caps_iter iter;
+ int expected_fallback_err = 0;
+ int fallback_err;
+
+ /* Get the max connector config, optionally filtered to the max_rate limit. */
+ lc_ops->iter_start(&iter, link_caps, fallback_order, INTEL_DP_LINK_CAPS_FILTER_ALL);
+ for_each_dp_link_config(&iter, &iter_config)
+ if (max_rate == 0 || iter_config.rate <= max_rate)
+ break;
+ lc_ops->iter_end(&iter);
+
+ KUNIT_EXPECT_TRUE(test, link_configs_match(&iter_config,
+ expected_target_config));
+ KUNIT_EXPECT_FALSE(test, link_configs_match(&iter_config,
+ &INTEL_DP_LINK_CONFIG_NULL));
+
+ ctx->dev.crtc_state.output_types = BIT(output_type);
+ ctx->dev.crtc_state.port_clock = expected_target_config->rate;
+ ctx->dev.crtc_state.lane_count = expected_target_config->lane_count;
+
+ if (link_configs_match(expected_fallback_config, &INTEL_DP_LINK_CONFIG_NULL))
+ expected_fallback_err = -1;
+
+ fallback_err = lt_ops->get_fallback_values(&ctx->dev.dig_port.dp, &ctx->dev.crtc_state);
+ KUNIT_EXPECT_EQ(test, fallback_err, expected_fallback_err);
+
+ if (!fallback_err) {
+ /*
+ * NOTE: This test does not verify any implied fallback
+ * target selection.
+ *
+ * The current driver behavior may still select a fallback
+ * configuration indirectly via max_limits, but that is an
+ * implementation artifact rather than part of the intended
+ * fallback API behavior, and is therefore not verified here.
+ *
+ * Instead, the effect of the fallback logic is verified by
+ * checking that the failed target configuration is disabled.
+ * Selecting the next target configuration from the remaining
+ * allowed configurations belongs to the modeset link target
+ * selection logic.
+ */
+ add_config(test, &expected_table->disabled_configs,
+ expected_target_config);
+ }
+
+ verify_link_caps(expected_table, link_caps);
+
+ return !fallback_err;
+}
+
+static const struct link_config_set *
+get_target_configs_for_output_type(struct kunit *test,
+ enum intel_output_type output_type)
+{
+ switch (output_type) {
+ case INTEL_OUTPUT_DDI:
+ case INTEL_OUTPUT_DP:
+ case INTEL_OUTPUT_EDP:
+ return &standard_dp_link_configs[INTEL_DP_LINK_CAPS_ORDER_KEY_RATE_LANE];
+ case INTEL_OUTPUT_DP_MST:
+ return &standard_dp_link_configs[INTEL_DP_LINK_CAPS_ORDER_KEY_BW];
+ default:
+ KUNIT_FAIL_AND_ABORT(test, "Missing output type: %d", output_type);
+ }
+}
+
+static const struct link_config_set *
+get_fallback_configs_for_output_type(struct kunit *test,
+ enum intel_output_type output_type)
+{
+ switch (output_type) {
+ case INTEL_OUTPUT_DDI:
+ case INTEL_OUTPUT_DP:
+ case INTEL_OUTPUT_EDP:
+ return &standard_dp_link_configs[INTEL_DP_LINK_CAPS_ORDER_KEY_LANE_RATE];
+ case INTEL_OUTPUT_DP_MST:
+ return &standard_dp_link_configs[INTEL_DP_LINK_CAPS_ORDER_KEY_BW];
+ default:
+ KUNIT_FAIL_AND_ABORT(test, "Missing output type: %d", output_type);
+ }
+}
+
+static bool output_type_allows_uhbr_fallback(enum intel_output_type output_type)
+{
+ return output_type == INTEL_OUTPUT_DP_MST;
+}
+
+static void assert_config_is_supported(const struct test_config_table *expected_table,
+ const struct intel_dp_link_config *config)
+{
+ struct kunit *test = expected_table->test;
+
+ KUNIT_ASSERT_TRUE(test, has_rate(&expected_table->rates, config->rate));
+ KUNIT_ASSERT_LE(test, config->lane_count, expected_table->max_lane_count);
+}
+
+static bool get_fallback_config(const struct test_config_table *expected_table,
+ enum intel_output_type output_type,
+ const struct intel_dp_link_config *target_config,
+ struct intel_dp_link_config *fallback_config)
+{
+ struct kunit *test = expected_table->test;
+ const struct link_config_set *config_set =
+ get_fallback_configs_for_output_type(test, output_type);
+ int i;
+
+ i = lookup_config(config_set, target_config);
+ KUNIT_ASSERT_GE(test, i, 0);
+
+ for (i--; i >= 0; i--) {
+ const struct intel_dp_link_config *config =
+ &config_set->entries[i];
+
+ if (output_type_allows_uhbr_fallback(output_type) ||
+ (drm_dp_is_uhbr_rate(target_config->rate) ==
+ drm_dp_is_uhbr_rate(config->rate))) {
+ assert_config_is_supported(expected_table, config);
+ *fallback_config = *config;
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool get_target_config(const struct test_config_table *expected_table,
+ enum intel_output_type output_type,
+ int max_rate,
+ struct intel_dp_link_config *target)
+{
+ struct kunit *test = expected_table->test;
+ const struct link_config_set *config_set =
+ get_target_configs_for_output_type(test, output_type);
+ int i;
+
+ for (i = config_set->size - 1; i >= 0; i--) {
+ const struct intel_dp_link_config *config =
+ &config_set->entries[i];
+
+ if (config->rate <= max_rate) {
+ assert_config_is_supported(expected_table, config);
+ *target = *config;
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void test_fallback_seq(struct kunit *test,
+ enum intel_output_type output_type,
+ bool uhbr)
+{
+ struct test_ctx *ctx = test->priv;
+ struct intel_dp_link_caps *link_caps = ctx->dev.dig_port.dp.link.caps;
+ struct test_config_table expected_table =
+ INIT_STANDARD_TABLE(test, LINK_TEST_NUM_STANDARD_RATES,
+ LINK_TEST_MAX_LANE_COUNT);
+ struct intel_digital_port *dig_port = &ctx->dev.dig_port;
+ struct intel_dp_link_config fallback_config = {};
+ struct intel_dp_link_config target_config;
+ int fallback_count = 0;
+ bool target_found;
+ int max_rate;
+
+ if (uhbr)
+ max_rate = expected_table.rates.entries[expected_table.rates.size - 1];
+ else
+ max_rate = 810000;
+
+ dig_port->base.type = output_type;
+ ctx->dev.dig_port.dp.use_max_params = false;
+
+ update_link_caps_and_verify(&expected_table, link_caps, true);
+
+ /* Get the initial target config. */
+ target_found = get_target_config(&expected_table, output_type,
+ max_rate, &target_config);
+ KUNIT_ASSERT_TRUE(test, target_found);
+
+ for (;;) {
+ /* Also test the case where no fallback is available. */
+ if (!get_fallback_config(&expected_table, output_type,
+ &target_config, &fallback_config))
+ fallback_config = INTEL_DP_LINK_CONFIG_NULL;
+
+ if (!test_fallback_from_target(&expected_table, output_type, max_rate,
+ &target_config, &fallback_config))
+ break;
+
+ /*
+ * The fallback changed the max rate allowed for the next
+ * target.
+ */
+ max_rate = fallback_config.rate;
+
+ /* Simply select the fallback config as the next target. */
+ target_config = fallback_config;
+
+ fallback_count++;
+ KUNIT_ASSERT_LT(test, fallback_count, LINK_TEST_MAX_CONFIGS);
+ }
+}
+
+static void intel_dp_link_test_fallback_for_sst_max_non_uhbr(struct kunit *test)
+{
+ test_fallback_seq(test, INTEL_OUTPUT_DP, false);
+}
+
+static void intel_dp_link_test_fallback_for_sst_max_uhbr(struct kunit *test)
+{
+ test_fallback_seq(test, INTEL_OUTPUT_DP, true);
+}
+
+static void intel_dp_link_test_fallback_for_mst(struct kunit *test)
+{
+ struct test_ctx *ctx = test->priv;
+
+ ctx->dev.connector.mst.dp = &ctx->dev.dig_port.dp;
+
+ test_fallback_seq(test, INTEL_OUTPUT_DP_MST, true);
+}
+
+static struct kunit_case intel_dp_link_test_cases[] = {
+ KUNIT_CASE(intel_dp_link_caps_test_baseline),
+
+ KUNIT_CASE(intel_dp_link_caps_test_update_reset),
+
+ KUNIT_CASE(intel_dp_link_caps_test_update_rates_shrink),
+ KUNIT_CASE(intel_dp_link_caps_test_update_rates_shrink_disable),
+ KUNIT_CASE(intel_dp_link_caps_test_update_rates_expand),
+ KUNIT_CASE(intel_dp_link_caps_test_update_rates_expand_disable),
+ KUNIT_CASE(intel_dp_link_caps_test_update_lanes_shrink),
+ KUNIT_CASE(intel_dp_link_caps_test_update_lanes_shrink_disable),
+ KUNIT_CASE(intel_dp_link_caps_test_update_lanes_expand),
+ KUNIT_CASE(intel_dp_link_caps_test_update_lanes_expand_disable),
+ KUNIT_CASE(intel_dp_link_caps_test_update_params_shrink_random),
+ KUNIT_CASE(intel_dp_link_caps_test_update_params_shrink_disable_random),
+ KUNIT_CASE(intel_dp_link_caps_test_update_params_expand_random),
+ KUNIT_CASE(intel_dp_link_caps_test_update_params_expand_disable_random),
+
+ KUNIT_CASE(intel_dp_link_test_fallback_for_edp),
+ KUNIT_CASE(intel_dp_link_test_fallback_for_sst_max_non_uhbr),
+ KUNIT_CASE(intel_dp_link_test_fallback_for_sst_max_uhbr),
+ KUNIT_CASE(intel_dp_link_test_fallback_for_mst),
+
+ {}
+};
+
+static struct test_ctx test_ctx;
+
+static int intel_dp_link_test_init(struct kunit *test)
+{
+ struct intel_digital_port *dig_port;
+ struct intel_encoder *encoder;
+ struct intel_dp *intel_dp;
+
+ /* Reset the dev state for each test. */
+ memset(&test_ctx.dev, 0, sizeof(test_ctx.dev));
+
+ test_ctx.dev.generic_device.drm.dev = &test_ctx.dev.device;
+
+ test_ctx.dev.display.drm = &test_ctx.dev.generic_device.drm;
+ test_ctx.dev.generic_device.display = &test_ctx.dev.display;
+
+ encoder = &test_ctx.dev.dig_port.base;
+ encoder->base.dev = &test_ctx.dev.generic_device.drm;
+
+ dig_port = &test_ctx.dev.dig_port;
+ dig_port->base.type = INTEL_OUTPUT_DP;
+
+ test_ctx.dev.connector.encoder = encoder;
+
+ intel_dp = &dig_port->dp;
+ intel_dp->attached_connector = &test_ctx.dev.connector;
+
+ intel_dp->link.caps = test_ctx.link_caps_ops->init(intel_dp);
+
+ test->priv = &test_ctx;
+
+ return 0;
+}
+
+static void intel_dp_link_test_exit(struct kunit *test)
+{
+ struct test_ctx *ctx = test->priv;
+
+ ctx->link_caps_ops->cleanup(ctx->dev.dig_port.dp.link.caps);
+}
+
+static int intel_dp_link_test_suite_init(struct kunit_suite *test_suite)
+{
+#ifdef I915
+ test_ctx.link_caps_ops = &i915_display_dp_link_caps_test_ops;
+ test_ctx.link_training_ops = &i915_display_dp_link_training_test_ops;
+#else
+ test_ctx.link_caps_ops = &intel_display_dp_link_caps_test_ops;
+ test_ctx.link_training_ops = &intel_display_dp_link_training_test_ops;
+#endif
+ prandom_seed_state(&test_ctx.rnd, 0);
+
+ return 0;
+}
+
+static struct kunit_suite intel_dp_link_test_suite = {
+ .name = "intel_dp_link",
+ .suite_init = intel_dp_link_test_suite_init,
+ .init = intel_dp_link_test_init,
+ .exit = intel_dp_link_test_exit,
+ .test_cases = intel_dp_link_test_cases,
+};
+
+kunit_test_suites(&intel_dp_link_test_suite);
+
+MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_LICENSE("GPL and additional rights");
+MODULE_DESCRIPTION("Intel DP link KUnit tests");
diff --git a/drivers/gpu/drm/imagination/pvr_context.c b/drivers/gpu/drm/imagination/pvr_context.c
index 52e16c1e7af0..406e0758e860 100644
--- a/drivers/gpu/drm/imagination/pvr_context.c
+++ b/drivers/gpu/drm/imagination/pvr_context.c
@@ -309,8 +309,8 @@ int pvr_context_create(struct pvr_file *pvr_file, struct drm_pvr_ioctl_create_co
goto err_free_ctx;
ctx->vm_ctx = pvr_vm_context_lookup(pvr_file, args->vm_context_handle);
- if (IS_ERR(ctx->vm_ctx)) {
- err = PTR_ERR(ctx->vm_ctx);
+ if (!ctx->vm_ctx) {
+ err = -EINVAL;
goto err_free_ctx;
}
diff --git a/drivers/gpu/drm/imagination/pvr_fw_trace.c b/drivers/gpu/drm/imagination/pvr_fw_trace.c
index 6bb5baa6c41b..805d9f9bc1dd 100644
--- a/drivers/gpu/drm/imagination/pvr_fw_trace.c
+++ b/drivers/gpu/drm/imagination/pvr_fw_trace.c
@@ -71,7 +71,7 @@ pvr_fw_trace_init_mask_set(const char *val, const struct kernel_param *kp)
return 0;
}
-const struct kernel_param_ops pvr_fw_trace_init_mask_ops = {
+static const struct kernel_param_ops pvr_fw_trace_init_mask_ops = {
.set = pvr_fw_trace_init_mask_set,
.get = param_get_hexint,
};
diff --git a/drivers/gpu/drm/panel/panel-anbernic-td4310.c b/drivers/gpu/drm/panel/panel-anbernic-td4310.c
index 9a1b4525423c..3b6de1b2fbc6 100644
--- a/drivers/gpu/drm/panel/panel-anbernic-td4310.c
+++ b/drivers/gpu/drm/panel/panel-anbernic-td4310.c
@@ -12,6 +12,7 @@
#include <linux/regulator/consumer.h>
#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <drm/drm_probe_helper.h>
@@ -165,7 +166,7 @@ static int panel_anbernic_td4310_probe(struct mipi_dsi_device *dsi)
if (!ctx->panel_info)
return -EINVAL;
- ret = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation);
+ ret = drm_of_get_panel_orientation(dev->of_node, &ctx->orientation);
if (ret < 0)
return dev_err_probe(dev, ret, "Failed to get panel orientation\n");
diff --git a/drivers/gpu/drm/panel/panel-boe-th101mb31ig002-28a.c b/drivers/gpu/drm/panel/panel-boe-th101mb31ig002-28a.c
index 01b4458e55ad..a70a2e58f88c 100644
--- a/drivers/gpu/drm/panel/panel-boe-th101mb31ig002-28a.c
+++ b/drivers/gpu/drm/panel/panel-boe-th101mb31ig002-28a.c
@@ -15,6 +15,7 @@
#include <drm/drm_connector.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
+#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <drm/drm_probe_helper.h>
@@ -380,7 +381,7 @@ static int boe_th101mb31ig002_dsi_probe(struct mipi_dsi_device *dsi)
return dev_err_probe(&dsi->dev, PTR_ERR(ctx->reset),
"Failed to get reset GPIO\n");
- ret = of_drm_get_panel_orientation(dsi->dev.of_node,
+ ret = drm_of_get_panel_orientation(dsi->dev.of_node,
&ctx->orientation);
if (ret)
return dev_err_probe(&dsi->dev, ret,
diff --git a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c
index 658ce64c71eb..150dff3ab6c3 100644
--- a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c
+++ b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c
@@ -13,6 +13,7 @@
#include <drm/drm_connector.h>
#include <drm/drm_crtc.h>
#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <video/mipi_display.h>
@@ -1722,7 +1723,7 @@ static int boe_panel_add(struct boe_panel *boe)
boe->base.prepare_prev_first = true;
- err = of_drm_get_panel_orientation(dev->of_node, &boe->orientation);
+ err = drm_of_get_panel_orientation(dev->of_node, &boe->orientation);
if (err < 0) {
dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, err);
return err;
diff --git a/drivers/gpu/drm/panel/panel-chipone-icna35xx.c b/drivers/gpu/drm/panel/panel-chipone-icna35xx.c
index 86d096455caa..2cc16494a4ce 100644
--- a/drivers/gpu/drm/panel/panel-chipone-icna35xx.c
+++ b/drivers/gpu/drm/panel/panel-chipone-icna35xx.c
@@ -21,6 +21,7 @@
#include <drm/drm_crtc.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
+#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <drm/drm_probe_helper.h>
@@ -374,7 +375,7 @@ static int icna35xx_probe(struct mipi_dsi_device *dsi)
pinfo->dsi = dsi;
mipi_dsi_set_drvdata(dsi, pinfo);
- ret = of_drm_get_panel_orientation(dev->of_node, &pinfo->orientation);
+ ret = drm_of_get_panel_orientation(dev->of_node, &pinfo->orientation);
if (ret < 0) {
dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, ret);
return ret;
diff --git a/drivers/gpu/drm/panel/panel-chipwealth-ch13726a.c b/drivers/gpu/drm/panel/panel-chipwealth-ch13726a.c
index be76bc825c3f..562dc573528d 100644
--- a/drivers/gpu/drm/panel/panel-chipwealth-ch13726a.c
+++ b/drivers/gpu/drm/panel/panel-chipwealth-ch13726a.c
@@ -13,6 +13,7 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
+#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <video/mipi_display.h>
@@ -268,7 +269,7 @@ static int ch13726a_probe(struct mipi_dsi_device *dsi)
return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
"Failed to get reset-gpios\n");
- ret = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation);
+ ret = drm_of_get_panel_orientation(dev->of_node, &ctx->orientation);
if (ret < 0) {
dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, ret);
return ret;
diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c
index bd7acc31b292..f66474d3ef65 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -40,6 +40,7 @@
#include <drm/drm_crtc.h>
#include <drm/drm_device.h>
#include <drm/drm_edid.h>
+#include <drm/drm_of.h>
#include <drm/drm_panel.h>
/**
@@ -865,7 +866,7 @@ static int panel_edp_probe(struct device *dev, const struct panel_desc *desc,
return dev_err_probe(dev, PTR_ERR(panel->enable_gpio),
"failed to request GPIO\n");
- err = of_drm_get_panel_orientation(dev->of_node, &panel->orientation);
+ err = drm_of_get_panel_orientation(dev->of_node, &panel->orientation);
if (err) {
dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, err);
return err;
diff --git a/drivers/gpu/drm/panel/panel-elida-kd35t133.c b/drivers/gpu/drm/panel/panel-elida-kd35t133.c
index 1f177834d629..d23002b5a2d7 100644
--- a/drivers/gpu/drm/panel/panel-elida-kd35t133.c
+++ b/drivers/gpu/drm/panel/panel-elida-kd35t133.c
@@ -21,6 +21,7 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
+#include <drm/drm_of.h>
#include <drm/drm_panel.h>
/* Manufacturer specific Commands send via DSI */
@@ -233,7 +234,7 @@ static int kd35t133_probe(struct mipi_dsi_device *dsi)
return ret;
}
- ret = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation);
+ ret = drm_of_get_panel_orientation(dev->of_node, &ctx->orientation);
if (ret < 0) {
dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, ret);
return ret;
diff --git a/drivers/gpu/drm/panel/panel-focaltech-ota7290b.c b/drivers/gpu/drm/panel/panel-focaltech-ota7290b.c
index ed02a8daf96f..bbc870b8fda8 100644
--- a/drivers/gpu/drm/panel/panel-focaltech-ota7290b.c
+++ b/drivers/gpu/drm/panel/panel-focaltech-ota7290b.c
@@ -17,6 +17,7 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
+#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <drm/drm_probe_helper.h>
@@ -181,7 +182,7 @@ static int ota7290b_probe(struct mipi_dsi_device *dsi)
return dev_err_probe(&dsi->dev, PTR_ERR(ctx->vdd),
"Couldn't get our VDD supply\n");
- ret = of_drm_get_panel_orientation(dsi->dev.of_node, &ctx->orientation);
+ ret = drm_of_get_panel_orientation(dsi->dev.of_node, &ctx->orientation);
if (ret) {
dev_err(&dsi->dev, "%pOF: failed to get orientation: %d\n",
dsi->dev.of_node, ret);
diff --git a/drivers/gpu/drm/panel/panel-himax-hx83102.c b/drivers/gpu/drm/panel/panel-himax-hx83102.c
index d7e5664a5838..6a0851ccf9bb 100644
--- a/drivers/gpu/drm/panel/panel-himax-hx83102.c
+++ b/drivers/gpu/drm/panel/panel-himax-hx83102.c
@@ -17,6 +17,7 @@
#include <drm/drm_connector.h>
#include <drm/drm_crtc.h>
#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <video/mipi_display.h>
@@ -1264,7 +1265,7 @@ static int hx83102_panel_add(struct hx83102 *ctx)
ctx->base.prepare_prev_first = true;
- err = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation);
+ err = drm_of_get_panel_orientation(dev->of_node, &ctx->orientation);
if (err < 0)
return dev_err_probe(dev, err, "failed to get orientation\n");
diff --git a/drivers/gpu/drm/panel/panel-himax-hx8394.c b/drivers/gpu/drm/panel/panel-himax-hx8394.c
index 416203da2f45..09124610fdc8 100644
--- a/drivers/gpu/drm/panel/panel-himax-hx8394.c
+++ b/drivers/gpu/drm/panel/panel-himax-hx8394.c
@@ -21,6 +21,7 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
+#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#define DRV_NAME "panel-himax-hx8394"
@@ -991,7 +992,7 @@ static int hx8394_probe(struct mipi_dsi_device *dsi)
return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
"Failed to get reset gpio\n");
- ret = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation);
+ ret = drm_of_get_panel_orientation(dev->of_node, &ctx->orientation);
if (ret < 0) {
dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, ret);
return ret;
diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9488.c b/drivers/gpu/drm/panel/panel-ilitek-ili9488.c
index 7302766034fc..6ab8ae72abbf 100644
--- a/drivers/gpu/drm/panel/panel-ilitek-ili9488.c
+++ b/drivers/gpu/drm/panel/panel-ilitek-ili9488.c
@@ -13,6 +13,7 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
+#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <drm/drm_probe_helper.h>
@@ -237,7 +238,7 @@ static int ili9488_dsi_probe(struct mipi_dsi_device *dsi)
if (ret < 0)
return dev_err_probe(dev, ret, "failed to get regulators\n");
- ret = of_drm_get_panel_orientation(dev->of_node, &ili->orientation);
+ ret = drm_of_get_panel_orientation(dev->of_node, &ili->orientation);
if (ret)
return dev_err_probe(dev, ret, "failed to get orientation\n");
diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9806e-dsi.c b/drivers/gpu/drm/panel/panel-ilitek-ili9806e-dsi.c
index ad33414719fc..0fb06c425545 100644
--- a/drivers/gpu/drm/panel/panel-ilitek-ili9806e-dsi.c
+++ b/drivers/gpu/drm/panel/panel-ilitek-ili9806e-dsi.c
@@ -9,6 +9,7 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
+#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <drm/drm_probe_helper.h>
@@ -131,7 +132,7 @@ static int ili9806e_dsi_probe(struct mipi_dsi_device *dsi)
dsi->format = ctx->desc->format;
dsi->lanes = ctx->desc->lanes;
- ret = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation);
+ ret = drm_of_get_panel_orientation(dev->of_node, &ctx->orientation);
if (ret)
return dev_err_probe(dev, ret, "Failed to get orientation\n");
diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c
index 0652cdb57d11..3abdd0870e83 100644
--- a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c
+++ b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c
@@ -16,6 +16,7 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
+#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <video/mipi_display.h>
@@ -2571,7 +2572,7 @@ static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi)
return dev_err_probe(&dsi->dev, PTR_ERR(ctx->reset),
"Couldn't get our reset GPIO\n");
- ret = of_drm_get_panel_orientation(dsi->dev.of_node, &ctx->orientation);
+ ret = drm_of_get_panel_orientation(dsi->dev.of_node, &ctx->orientation);
if (ret) {
dev_err(&dsi->dev, "%pOF: failed to get orientation: %d\n",
dsi->dev.of_node, ret);
diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9882t.c b/drivers/gpu/drm/panel/panel-ilitek-ili9882t.c
index 5f4e0d82ee67..6d07fe901357 100644
--- a/drivers/gpu/drm/panel/panel-ilitek-ili9882t.c
+++ b/drivers/gpu/drm/panel/panel-ilitek-ili9882t.c
@@ -13,6 +13,7 @@
#include <drm/drm_connector.h>
#include <drm/drm_crtc.h>
#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <video/mipi_display.h>
@@ -795,7 +796,7 @@ static int ili9882t_add(struct ili9882t *ili)
gpiod_set_value_cansleep(ili->enable_gpio, 0);
- err = of_drm_get_panel_orientation(dev->of_node, &ili->orientation);
+ err = drm_of_get_panel_orientation(dev->of_node, &ili->orientation);
if (err < 0) {
dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, err);
return err;
diff --git a/drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c b/drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c
index f6b04de1182e..67ef9e0fea03 100644
--- a/drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c
+++ b/drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c
@@ -2992,7 +2992,7 @@ static int jadard_dsi_probe(struct mipi_dsi_device *dsi)
return dev_err_probe(&dsi->dev, PTR_ERR(jadard->vccio),
"failed to get vccio regulator\n");
- ret = of_drm_get_panel_orientation(dev->of_node, &jadard->orientation);
+ ret = drm_of_get_panel_orientation(dev->of_node, &jadard->orientation);
if (ret < 0)
return dev_err_probe(dev, ret, "failed to get orientation\n");
diff --git a/drivers/gpu/drm/panel/panel-lvds.c b/drivers/gpu/drm/panel/panel-lvds.c
index 46b07f38559f..37f7498449ec 100644
--- a/drivers/gpu/drm/panel/panel-lvds.c
+++ b/drivers/gpu/drm/panel/panel-lvds.c
@@ -126,7 +126,7 @@ static int panel_lvds_parse_dt(struct panel_lvds *lvds)
struct device_node *np = lvds->dev->of_node;
int ret;
- ret = of_drm_get_panel_orientation(np, &lvds->orientation);
+ ret = drm_of_get_panel_orientation(np, &lvds->orientation);
if (ret < 0) {
dev_err(lvds->dev, "%pOF: failed to get orientation %d\n", np, ret);
return ret;
diff --git a/drivers/gpu/drm/panel/panel-novatek-nt36523.c b/drivers/gpu/drm/panel/panel-novatek-nt36523.c
index 226d91daf8c7..34b9123d3fd7 100644
--- a/drivers/gpu/drm/panel/panel-novatek-nt36523.c
+++ b/drivers/gpu/drm/panel/panel-novatek-nt36523.c
@@ -19,6 +19,7 @@
#include <drm/drm_crtc.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
+#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#define DSI_NUM_MIN 1
@@ -1206,7 +1207,7 @@ static int nt36523_probe(struct mipi_dsi_device *dsi)
pinfo->dsi[0] = dsi;
mipi_dsi_set_drvdata(dsi, pinfo);
- ret = of_drm_get_panel_orientation(dev->of_node, &pinfo->orientation);
+ ret = drm_of_get_panel_orientation(dev->of_node, &pinfo->orientation);
if (ret < 0) {
dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, ret);
return ret;
diff --git a/drivers/gpu/drm/panel/panel-renesas-r63419.c b/drivers/gpu/drm/panel/panel-renesas-r63419.c
index 59ac323f5276..ff3846d574e5 100644
--- a/drivers/gpu/drm/panel/panel-renesas-r63419.c
+++ b/drivers/gpu/drm/panel/panel-renesas-r63419.c
@@ -20,6 +20,7 @@
#include <drm/drm_connector.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
+#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <drm/drm_probe_helper.h>
@@ -292,7 +293,7 @@ static int renesas_r63419_probe(struct mipi_dsi_device *dsi)
mipi_dsi_set_drvdata(dsi, ctx);
/* Get panel orientation */
- ret = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation);
+ ret = drm_of_get_panel_orientation(dev->of_node, &ctx->orientation);
if (ret < 0 && ret != -ENODEV)
return dev_err_probe(dev, ret,
"Failed to get panel orientation\n");
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index c09bf3db5e78..5c169fdf265c 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -693,7 +693,7 @@ static struct panel_simple *panel_simple_probe(struct device *dev)
return dev_err_cast_probe(dev, panel->enable_gpio,
"failed to request GPIO\n");
- err = of_drm_get_panel_orientation(dev->of_node, &panel->orientation);
+ err = drm_of_get_panel_orientation(dev->of_node, &panel->orientation);
if (err) {
dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, err);
return ERR_PTR(err);
diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7701.c b/drivers/gpu/drm/panel/panel-sitronix-st7701.c
index 2f79ec4a2063..f16e0de1ea60 100644
--- a/drivers/gpu/drm/panel/panel-sitronix-st7701.c
+++ b/drivers/gpu/drm/panel/panel-sitronix-st7701.c
@@ -7,6 +7,7 @@
#include <drm/drm_mipi_dbi.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
+#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <linux/bitfield.h>
@@ -1296,7 +1297,7 @@ static int st7701_probe(struct device *dev, int connector_type)
return PTR_ERR(st7701->reset);
}
- ret = of_drm_get_panel_orientation(dev->of_node, &st7701->orientation);
+ ret = drm_of_get_panel_orientation(dev->of_node, &st7701->orientation);
if (ret < 0)
return dev_err_probe(dev, ret, "Failed to get orientation\n");
diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7703.c b/drivers/gpu/drm/panel/panel-sitronix-st7703.c
index f1641c9c7d13..fcbb0b7d50e4 100644
--- a/drivers/gpu/drm/panel/panel-sitronix-st7703.c
+++ b/drivers/gpu/drm/panel/panel-sitronix-st7703.c
@@ -20,6 +20,7 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
+#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#define DRV_NAME "panel-sitronix-st7703"
@@ -873,7 +874,7 @@ static int st7703_probe(struct mipi_dsi_device *dsi)
return dev_err_probe(dev, PTR_ERR(ctx->iovcc),
"Failed to request iovcc regulator\n");
- ret = of_drm_get_panel_orientation(dsi->dev.of_node, &ctx->orientation);
+ ret = drm_of_get_panel_orientation(dsi->dev.of_node, &ctx->orientation);
if (ret < 0)
return dev_err_probe(&dsi->dev, ret, "Failed to get orientation\n");
diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
index d5f821d6b23c..da6ed31d151e 100644
--- a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
+++ b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c
@@ -14,6 +14,7 @@
#include <drm/drm_device.h>
#include <drm/drm_modes.h>
+#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#define ST7789V_RAMCTRL_CMD 0xb0
@@ -646,7 +647,7 @@ static int st7789v_probe(struct spi_device *spi)
if (ret)
return dev_err_probe(dev, ret, "Failed to get backlight\n");
- ret = of_drm_get_panel_orientation(spi->dev.of_node, &ctx->orientation);
+ ret = drm_of_get_panel_orientation(spi->dev.of_node, &ctx->orientation);
if (ret)
return dev_err_probe(&spi->dev, ret, "Failed to get orientation\n");
diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c
index 298b046c95ed..5832dccfc093 100644
--- a/drivers/gpu/drm/panthor/panthor_sched.c
+++ b/drivers/gpu/drm/panthor/panthor_sched.c
@@ -3446,7 +3446,6 @@ queue_timedout_job(struct drm_sched_job *sched_job)
static void queue_free_job(struct drm_sched_job *sched_job)
{
- drm_sched_job_cleanup(sched_job);
panthor_job_put(sched_job);
}
diff --git a/drivers/gpu/drm/sysfb/simpledrm.c b/drivers/gpu/drm/sysfb/simpledrm.c
index 9e0711e0095a..21ddf4502ecc 100644
--- a/drivers/gpu/drm/sysfb/simpledrm.c
+++ b/drivers/gpu/drm/sysfb/simpledrm.c
@@ -28,6 +28,7 @@
#include <drm/drm_managed.h>
#include <drm/drm_modeset_helper.h>
#include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_of.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
@@ -623,6 +624,7 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv,
int width, height, stride;
u16 width_mm = 0, height_mm = 0;
struct device_node *panel_node;
+ enum drm_panel_orientation orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
const struct drm_format_info *format;
u64 size;
struct resource *res, *mem = NULL;
@@ -698,6 +700,12 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv,
ret = simplefb_get_panel_height_mm_of(dev, panel_node);
if (ret > 0)
height_mm = ret;
+ /*
+ * Ignore errors from parsing the panel orientation. With
+ * the orientation initialized to UNKNOWN, the connector
+ * helpers will do the right thing.
+ */
+ drm_of_get_panel_orientation(panel_node, &orientation);
of_node_put(panel_node);
}
} else {
@@ -861,8 +869,7 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv,
if (ret)
return ERR_PTR(ret);
drm_connector_helper_add(connector, &simpledrm_connector_helper_funcs);
- drm_connector_set_panel_orientation_with_quirk(connector,
- DRM_MODE_PANEL_ORIENTATION_UNKNOWN,
+ drm_connector_set_panel_orientation_with_quirk(connector, orientation,
width, height);
ret = drm_connector_attach_encoder(connector, encoder);
diff --git a/drivers/gpu/drm/v3d/v3d_submit.c b/drivers/gpu/drm/v3d/v3d_submit.c
index 4a0493c6283d..119a81c9e1c4 100644
--- a/drivers/gpu/drm/v3d/v3d_submit.c
+++ b/drivers/gpu/drm/v3d/v3d_submit.c
@@ -5,6 +5,7 @@
*/
#include <linux/dma-fence-unwrap.h>
+#include <linux/overflow.h>
#include <drm/drm_print.h>
#include <drm/drm_syncobj.h>
@@ -1379,6 +1380,126 @@ static const unsigned int cpu_job_bo_handle_count[] = {
[V3D_CPU_JOB_TYPE_COPY_PERFORMANCE_QUERY] = 1,
};
+/* Reject offset + (count - 1) * stride + write_size if it leaves the BO. */
+static int
+v3d_check_copy_extent(struct drm_device *dev, size_t bo_size,
+ u32 offset, u32 stride, u32 count, u64 write_size)
+{
+ u64 last;
+
+ if (!count)
+ return 0;
+
+ /*
+ * The executors walk a u8 * cursor, so the furthest written byte is
+ * offset + (count - 1) * stride + write_size, matching the pointer
+ * arithmetic in v3d_copy_query_results()/v3d_copy_performance_query().
+ * (count - 1) * stride is a u32 * u32 product that is exact in u64,
+ * and offset + write_size stays far below the u64 range, so a single
+ * overflow check guards the total.
+ */
+ last = write_size + offset;
+ if (check_add_overflow((u64)(count - 1) * stride, last, &last) ||
+ last > bo_size) {
+ drm_dbg(dev, "CPU job copy buffer exceeds the destination BO.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* Reject a query CPU job whose writes would land outside their BO. */
+static int
+v3d_cpu_job_bounds_check(struct v3d_cpu_job *job)
+{
+ struct drm_device *dev = &job->base.v3d->drm;
+ struct v3d_timestamp_query_info *tquery = &job->timestamp_query;
+ struct v3d_copy_query_results_info *copy = &job->copy;
+ u32 elem = copy->do_64bit ? sizeof(u64) : sizeof(u32);
+ struct v3d_bo *dst, *src;
+ u64 slots, write_size;
+ u32 i;
+
+ switch (job->job_type) {
+ case V3D_CPU_JOB_TYPE_TIMESTAMP_QUERY:
+ case V3D_CPU_JOB_TYPE_RESET_TIMESTAMP_QUERY:
+ /* Each query writes one u64 timestamp slot into bo[0]. */
+ dst = to_v3d_bo(job->base.bo[0]);
+
+ for (i = 0; i < tquery->count; i++) {
+ if ((u64)tquery->queries[i].offset + sizeof(u64) >
+ dst->base.base.size)
+ goto err_range;
+ }
+ return 0;
+ case V3D_CPU_JOB_TYPE_COPY_TIMESTAMP_QUERY:
+ /* Copies one u64 per query from bo[1] into bo[0]. */
+ dst = to_v3d_bo(job->base.bo[0]);
+ src = to_v3d_bo(job->base.bo[1]);
+
+ for (i = 0; i < tquery->count; i++) {
+ if ((u64)tquery->queries[i].offset + sizeof(u64) >
+ src->base.base.size)
+ goto err_range;
+ }
+
+ write_size = (copy->availability_bit ? 2 : 1) * elem;
+ return v3d_check_copy_extent(dev, dst->base.base.size,
+ copy->offset, copy->stride,
+ tquery->count, write_size);
+ case V3D_CPU_JOB_TYPE_COPY_PERFORMANCE_QUERY:
+ /*
+ * Each query writes nperfmons * DRM_V3D_MAX_PERF_COUNTERS
+ * counter slots into bo[0], plus an availability slot at
+ * index ncounters. nperfmons and ncounters are user values,
+ * so the slot count is computed overflow-safe.
+ */
+ dst = to_v3d_bo(job->base.bo[0]);
+
+ slots = (u64)job->performance_query.nperfmons *
+ DRM_V3D_MAX_PERF_COUNTERS;
+ if (copy->availability_bit)
+ slots = max(slots,
+ (u64)job->performance_query.ncounters + 1);
+
+ write_size = slots * elem;
+ return v3d_check_copy_extent(dev, dst->base.base.size,
+ copy->offset, copy->stride,
+ job->performance_query.count,
+ write_size);
+ case V3D_CPU_JOB_TYPE_INDIRECT_CSD: {
+ struct v3d_indirect_csd_info *indirect_csd = &job->indirect_csd;
+
+ /* 3 is the three dimensions (x, y, z) of the workgroup counts. */
+ src = to_v3d_bo(job->base.bo[0]);
+ if ((u64)indirect_csd->offset + 3 * sizeof(u32) >
+ src->base.base.size)
+ goto err_range;
+
+ dst = to_v3d_bo(indirect_csd->indirect);
+ for (i = 0; i < 3; i++) {
+ u32 uidx = indirect_csd->wg_uniform_offsets[i];
+
+ /*
+ * 0xffffffff means "skip this rewrite", so the exec
+ * path never writes that index and it needs no check.
+ */
+ if (uidx != 0xffffffff &&
+ (u64)uidx * sizeof(u32) + sizeof(u32) >
+ dst->base.base.size)
+ goto err_range;
+ }
+ return 0;
+ }
+ default:
+ return 0;
+ }
+
+err_range:
+ drm_dbg(dev, "CPU job query offset exceeds the BO.\n");
+ return -EINVAL;
+}
+
/**
* v3d_submit_cpu_ioctl() - Submits a CPU job to the V3D.
* @dev: DRM device
@@ -1441,6 +1562,10 @@ v3d_submit_cpu_ioctl(struct drm_device *dev, void *data,
ret = v3d_lookup_bos(&submit, args->bo_handles, args->bo_handle_count);
if (ret)
goto fail;
+
+ ret = v3d_cpu_job_bounds_check(cpu_job);
+ if (ret)
+ goto fail;
}
if (cpu_job->job_type == V3D_CPU_JOB_TYPE_INDIRECT_CSD) {
diff --git a/drivers/gpu/drm/xe/.gitignore b/drivers/gpu/drm/xe/.gitignore
index 8778bf132674..6dad8a5a2135 100644
--- a/drivers/gpu/drm/xe/.gitignore
+++ b/drivers/gpu/drm/xe/.gitignore
@@ -2,3 +2,4 @@
*.hdrtest
/generated
/xe_gen_wa_oob
+!.kunitconfig-display
diff --git a/drivers/gpu/drm/xe/.kunitconfig-display b/drivers/gpu/drm/xe/.kunitconfig-display
new file mode 100644
index 000000000000..17020aa4ded3
--- /dev/null
+++ b/drivers/gpu/drm/xe/.kunitconfig-display
@@ -0,0 +1,11 @@
+CONFIG_EXPERT=y
+CONFIG_MODULES=y
+CONFIG_KUNIT=y
+CONFIG_PCI=y
+CONFIG_DEBUG_FS=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DRM=m
+CONFIG_DRM_XE=m
+CONFIG_DRM_XE_DISPLAY=y
+CONFIG_DRM_XE_KUNIT_TEST=m
diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
index 6d728f8c4c39..67ada1d6c2fb 100644
--- a/drivers/gpu/drm/xe/Makefile
+++ b/drivers/gpu/drm/xe/Makefile
@@ -374,6 +374,9 @@ xe-$(CONFIG_DRM_XE_DP_TUNNEL) += \
obj-$(CONFIG_DRM_XE) += xe.o
obj-$(CONFIG_DRM_XE_KUNIT_TEST) += tests/
+ifeq ($(CONFIG_DRM_XE_DISPLAY),y)
+ obj-$(CONFIG_DRM_XE_KUNIT_TEST) += display/tests/
+endif
# header test
hdrtest_find_args := -not -path xe_rtp_helpers.h
diff --git a/drivers/gpu/drm/xe/abi/guc_actions_abi.h b/drivers/gpu/drm/xe/abi/guc_actions_abi.h
index 83a6e7794982..f5c9b37038d4 100644
--- a/drivers/gpu/drm/xe/abi/guc_actions_abi.h
+++ b/drivers/gpu/drm/xe/abi/guc_actions_abi.h
@@ -152,6 +152,7 @@ enum xe_guc_action {
XE_GUC_ACTION_REPORT_PAGE_FAULT_REQ_DESC = 0x6002,
XE_GUC_ACTION_PAGE_FAULT_RES_DESC = 0x6003,
XE_GUC_ACTION_ACCESS_COUNTER_NOTIFY = 0x6004,
+ XE_GUC_ACTION_NOTIFY_UNCORRECTABLE_LOCAL_ERROR = 0x6005,
XE_GUC_ACTION_TLB_INVALIDATION = 0x7000,
XE_GUC_ACTION_TLB_INVALIDATION_DONE = 0x7001,
XE_GUC_ACTION_TLB_INVALIDATION_ALL = 0x7002,
diff --git a/drivers/gpu/drm/xe/abi/guc_klvs_abi.h b/drivers/gpu/drm/xe/abi/guc_klvs_abi.h
index 644f5a4226d7..ec9c22dc21be 100644
--- a/drivers/gpu/drm/xe/abi/guc_klvs_abi.h
+++ b/drivers/gpu/drm/xe/abi/guc_klvs_abi.h
@@ -154,6 +154,11 @@ enum {
* (instead of waiting the full timeslice duration). The bit is instead set
* to one if a single context is queued on the engine, to avoid it being
* switched out if there isn't another context that can run in its place.
+ *
+ * _`GUC_KLV_OPT_IN_FEATURE_UNCORRECTABLE_LOCAL_ERROR_NOTIFICATION` : 0x4004
+ * This flag will enable notification from GuC to KMD via G2H message
+ * GUC_ACTION_GUC2HOST_NOTIFY_UNCORRECTABLE_LOCAL_ERROR upon receiving the
+ * same interrupt from the CS.
*/
#define GUC_KLV_OPT_IN_FEATURE_EXT_CAT_ERR_TYPE_KEY 0x4001
@@ -162,6 +167,9 @@ enum {
#define GUC_KLV_OPT_IN_FEATURE_DYNAMIC_INHIBIT_CONTEXT_SWITCH_KEY 0x4003
#define GUC_KLV_OPT_IN_FEATURE_DYNAMIC_INHIBIT_CONTEXT_SWITCH_LEN 0u
+#define GUC_KLV_OPT_IN_FEATURE_UNCORRECTABLE_LOCAL_ERROR_NOTIFICATION_KEY 0x4004
+#define GUC_KLV_OPT_IN_FEATURE_UNCORRECTABLE_LOCAL_ERROR_NOTIFICATION_LEN 0u
+
/**
* DOC: GuC Scheduling Policies KLVs
*
@@ -504,6 +512,8 @@ enum xe_guc_klv_ids {
GUC_WA_KLV_RESET_BB_STACK_PTR_ON_VF_SWITCH = 0x900b,
GUC_WA_KLV_RESTORE_UNSAVED_MEDIA_CONTROL_REG = 0x900c,
GUC_WA_KLV_CLR_CS_INDIRECT_RING_STATE_IF_IDLE_AT_CTX_REG = 0x900e,
+ GUC_WA_KLV_REMAP_RANGED_TLB_INV = 0x900f,
+ GUC_WA_KLV_IGNORE_MMIO_READ_SEM_TOKEN_64 = 0x9010,
};
#endif
diff --git a/drivers/gpu/drm/xe/display/tests/Makefile b/drivers/gpu/drm/xe/display/tests/Makefile
new file mode 100644
index 000000000000..c71686458072
--- /dev/null
+++ b/drivers/gpu/drm/xe/display/tests/Makefile
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0
+
+subdir-ccflags-$(CONFIG_DRM_XE_DISPLAY) += \
+ -I$(srctree)/drivers/gpu/drm/i915/display/
+
+# Rule to build display code shared with i915
+$(obj)/i915-display/tests/%.o: $(srctree)/drivers/gpu/drm/i915/display/tests/%.c FORCE
+ $(call cmd,force_checksrc)
+ $(call if_changed_rule,cc_o_c)
+
+obj-$(CONFIG_DRM_XE_KUNIT_TEST) += xe_display_test.o
+xe_display_test-y = \
+ i915-display/tests/intel_dp_link_test.o
diff --git a/drivers/gpu/drm/xe/xe_gt_types.h b/drivers/gpu/drm/xe/xe_gt_types.h
index e5588c88800a..0d234160ee3a 100644
--- a/drivers/gpu/drm/xe/xe_gt_types.h
+++ b/drivers/gpu/drm/xe/xe_gt_types.h
@@ -145,6 +145,11 @@ struct xe_gt {
/** @info.has_indirect_ring_state: GT has indirect ring state support */
u8 has_indirect_ring_state:1;
/**
+ * @info.has_uncorrectable_error_reporting: GT has uncorrectable
+ * error reporting support
+ */
+ u8 has_uncorrectable_error_reporting:1;
+ /**
* @info.has_xe2_blt_instructions: GT supports Xe2-style MEM_SET
* and MEM_COPY blitter functionality. Note that despite the
* name, some Xe1 platforms may also support this "Xe2-style"
diff --git a/drivers/gpu/drm/xe/xe_guc.c b/drivers/gpu/drm/xe/xe_guc.c
index 4023700ff2a9..543f3992bccd 100644
--- a/drivers/gpu/drm/xe/xe_guc.c
+++ b/drivers/gpu/drm/xe/xe_guc.c
@@ -12,6 +12,7 @@
#include "abi/guc_actions_abi.h"
#include "abi/guc_errors_abi.h"
+#include "abi/guc_klvs_abi.h"
#include "regs/xe_gt_regs.h"
#include "regs/xe_gtt_defs.h"
#include "regs/xe_guc_regs.h"
@@ -641,6 +642,15 @@ int xe_guc_opt_in_features_enable(struct xe_guc *guc)
if (GUC_SUBMIT_VER(guc) >= MAKE_GUC_VER(1, 7, 0))
klvs[count++] = PREP_GUC_KLV_TAG(OPT_IN_FEATURE_EXT_CAT_ERR_TYPE);
+ /*
+ * The uncorrectable local error notification opt-in was added in
+ * GuC v70.38.0, which maps to compatibility version v1.18.0.
+ */
+ if (GUC_SUBMIT_VER(guc) >= MAKE_GUC_VER(1, 18, 0) &&
+ guc_to_gt(guc)->info.has_uncorrectable_error_reporting)
+ klvs[count++] =
+ PREP_GUC_KLV_TAG(OPT_IN_FEATURE_UNCORRECTABLE_LOCAL_ERROR_NOTIFICATION);
+
if (supports_dynamic_ics(guc))
klvs[count++] = PREP_GUC_KLV_TAG(OPT_IN_FEATURE_DYNAMIC_INHIBIT_CONTEXT_SWITCH);
diff --git a/drivers/gpu/drm/xe/xe_guc_ads.c b/drivers/gpu/drm/xe/xe_guc_ads.c
index c98454545a85..79d6fd8d919b 100644
--- a/drivers/gpu/drm/xe/xe_guc_ads.c
+++ b/drivers/gpu/drm/xe/xe_guc_ads.c
@@ -364,6 +364,15 @@ static void guc_waklv_init(struct xe_guc_ads *ads)
guc_waklv_enable(ads, NULL, 0, &offset, &remain,
GUC_WA_KLV_CLR_CS_INDIRECT_RING_STATE_IF_IDLE_AT_CTX_REG);
+ if (XE_GT_WA(gt, 22022079272) && GUC_FIRMWARE_VER_AT_LEAST(&gt->uc.guc, 70, 62))
+ guc_waklv_enable(ads, NULL, 0, &offset, &remain, GUC_WA_KLV_REMAP_RANGED_TLB_INV);
+
+ /* The GuC does not enable the sem_tok_64 feature on NVL-S */
+ if (XE_GT_WA(gt, 16029897822) && gt_to_xe(gt)->info.platform != XE_NOVALAKE_S &&
+ GUC_FIRMWARE_VER_AT_LEAST(&gt->uc.guc, 70, 69))
+ guc_waklv_enable(ads, NULL, 0, &offset, &remain,
+ GUC_WA_KLV_IGNORE_MMIO_READ_SEM_TOKEN_64);
+
size = guc_ads_waklv_size(ads) - remain;
if (!size)
return;
diff --git a/drivers/gpu/drm/xe/xe_guc_ct.c b/drivers/gpu/drm/xe/xe_guc_ct.c
index 21e0dad9a481..fe70c0fd85c5 100644
--- a/drivers/gpu/drm/xe/xe_guc_ct.c
+++ b/drivers/gpu/drm/xe/xe_guc_ct.c
@@ -1065,6 +1065,11 @@ static int __guc_ct_send_locked(struct xe_guc_ct *ct, const u32 *action,
xe_gt_assert(gt, g2h_len || !num_g2h);
lockdep_assert_held(&ct->lock);
+ if (xe_device_wedged(ct_to_xe(ct))) {
+ ret = -ENOTRECOVERABLE;
+ goto out;
+ }
+
if (unlikely(ct->ctbs.h2g.info.broken)) {
ret = -EPIPE;
goto out;
@@ -1236,6 +1241,36 @@ static int guc_ct_send(struct xe_guc_ct *ct, const u32 *action, u32 len,
return ret;
}
+/**
+ * xe_guc_ct_send - Send an HXG message to the GuC over CT
+ * @ct: the &xe_guc_ct
+ * @action: dword array with the HXG message (can't be NULL)
+ * @len: length of the HXG message in dwords (can't be 0)
+ * @g2h_len: G2H response space to reserve in dwords, or 0
+ * @num_g2h: number of G2H messages expected, or 0
+ *
+ * Return codes from the non-blocking send helpers are:
+ *
+ * * -ENOTRECOVERABLE: the xe device is wedged. Stop submitting new GuC work; the
+ * request cannot make progress until the device is recovered.
+ * * -EPIPE: the H2G CTB is marked broken. The channel stays unusable until the
+ * CT is restarted, which clears the broken flag.
+ * * -ENODEV: the CT channel is disabled, messages not expected in this state.
+ * Don't retry until it is enabled again.
+ * * -ECANCELED: the CT channel is stopped or a GT recovery is pending; the
+ * message was dropped. Often benign. Cancel-tolerant callers (e.g. TLB
+ * invalidations, GuC submission) rely on the stop/start flow to recover;
+ * others should retry once the CT is re-enabled or the reset/recovery
+ * completes.
+ * * -EDEADLK: no CTB room and the wait for space timed out. The send helpers
+ * have already requested an async GT reset before returning this error.
+ *
+ * -ENOMEM may also be returned if an internal allocation fails; the blocking
+ * xe_guc_ct_send_recv() path retries that allocation. -EBUSY and
+ * -EAGAIN are internal flow-control results handled by the send helpers.
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
int xe_guc_ct_send(struct xe_guc_ct *ct, const u32 *action, u32 len,
u32 g2h_len, u32 num_g2h)
{
@@ -1388,7 +1423,7 @@ wait_again:
if (g2h_fence.fail) {
if (g2h_fence.cancel) {
xe_gt_dbg(gt, "H2G request %#x canceled!\n", action[0]);
- ret = -ECANCELED;
+ ret = xe_device_wedged(ct_to_xe(ct)) ? -ENOTRECOVERABLE : -ECANCELED;
goto unlock;
}
xe_gt_err(gt, "H2G request %#x failed: error %#x hint %#x\n",
@@ -1661,6 +1696,9 @@ static int process_g2h_msg(struct xe_guc_ct *ct, u32 *msg, u32 len)
ret = xe_guc_exec_queue_memory_cat_error_handler(guc, payload,
adj_len);
break;
+ case XE_GUC_ACTION_NOTIFY_UNCORRECTABLE_LOCAL_ERROR:
+ ret = xe_guc_uncorrectable_error_handler(guc, payload, adj_len);
+ break;
case XE_GUC_ACTION_REPORT_PAGE_FAULT_REQ_DESC:
ret = xe_guc_pagefault_handler(guc, payload, adj_len);
break;
@@ -1724,6 +1762,9 @@ static int g2h_read(struct xe_guc_ct *ct, u32 *msg, bool fast_path)
xe_gt_assert(gt, xe_guc_ct_initialized(ct));
lockdep_assert_held(&ct->fast_lock);
+ if (xe_device_wedged(xe))
+ return -ENOTRECOVERABLE;
+
if (ct->state == XE_GUC_CT_STATE_DISABLED)
return -ENODEV;
diff --git a/drivers/gpu/drm/xe/xe_guc_engine_activity.c b/drivers/gpu/drm/xe/xe_guc_engine_activity.c
index 2b99c1ebdd58..f43ca1c76f75 100644
--- a/drivers/gpu/drm/xe/xe_guc_engine_activity.c
+++ b/drivers/gpu/drm/xe/xe_guc_engine_activity.c
@@ -473,7 +473,7 @@ void xe_guc_engine_activity_enable_stats(struct xe_guc *guc)
ret = enable_engine_activity_stats(guc);
if (ret)
- xe_gt_err(guc_to_gt(guc), "failed to enable activity stats%d\n", ret);
+ xe_gt_err(guc_to_gt(guc), "failed to enable activity stats: %pe\n", ERR_PTR(ret));
else
engine_activity_set_cpu_ts(guc, 0);
}
diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c
index 12416bfa3255..e5fcb1f21115 100644
--- a/drivers/gpu/drm/xe/xe_guc_submit.c
+++ b/drivers/gpu/drm/xe/xe_guc_submit.c
@@ -3022,6 +3022,38 @@ int xe_guc_exec_queue_memory_cat_error_handler(struct xe_guc *guc, u32 *msg,
return 0;
}
+int xe_guc_uncorrectable_error_handler(struct xe_guc *guc, u32 *msg, u32 len)
+{
+ struct xe_gt *gt = guc_to_gt(guc);
+ struct xe_exec_queue *q;
+ u32 guc_id;
+
+ if (unlikely(!len || len > 1))
+ return -EPROTO;
+
+ guc_id = msg[0];
+
+ if (guc_id == GUC_ID_UNKNOWN) {
+ xe_gt_err(gt, "GuC: Uncorrectable local error with unknown GuC id\n");
+ return 0;
+ }
+
+ q = g2h_exec_queue_lookup(guc, guc_id);
+ if (unlikely(!q))
+ return -EPROTO;
+
+ xe_gt_err(gt,
+ "GuC: Uncorrectable local error! guc_id=%d class=%s, logical_mask=0x%x",
+ guc_id, xe_hw_engine_class_to_str(q->class), q->logical_mask);
+
+ trace_xe_guc_uncorrectable_error(q);
+
+ /* Treat the same as engine reset */
+ xe_guc_exec_queue_reset_trigger_cleanup(q);
+
+ return 0;
+}
+
int xe_guc_exec_queue_reset_failure_handler(struct xe_guc *guc, u32 *msg, u32 len)
{
struct xe_gt *gt = guc_to_gt(guc);
diff --git a/drivers/gpu/drm/xe/xe_guc_submit.h b/drivers/gpu/drm/xe/xe_guc_submit.h
index b3839a90c142..ccade320dc69 100644
--- a/drivers/gpu/drm/xe/xe_guc_submit.h
+++ b/drivers/gpu/drm/xe/xe_guc_submit.h
@@ -34,6 +34,7 @@ int xe_guc_deregister_done_handler(struct xe_guc *guc, u32 *msg, u32 len);
int xe_guc_exec_queue_reset_handler(struct xe_guc *guc, u32 *msg, u32 len);
int xe_guc_exec_queue_memory_cat_error_handler(struct xe_guc *guc, u32 *msg,
u32 len);
+int xe_guc_uncorrectable_error_handler(struct xe_guc *guc, u32 *msg, u32 len);
int xe_guc_exec_queue_reset_failure_handler(struct xe_guc *guc, u32 *msg, u32 len);
int xe_guc_error_capture_handler(struct xe_guc *guc, u32 *msg, u32 len);
int xe_guc_exec_queue_cgp_sync_done_handler(struct xe_guc *guc, u32 *msg, u32 len);
diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c
index 91af603e9431..11a69dffdce7 100644
--- a/drivers/gpu/drm/xe/xe_pci.c
+++ b/drivers/gpu/drm/xe/xe_pci.c
@@ -120,6 +120,7 @@ static const struct xe_graphics_desc graphics_xe2 = {
static const struct xe_graphics_desc graphics_xe3p_lpg = {
XE2_GFX_FEATURES,
.has_indirect_ring_state = 1,
+ .has_uncorrectable_error_reporting = 1,
.multi_queue_engine_class_mask = BIT(XE_ENGINE_CLASS_COPY) | BIT(XE_ENGINE_CLASS_COMPUTE),
.num_geometry_xecore_fuse_regs = 3,
.num_compute_xecore_fuse_regs = 3,
@@ -129,6 +130,7 @@ static const struct xe_graphics_desc graphics_xe3p_xpc = {
XE2_GFX_FEATURES,
.has_access_counter = 0,
.has_indirect_ring_state = 1,
+ .has_uncorrectable_error_reporting = 1,
.hw_engine_mask =
GENMASK(XE_HW_ENGINE_BCS8, XE_HW_ENGINE_BCS1) |
GENMASK(XE_HW_ENGINE_CCS3, XE_HW_ENGINE_CCS0),
@@ -151,6 +153,14 @@ static const struct xe_media_desc media_xelpmp = {
BIT(XE_HW_ENGINE_GSCCS0)
};
+static const struct xe_media_desc media_xe3p_hpm = {
+ .has_uncorrectable_error_reporting = 1,
+ .hw_engine_mask =
+ GENMASK(XE_HW_ENGINE_VCS7, XE_HW_ENGINE_VCS0) |
+ GENMASK(XE_HW_ENGINE_VECS3, XE_HW_ENGINE_VECS0) |
+ BIT(XE_HW_ENGINE_GSCCS0)
+};
+
/* Pre-GMDID Graphics IPs */
static const struct xe_ip graphics_ip_xelp = { 1200, "Xe_LP", &graphics_xelp };
static const struct xe_ip graphics_ip_xelpp = { 1210, "Xe_LP+", &graphics_xelp };
@@ -186,7 +196,7 @@ static const struct xe_ip media_ips[] = {
{ 3000, "Xe3_LPM", &media_xelpmp },
{ 3002, "Xe3_LPM", &media_xelpmp },
{ 3500, "Xe3p_LPM", &media_xelpmp },
- { 3503, "Xe3p_HPM", &media_xelpmp },
+ { 3503, "Xe3p_HPM", &media_xe3p_hpm },
};
#define MULTI_LRC_MASK \
@@ -875,6 +885,8 @@ static struct xe_gt *alloc_primary_gt(struct xe_tile *tile,
gt->info.type = XE_GT_TYPE_MAIN;
gt->info.id = tile->id * xe->info.max_gt_per_tile;
gt->info.has_indirect_ring_state = graphics_desc->has_indirect_ring_state;
+ gt->info.has_uncorrectable_error_reporting =
+ graphics_desc->has_uncorrectable_error_reporting;
gt->info.multi_queue_engine_class_mask = graphics_desc->multi_queue_engine_class_mask;
gt->info.engine_mask = graphics_desc->hw_engine_mask;
gt->info.num_geometry_xecore_fuse_regs = graphics_desc->num_geometry_xecore_fuse_regs;
@@ -920,6 +932,7 @@ static struct xe_gt *alloc_media_gt(struct xe_tile *tile,
gt->info.type = XE_GT_TYPE_MEDIA;
gt->info.id = tile->id * xe->info.max_gt_per_tile + 1;
gt->info.has_indirect_ring_state = media_desc->has_indirect_ring_state;
+ gt->info.has_uncorrectable_error_reporting = media_desc->has_uncorrectable_error_reporting;
gt->info.engine_mask = media_desc->hw_engine_mask;
return gt;
diff --git a/drivers/gpu/drm/xe/xe_pci_types.h b/drivers/gpu/drm/xe/xe_pci_types.h
index 24d4a3d00517..fed509ff601e 100644
--- a/drivers/gpu/drm/xe/xe_pci_types.h
+++ b/drivers/gpu/drm/xe/xe_pci_types.h
@@ -79,12 +79,14 @@ struct xe_graphics_desc {
u8 has_ctx_tlb_inval:1;
u8 has_usm:1;
u8 has_64bit_timestamp:1;
+ u8 has_uncorrectable_error_reporting:1;
};
struct xe_media_desc {
u64 hw_engine_mask; /* hardware engines provided by media IP */
u8 has_indirect_ring_state:1;
+ u8 has_uncorrectable_error_reporting:1;
};
struct xe_ip {
diff --git a/drivers/gpu/drm/xe/xe_pt.c b/drivers/gpu/drm/xe/xe_pt.c
index 5fdad444009f..7111b5d0f6aa 100644
--- a/drivers/gpu/drm/xe/xe_pt.c
+++ b/drivers/gpu/drm/xe/xe_pt.c
@@ -760,7 +760,7 @@ xe_pt_stage_bind(struct xe_tile *tile, struct xe_vma *vma,
return -EAGAIN;
}
if (xe_svm_range_has_dma_mapping(range)) {
- xe_res_first_dma(range->base.pages.dma_addr, 0,
+ xe_res_first_dma(range->pages.dma_addr, 0,
xe_svm_range_size(range),
&curs);
xe_svm_range_debug(range, "BIND PREPARE - MIXED");
@@ -1418,6 +1418,7 @@ static int xe_pt_pre_commit(struct xe_migrate_pt_update *pt_update)
pt_update_ops, rftree);
}
+#if IS_ENABLED(CONFIG_DRM_GPUSVM)
/*
* Acquire/release the svm notifier_lock around xe_pt_svm_userptr_pre_commit()
* and the matching late release in xe_pt_update_ops_run(). Read mode by
@@ -1444,6 +1445,10 @@ static void xe_pt_svm_userptr_notifier_unlock(struct xe_vm *vm)
xe_svm_notifier_unlock(vm);
#endif
}
+#else
+static inline void xe_pt_svm_userptr_notifier_lock(struct xe_vm *vm) { }
+static inline void xe_pt_svm_userptr_notifier_unlock(struct xe_vm *vm) { }
+#endif
#if IS_ENABLED(CONFIG_DRM_GPUSVM)
#ifdef CONFIG_DRM_XE_USERPTR_INVAL_INJECT
diff --git a/drivers/gpu/drm/xe/xe_svm.c b/drivers/gpu/drm/xe/xe_svm.c
index e0f0c23d172d..b228a737cfd6 100644
--- a/drivers/gpu/drm/xe/xe_svm.c
+++ b/drivers/gpu/drm/xe/xe_svm.c
@@ -66,7 +66,7 @@ static bool xe_svm_range_in_vram(struct xe_svm_range *range)
struct drm_gpusvm_pages_flags flags = {
/* Pairs with WRITE_ONCE in drm_gpusvm.c */
- .__flags = READ_ONCE(range->base.pages.flags.__flags),
+ .__flags = READ_ONCE(range->pages.flags.__flags),
};
return flags.has_devmem_pages;
@@ -96,7 +96,7 @@ static struct xe_vm *range_to_vm(struct drm_gpusvm_range *r)
(r__)->base.gpusvm, \
xe_svm_range_in_vram((r__)) ? 1 : 0, \
xe_svm_range_has_vram_binding((r__)) ? 1 : 0, \
- (r__)->base.pages.notifier_seq, \
+ (r__)->pages.notifier_seq, \
xe_svm_range_start((r__)), xe_svm_range_end((r__)), \
xe_svm_range_size((r__)))
@@ -115,6 +115,7 @@ xe_svm_range_alloc(struct drm_gpusvm *gpusvm)
return NULL;
INIT_LIST_HEAD(&range->garbage_collector_link);
+ drm_gpusvm_init_pages(&range->pages, &gpusvm_to_vm(gpusvm)->xe->drm);
xe_vm_get(gpusvm_to_vm(gpusvm));
return &range->base;
@@ -122,8 +123,10 @@ xe_svm_range_alloc(struct drm_gpusvm *gpusvm)
static void xe_svm_range_free(struct drm_gpusvm_range *range)
{
+ drm_gpusvm_free_pages(range->gpusvm, &(to_xe_range(range)->pages),
+ drm_gpusvm_range_size(range) >> PAGE_SHIFT);
xe_vm_put(range_to_vm(range));
- kfree(range);
+ kfree(to_xe_range(range));
}
static void
@@ -134,7 +137,8 @@ xe_svm_garbage_collector_add_range(struct xe_vm *vm, struct xe_svm_range *range,
range_debug(range, "GARBAGE COLLECTOR ADD");
- drm_gpusvm_range_set_unmapped(&range->base, mmu_range);
+ drm_gpusvm_range_set_unmapped(&range->base, &range->pages, 1,
+ mmu_range);
spin_lock(&vm->svm.garbage_collector.lock);
if (list_empty(&range->garbage_collector_link))
@@ -166,7 +170,7 @@ xe_svm_range_notifier_event_begin(struct xe_vm *vm, struct drm_gpusvm_range *r,
range_debug(range, "NOTIFIER");
/* Skip if already unmapped or if no binding exist */
- if (range->base.pages.flags.unmapped || !range->tile_present)
+ if (range->base.flags.unmapped || !range->tile_present)
return 0;
range_debug(range, "NOTIFIER - EXECUTE");
@@ -208,7 +212,8 @@ xe_svm_range_notifier_event_end(struct xe_vm *vm, struct drm_gpusvm_range *r,
xe_svm_assert_in_notifier(vm);
- drm_gpusvm_range_unmap_pages(&vm->svm.gpusvm, r, &ctx);
+ drm_gpusvm_unmap_pages(&vm->svm.gpusvm, &(to_xe_range(r)->pages),
+ drm_gpusvm_range_size(r) >> PAGE_SHIFT, &ctx);
if (!xe_vm_is_closed(vm) && mmu_range->event == MMU_NOTIFY_UNMAP)
xe_svm_garbage_collector_add_range(vm, to_xe_range(r),
mmu_range);
@@ -299,6 +304,7 @@ range_notifier_event_end:
static int __xe_svm_garbage_collector(struct xe_vm *vm,
struct xe_svm_range *range)
{
+ struct drm_gpusvm_ctx ctx = { .in_notifier = false, };
struct dma_fence *fence;
range_debug(range, "GARBAGE COLLECTOR");
@@ -310,6 +316,10 @@ static int __xe_svm_garbage_collector(struct xe_vm *vm,
return PTR_ERR(fence);
dma_fence_put(fence);
+ drm_gpusvm_unmap_pages(&vm->svm.gpusvm, &range->pages,
+ drm_gpusvm_range_size(&range->base) >> PAGE_SHIFT,
+ &ctx);
+
drm_gpusvm_range_remove(&vm->svm.gpusvm, &range->base);
return 0;
@@ -901,7 +911,7 @@ int xe_svm_init(struct xe_vm *vm)
return err;
}
- err = drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM", &vm->xe->drm,
+ err = drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM",
current->mm, 0, vm->size,
xe_modparam.svm_notifier_size * SZ_1M,
&gpusvm_ops, fault_chunk_sizes,
@@ -915,7 +925,7 @@ int xe_svm_init(struct xe_vm *vm)
}
} else {
err = drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM (simple)",
- &vm->xe->drm, NULL, 0, 0, 0, NULL,
+ NULL, 0, 0, 0, NULL,
NULL, 0);
}
@@ -944,15 +954,28 @@ void xe_svm_close(struct xe_vm *vm)
*/
void xe_svm_fini(struct xe_vm *vm)
{
+ struct drm_gpusvm_notifier *notifier, *next;
+ struct drm_gpusvm_ctx ctx = { .in_notifier = false, };
+
xe_assert(vm->xe, xe_vm_is_closed(vm));
+ drm_gpusvm_for_each_notifier_safe(notifier, next, &vm->svm.gpusvm, 0, LONG_MAX) {
+ struct drm_gpusvm_range *range, *__next;
+
+ drm_gpusvm_for_each_range_safe(range, __next, notifier, 0, LONG_MAX)
+ drm_gpusvm_unmap_pages(&vm->svm.gpusvm,
+ &(to_xe_range(range)->pages),
+ drm_gpusvm_range_size(range) >> PAGE_SHIFT,
+ &ctx);
+ }
+
drm_gpusvm_fini(&vm->svm.gpusvm);
}
static bool xe_svm_range_has_pagemap_locked(const struct xe_svm_range *range,
const struct drm_pagemap *dpagemap)
{
- return range->base.pages.dpagemap == dpagemap;
+ return range->pages.dpagemap == dpagemap;
}
static bool xe_svm_range_has_pagemap(struct xe_svm_range *range,
@@ -1017,7 +1040,7 @@ bool xe_svm_range_validate(struct xe_vm *vm,
if (dpagemap)
ret = ret && xe_svm_range_has_pagemap_locked(range, dpagemap);
else
- ret = ret && !range->base.pages.dpagemap;
+ ret = ret && !range->pages.dpagemap;
xe_svm_notifier_unlock(vm);
@@ -1135,8 +1158,12 @@ bool xe_svm_range_needs_migrate_to_vram(struct xe_svm_range *range, struct xe_vm
{
struct xe_vm *vm = range_to_vm(&range->base);
u64 range_size = xe_svm_range_size(range);
+ struct drm_gpusvm_range_flags flags = {
+ /* READ_ONCE pairs with WRITE_ONCE in drm_gpusvm_range_set_unmapped() */
+ .__flags = READ_ONCE(range->base.flags.__flags),
+ };
- if (!range->base.pages.flags.migrate_devmem || !dpagemap)
+ if (!flags.migrate_devmem || !dpagemap)
return false;
xe_assert(vm->xe, IS_DGFX(vm->xe));
@@ -1220,6 +1247,7 @@ static int __xe_svm_handle_pagefault(struct xe_vm *vm, struct xe_vma *vma,
struct xe_validation_ctx vctx;
struct drm_exec exec;
struct xe_svm_range *range;
+ struct drm_gpusvm_range_flags range_flags;
struct dma_fence *fence;
struct drm_pagemap *dpagemap;
struct xe_tile *tile = gt_to_tile(gt);
@@ -1248,7 +1276,9 @@ retry:
xe_svm_range_fault_count_stats_incr(gt, range);
- if (ctx.devmem_only && !range->base.pages.flags.migrate_devmem)
+ /* READ_ONCE pairs with WRITE_ONCE in drm_gpusvm_range_set_unmapped() */
+ range_flags.__flags = READ_ONCE(range->base.flags.__flags);
+ if (ctx.devmem_only && !range_flags.migrate_devmem)
return -EACCES;
if (xe_svm_range_is_valid(range, tile, ctx.devmem_only, dpagemap)) {
@@ -1505,7 +1535,11 @@ int xe_svm_range_get_pages(struct xe_vm *vm, struct xe_svm_range *range,
{
int err = 0;
- err = drm_gpusvm_range_get_pages(&vm->svm.gpusvm, &range->base, ctx);
+ err = drm_gpusvm_get_pages(&vm->svm.gpusvm, &range->pages,
+ vm->svm.gpusvm.mm,
+ &range->base.notifier->notifier,
+ drm_gpusvm_range_start(&range->base),
+ drm_gpusvm_range_end(&range->base), ctx);
if (err == -EOPNOTSUPP) {
range_debug(range, "PAGE FAULT - EVICT PAGES");
drm_gpusvm_range_evict(&vm->svm.gpusvm, &range->base);
@@ -1620,8 +1654,12 @@ int xe_svm_alloc_vram(struct xe_svm_range *range, const struct drm_gpusvm_ctx *c
struct xe_device *xe = vm->xe;
int err, retries = 1;
bool write_locked = false;
+ struct drm_gpusvm_range_flags flags = {
+ /* READ_ONCE pairs with WRITE_ONCE in drm_gpusvm_range_set_unmapped() */
+ .__flags = READ_ONCE(range->base.flags.__flags),
+ };
- xe_assert(range_to_vm(&range->base)->xe, range->base.pages.flags.migrate_devmem);
+ xe_assert(range_to_vm(&range->base)->xe, flags.migrate_devmem);
range_debug(range, "ALLOCATE VRAM");
migration_state = drm_gpusvm_scan_mm(&range->base,
diff --git a/drivers/gpu/drm/xe/xe_svm.h b/drivers/gpu/drm/xe/xe_svm.h
index 3ca46a6f98c7..a921556d3466 100644
--- a/drivers/gpu/drm/xe/xe_svm.h
+++ b/drivers/gpu/drm/xe/xe_svm.h
@@ -31,6 +31,8 @@ struct xe_vram_region;
struct xe_svm_range {
/** @base: base drm_gpusvm_range */
struct drm_gpusvm_range base;
+ /** @pages: Page/DMA mapping state for this range (single drm_device). */
+ struct drm_gpusvm_pages pages;
/**
* @garbage_collector_link: Link into VM's garbage collect SVM range
* list. Protected by VM's garbage collect lock.
@@ -74,7 +76,7 @@ struct xe_pagemap {
*/
static inline bool xe_svm_range_pages_valid(struct xe_svm_range *range)
{
- return drm_gpusvm_range_pages_valid(range->base.gpusvm, &range->base);
+ return drm_gpusvm_pages_valid(range->base.gpusvm, &range->pages);
}
int xe_devm_add(struct xe_tile *tile, struct xe_vram_region *vr);
@@ -132,7 +134,7 @@ void *xe_svm_private_page_owner(struct xe_vm *vm, bool force_smem);
static inline bool xe_svm_range_has_dma_mapping(struct xe_svm_range *range)
{
lockdep_assert_held(&range->base.gpusvm->notifier_lock);
- return range->base.pages.flags.has_dma_mapping;
+ return range->pages.flags.has_dma_mapping;
}
/**
@@ -210,10 +212,10 @@ struct xe_vram_region;
struct xe_svm_range {
struct {
struct interval_tree_node itree;
- struct {
- const struct drm_pagemap_addr *dma_addr;
- } pages;
} base;
+ struct {
+ const struct drm_pagemap_addr *dma_addr;
+ } pages;
u32 tile_present;
u32 tile_invalidated;
};
@@ -233,7 +235,7 @@ static inline
int xe_svm_init(struct xe_vm *vm)
{
#if IS_ENABLED(CONFIG_DRM_GPUSVM)
- return drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM (simple)", &vm->xe->drm,
+ return drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM (simple)",
NULL, 0, 0, 0, NULL, NULL, 0);
#else
return 0;
diff --git a/drivers/gpu/drm/xe/xe_trace.h b/drivers/gpu/drm/xe/xe_trace.h
index 750fa32c13b2..2fe8f89a1e34 100644
--- a/drivers/gpu/drm/xe/xe_trace.h
+++ b/drivers/gpu/drm/xe/xe_trace.h
@@ -213,6 +213,11 @@ DEFINE_EVENT(xe_exec_queue, xe_exec_queue_memory_cat_error,
TP_ARGS(q)
);
+DEFINE_EVENT(xe_exec_queue, xe_guc_uncorrectable_error,
+ TP_PROTO(struct xe_exec_queue *q),
+ TP_ARGS(q)
+);
+
DEFINE_EVENT(xe_exec_queue, xe_exec_queue_cgp_context_error,
TP_PROTO(struct xe_exec_queue *q),
TP_ARGS(q)
diff --git a/drivers/gpu/drm/xe/xe_uc_fw.c b/drivers/gpu/drm/xe/xe_uc_fw.c
index 3f08a3b54062..a8e6f18cc9b4 100644
--- a/drivers/gpu/drm/xe/xe_uc_fw.c
+++ b/drivers/gpu/drm/xe/xe_uc_fw.c
@@ -115,6 +115,7 @@ struct fw_blobs_by_type {
#define XE_GT_TYPE_ANY XE_GT_TYPE_UNINITIALIZED
#define XE_GUC_FIRMWARE_DEFS(fw_def, mmp_ver, major_ver) \
+ fw_def(NOVALAKE_S, GT_TYPE_ANY, major_ver(xe, guc, nvl, 70, 71, 0)) \
fw_def(PANTHERLAKE, GT_TYPE_ANY, major_ver(xe, guc, ptl, 70, 54, 0)) \
fw_def(BATTLEMAGE, GT_TYPE_ANY, major_ver(xe, guc, bmg, 70, 54, 0)) \
fw_def(LUNARLAKE, GT_TYPE_ANY, major_ver(xe, guc, lnl, 70, 53, 0)) \
diff --git a/drivers/gpu/drm/xe/xe_userptr.c b/drivers/gpu/drm/xe/xe_userptr.c
index 1d2ab678faf5..8b2d461ea0b2 100644
--- a/drivers/gpu/drm/xe/xe_userptr.c
+++ b/drivers/gpu/drm/xe/xe_userptr.c
@@ -390,19 +390,20 @@ int xe_userptr_setup(struct xe_userptr_vma *uvma, unsigned long start,
unsigned long range)
{
struct xe_userptr *userptr = &uvma->userptr;
+ struct xe_vm *vm = xe_vma_vm(&uvma->vma);
int err;
INIT_LIST_HEAD(&userptr->invalidate_link);
INIT_LIST_HEAD(&userptr->repin_link);
+ drm_gpusvm_init_pages(&userptr->pages, &vm->xe->drm);
+
err = mmu_interval_notifier_insert(&userptr->notifier, current->mm,
start, range,
&vma_userptr_notifier_ops);
if (err)
return err;
- userptr->pages.notifier_seq = LONG_MAX;
-
return 0;
}
diff --git a/drivers/gpu/drm/xe/xe_vm_madvise.c b/drivers/gpu/drm/xe/xe_vm_madvise.c
index 9e343f9aa44d..0474768a38aa 100644
--- a/drivers/gpu/drm/xe/xe_vm_madvise.c
+++ b/drivers/gpu/drm/xe/xe_vm_madvise.c
@@ -657,7 +657,7 @@ int xe_vm_madvise_ioctl(struct drm_device *dev, void *data, struct drm_file *fil
xe_device_is_l2_flush_optimized(xe) &&
(pat_index != 19 && coh_mode != XE_COH_2WAY))) {
err = -EINVAL;
- goto madv_fini;
+ goto free_vmas;
}
}
diff --git a/drivers/gpu/drm/xe/xe_wa_oob.rules b/drivers/gpu/drm/xe/xe_wa_oob.rules
index 9027365f0043..5d6574ec9dee 100644
--- a/drivers/gpu/drm/xe/xe_wa_oob.rules
+++ b/drivers/gpu/drm/xe/xe_wa_oob.rules
@@ -66,3 +66,8 @@
14025883347 MEDIA_VERSION_RANGE(1301, 3503)
GRAPHICS_VERSION_RANGE(2004, 3005)
16029380221 MEDIA_VERSION(3500)
+22022079272 MEDIA_VERSION(3503)
+ GRAPHICS_VERSION(3510)
+ GRAPHICS_VERSION(3511)
+16029897822 MEDIA_VERSION(3500)
+ GRAPHICS_VERSION(3510)
diff --git a/drivers/gpu/nova-core/fsp.rs b/drivers/gpu/nova-core/fsp.rs
index f0c595175c9c..08f4acef09f6 100644
--- a/drivers/gpu/nova-core/fsp.rs
+++ b/drivers/gpu/nova-core/fsp.rs
@@ -85,16 +85,16 @@ impl FspMessageHeader {
}
}
-/// Complete FSP response structure with MCTP and NVDM headers.
+/// Common FSP response header with MCTP, NVDM and command response payloads.
#[repr(C, packed)]
#[derive(Clone, Copy)]
-struct FspResponse {
+struct FspResponseHeader {
header: FspMessageHeader,
response: NvdmPayloadCommandResponse,
}
-// SAFETY: FspResponse is a packed C struct with only integral fields.
-unsafe impl FromBytes for FspResponse {}
+// SAFETY: FspResponseHeader is a packed C struct with only integral fields.
+unsafe impl FromBytes for FspResponseHeader {}
/// Trait implemented by types representing a message to send to FSP.
///
@@ -273,10 +273,11 @@ impl<'a> Fsp<'a> {
dev_err!(dev, "FSP response error: {:?}\n", e);
})?;
- let (response, _) = FspResponse::from_bytes_prefix(&response_buf[..]).ok_or_else(|| {
- dev_err!(dev, "FSP response too small: {}\n", response_buf.len());
- EIO
- })?;
+ let (response, _) =
+ FspResponseHeader::from_bytes_prefix(&response_buf[..]).ok_or_else(|| {
+ dev_err!(dev, "FSP response too small: {}\n", response_buf.len());
+ EIO
+ })?;
let mctp_header = response.header.mctp_header;
let nvdm_header = response.header.nvdm_header;
diff --git a/drivers/gpu/nova-core/gsp/boot.rs b/drivers/gpu/nova-core/gsp/boot.rs
index ab0491b57944..152093aafae6 100644
--- a/drivers/gpu/nova-core/gsp/boot.rs
+++ b/drivers/gpu/nova-core/gsp/boot.rs
@@ -135,7 +135,7 @@ impl super::Gsp {
self.cmdq
.send_command_no_wait(bar, commands::SetSystemInfo::new(pdev, chipset))?;
self.cmdq
- .send_command_no_wait(bar, commands::SetRegistry::new())?;
+ .send_command_no_wait(bar, commands::SetRegistry::new()?)?;
hal.post_boot(&self, &ctx, &gsp_fw)?;
diff --git a/drivers/gpu/nova-core/gsp/commands.rs b/drivers/gpu/nova-core/gsp/commands.rs
index 86a3747cd31c..08380de39048 100644
--- a/drivers/gpu/nova-core/gsp/commands.rs
+++ b/drivers/gpu/nova-core/gsp/commands.rs
@@ -67,37 +67,44 @@ struct RegistryEntry {
/// The `SetRegistry` command.
pub(crate) struct SetRegistry {
- entries: [RegistryEntry; Self::NUM_ENTRIES],
+ entries: KVec<RegistryEntry>,
}
impl SetRegistry {
- // For now we hard-code the registry entries. Future work will allow others to
- // be added as module parameters.
- const NUM_ENTRIES: usize = 3;
-
/// Creates a new `SetRegistry` command, using a set of hardcoded entries.
- pub(crate) fn new() -> Self {
- Self {
- entries: [
- // RMSecBusResetEnable - enables PCI secondary bus reset
- RegistryEntry {
- key: "RMSecBusResetEnable",
- value: 1,
- },
- // RMForcePcieConfigSave - forces GSP-RM to preserve PCI configuration registers on
- // any PCI reset.
- RegistryEntry {
- key: "RMForcePcieConfigSave",
- value: 1,
- },
- // RMDevidCheckIgnore - allows GSP-RM to boot even if the PCI dev ID is not found
- // in the internal product name database.
- RegistryEntry {
- key: "RMDevidCheckIgnore",
- value: 1,
- },
- ],
- }
+ pub(crate) fn new() -> Result<Self> {
+ let mut entries = KVec::new();
+
+ // RMSecBusResetEnable - enables PCI secondary bus reset
+ entries.push(
+ RegistryEntry {
+ key: "RMSecBusResetEnable",
+ value: 1,
+ },
+ GFP_KERNEL,
+ )?;
+
+ // RMForcePcieConfigSave - forces GSP-RM to preserve PCI configuration registers on
+ // any PCI reset.
+ entries.push(
+ RegistryEntry {
+ key: "RMForcePcieConfigSave",
+ value: 1,
+ },
+ GFP_KERNEL,
+ )?;
+
+ // RMDevidCheckIgnore - allows GSP-RM to boot even if the PCI dev ID is not found
+ // in the internal product name database.
+ entries.push(
+ RegistryEntry {
+ key: "RMDevidCheckIgnore",
+ value: 1,
+ },
+ GFP_KERNEL,
+ )?;
+
+ Ok(Self { entries })
}
}
@@ -108,15 +115,18 @@ impl CommandToGsp for SetRegistry {
type InitError = Infallible;
fn init(&self) -> impl Init<Self::Command, Self::InitError> {
- Self::Command::init(Self::NUM_ENTRIES as u32, self.variable_payload_len() as u32)
+ Self::Command::init(
+ self.entries.len() as u32,
+ self.variable_payload_len() as u32,
+ )
}
fn variable_payload_len(&self) -> usize {
let mut key_size = 0;
- for i in 0..Self::NUM_ENTRIES {
- key_size += self.entries[i].key.len() + 1; // +1 for NULL terminator
+ for entry in self.entries.iter() {
+ key_size += entry.key.len() + 1; // +1 for NULL terminator
}
- Self::NUM_ENTRIES * size_of::<fw::commands::PackedRegistryEntry>() + key_size
+ self.entries.len() * size_of::<fw::commands::PackedRegistryEntry>() + key_size
}
fn init_variable_payload(
@@ -124,12 +134,12 @@ impl CommandToGsp for SetRegistry {
dst: &mut SBufferIter<core::array::IntoIter<&mut [u8], 2>>,
) -> Result {
let string_data_start_offset = size_of::<Self::Command>()
- + Self::NUM_ENTRIES * size_of::<fw::commands::PackedRegistryEntry>();
+ + self.entries.len() * size_of::<fw::commands::PackedRegistryEntry>();
// Array for string data.
let mut string_data = KVec::new();
- for entry in self.entries.iter().take(Self::NUM_ENTRIES) {
+ for entry in self.entries.iter() {
dst.write_all(
fw::commands::PackedRegistryEntry::new(
(string_data_start_offset + string_data.len()) as u32,
diff --git a/drivers/hwmon/iio_hwmon.c b/drivers/hwmon/iio_hwmon.c
index fc17ad93a376..6502e20517a8 100644
--- a/drivers/hwmon/iio_hwmon.c
+++ b/drivers/hwmon/iio_hwmon.c
@@ -221,3 +221,4 @@ module_platform_driver(iio_hwmon_driver);
MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
MODULE_DESCRIPTION("IIO to hwmon driver");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c
index 1ac0288fbbd8..4fa7f522f245 100644
--- a/drivers/hwmon/ntc_thermistor.c
+++ b/drivers/hwmon/ntc_thermistor.c
@@ -748,3 +748,4 @@ MODULE_DESCRIPTION("NTC Thermistor Driver");
MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:ntc-thermistor");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c
index 0f478f142400..eb521125f4eb 100644
--- a/drivers/iio/accel/hid-sensor-accel-3d.c
+++ b/drivers/iio/accel/hid-sensor-accel-3d.c
@@ -121,9 +121,8 @@ static const struct iio_chan_spec gravity_channels[] = {
/* Channel read_raw handler */
static int accel_3d_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int *val, int *val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
{
struct accel_3d_state *accel_state = iio_priv(indio_dev);
int report_id = -1;
@@ -150,7 +149,7 @@ static int accel_3d_read_raw(struct iio_dev *indio_dev,
else {
*val = 0;
hid_sensor_power_state(&accel_state->common_attributes,
- false);
+ false);
return -EINVAL;
}
hid_sensor_power_state(&accel_state->common_attributes, false);
@@ -183,10 +182,8 @@ static int accel_3d_read_raw(struct iio_dev *indio_dev,
/* Channel write_raw handler */
static int accel_3d_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val,
- int val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
{
struct accel_3d_state *accel_state = iio_priv(indio_dev);
int ret = 0;
@@ -222,8 +219,7 @@ static void hid_sensor_push_data(struct iio_dev *indio_dev, void *data,
/* Callback handler to send event after all samples are received and captured */
static int accel_3d_proc_event(struct hid_sensor_hub_device *hsdev,
- u32 usage_id,
- void *priv)
+ u32 usage_id, void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct accel_3d_state *accel_state = iio_priv(indio_dev);
@@ -246,9 +242,9 @@ static int accel_3d_proc_event(struct hid_sensor_hub_device *hsdev,
/* Capture samples in local storage */
static int accel_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
- u32 usage_id,
- size_t raw_len, char *raw_data,
- void *priv)
+ u32 usage_id,
+ size_t raw_len, char *raw_data,
+ void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct accel_3d_state *accel_state = iio_priv(indio_dev);
@@ -280,10 +276,10 @@ static int accel_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
/* Parse report which is specific to an usage id*/
static int accel_3d_parse_report(struct platform_device *pdev,
- struct hid_sensor_hub_device *hsdev,
- struct iio_chan_spec *channels,
- u32 usage_id,
- struct accel_3d_state *st)
+ struct hid_sensor_hub_device *hsdev,
+ struct iio_chan_spec *channels,
+ u32 usage_id,
+ struct accel_3d_state *st)
{
int ret;
@@ -302,10 +298,10 @@ static int accel_3d_parse_report(struct platform_device *pdev,
};
}
dev_dbg(&pdev->dev, "accel_3d %x:%x, %x:%x, %x:%x\n",
- st->accel[0].index,
- st->accel[0].report_id,
- st->accel[1].index, st->accel[1].report_id,
- st->accel[2].index, st->accel[2].report_id);
+ st->accel[0].index,
+ st->accel[0].report_id,
+ st->accel[1].index, st->accel[1].report_id,
+ st->accel[2].index, st->accel[2].report_id);
st->scale_precision = hid_sensor_format_scale(
hsdev->usage,
@@ -328,7 +324,7 @@ static int hid_accel_3d_probe(struct platform_device *pdev)
indio_dev = devm_iio_device_alloc(&pdev->dev,
sizeof(struct accel_3d_state));
- if (indio_dev == NULL)
+ if (!indio_dev)
return -ENOMEM;
platform_set_drvdata(pdev, indio_dev);
@@ -365,8 +361,8 @@ static int hid_accel_3d_probe(struct platform_device *pdev)
return -ENOMEM;
}
ret = accel_3d_parse_report(pdev, hsdev,
- (struct iio_chan_spec *)indio_dev->channels,
- hsdev->usage, accel_state);
+ (struct iio_chan_spec *)indio_dev->channels,
+ hsdev->usage, accel_state);
if (ret) {
dev_err(&pdev->dev, "failed to setup attributes\n");
return ret;
@@ -379,32 +375,32 @@ static int hid_accel_3d_probe(struct platform_device *pdev)
atomic_set(&accel_state->common_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name,
- &accel_state->common_attributes);
+ &accel_state->common_attributes);
if (ret < 0) {
dev_err(&pdev->dev, "trigger setup failed\n");
return ret;
}
- ret = iio_device_register(indio_dev);
- if (ret) {
- dev_err(&pdev->dev, "device register failed\n");
- goto error_remove_trigger;
- }
-
accel_state->callbacks.send_event = accel_3d_proc_event;
accel_state->callbacks.capture_sample = accel_3d_capture_sample;
accel_state->callbacks.pdev = pdev;
ret = sensor_hub_register_callback(hsdev, hsdev->usage,
- &accel_state->callbacks);
+ &accel_state->callbacks);
if (ret < 0) {
dev_err(&pdev->dev, "callback reg failed\n");
- goto error_iio_unreg;
+ goto error_remove_trigger;
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "device register failed\n");
+ goto error_remove_callback;
}
return ret;
-error_iio_unreg:
- iio_device_unregister(indio_dev);
+error_remove_callback:
+ sensor_hub_remove_callback(hsdev, hsdev->usage);
error_remove_trigger:
hid_sensor_remove_trigger(indio_dev, &accel_state->common_attributes);
return ret;
@@ -417,8 +413,8 @@ static void hid_accel_3d_remove(struct platform_device *pdev)
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct accel_3d_state *accel_state = iio_priv(indio_dev);
- sensor_hub_remove_callback(hsdev, hsdev->usage);
iio_device_unregister(indio_dev);
+ sensor_hub_remove_callback(hsdev, hsdev->usage);
hid_sensor_remove_trigger(indio_dev, &accel_state->common_attributes);
}
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index bc21034078b5..d1d6ca27cce1 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -1077,6 +1077,7 @@ config MAX1363
config MAX14001
tristate "Analog Devices MAX14001/MAX14002 ADC driver"
depends on SPI
+ select REGMAP
help
Say yes here to build support for Analog Devices MAX14001/MAX14002
Configurable, Isolated 10-bit ADCs for Multi-Range Binary Inputs.
@@ -1087,6 +1088,7 @@ config MAX14001
config MAX34408
tristate "Maxim max34408/max344089 ADC driver"
depends on I2C
+ select REGMAP_I2C
help
Say yes here to build support for Maxim max34408/max34409 current sense
monitor with 8-bits ADC interface with overcurrent delay/threshold and
@@ -1166,6 +1168,17 @@ config MCP3911
This driver can also be built as a module. If so, the module will be
called mcp3911.
+config MEDIATEK_MT6323_AUXADC
+ tristate "MediaTek MT6323 PMIC AUXADC driver"
+ depends on MFD_MT6397
+ help
+ Say yes here to enable support for MediaTek MT6323 PMIC Auxiliary ADC.
+ This driver provides multiple channels for system monitoring,
+ such as battery voltage, PMIC temperature, and others.
+
+ This driver can also be built as a module. If so, the module will be
+ called mt6323-auxadc.
+
config MEDIATEK_MT6359_AUXADC
tristate "MediaTek MT6359 PMIC AUXADC driver"
depends on MFD_MT6397
@@ -1965,6 +1978,39 @@ config TWL6030_GPADC
This driver can also be built as a module. If so, the module will be
called twl6030-gpadc.
+config VERSAL_SYSMON_CORE
+ tristate
+ select REGMAP
+
+config VERSAL_SYSMON
+ tristate "AMD Versal SysMon driver"
+ depends on ARCH_ZYNQMP || COMPILE_TEST
+ depends on HAS_IOMEM
+ select VERSAL_SYSMON_CORE
+ help
+ Say yes here to have support for the AMD/Xilinx Versal System
+ Monitor (SysMon). This driver provides voltage and temperature
+ monitoring through the IIO subsystem.
+
+ The SysMon measures up to 160 supply voltages and reads up to
+ 64 temperature satellites distributed across the SoC.
+
+ To compile this driver as a module, choose M here: the module
+ will be called versal-sysmon.
+
+config VERSAL_SYSMON_I2C
+ tristate "AMD Versal SysMon I2C driver"
+ depends on I2C
+ select VERSAL_SYSMON_CORE
+ help
+ Say yes here to have support for the AMD/Xilinx Versal System
+ Monitor (SysMon) via I2C interface. This driver enables voltage
+ and temperature monitoring when the Versal chip has SysMon
+ configured with I2C access.
+
+ To compile this driver as a module, choose M here: the module
+ will be called versal-sysmon-i2c.
+
config VF610_ADC
tristate "Freescale vf610 ADC driver"
depends on HAS_IOMEM
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 707dd708912f..0f90b75577ff 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -100,6 +100,7 @@ obj-$(CONFIG_MCP320X) += mcp320x.o
obj-$(CONFIG_MCP3422) += mcp3422.o
obj-$(CONFIG_MCP3564) += mcp3564.o
obj-$(CONFIG_MCP3911) += mcp3911.o
+obj-$(CONFIG_MEDIATEK_MT6323_AUXADC) += mt6323-auxadc.o
obj-$(CONFIG_MEDIATEK_MT6359_AUXADC) += mt6359-auxadc.o
obj-$(CONFIG_MEDIATEK_MT6360_ADC) += mt6360-adc.o
obj-$(CONFIG_MEDIATEK_MT6370_ADC) += mt6370-adc.o
@@ -168,6 +169,9 @@ obj-$(CONFIG_TI_TLC4541) += ti-tlc4541.o
obj-$(CONFIG_TI_TSC2046) += ti-tsc2046.o
obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o
+obj-$(CONFIG_VERSAL_SYSMON_CORE) += versal-sysmon-core.o
+obj-$(CONFIG_VERSAL_SYSMON) += versal-sysmon.o
+obj-$(CONFIG_VERSAL_SYSMON_I2C) += versal-sysmon-i2c.o
obj-$(CONFIG_VF610_ADC) += vf610_adc.o
obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o
obj-$(CONFIG_XILINX_AMS) += xilinx-ams.o
diff --git a/drivers/iio/adc/ad7779.c b/drivers/iio/adc/ad7779.c
index 003e23d6e242..79fb38d0f400 100644
--- a/drivers/iio/adc/ad7779.c
+++ b/drivers/iio/adc/ad7779.c
@@ -142,7 +142,6 @@ struct ad7779_state {
const struct ad7779_chip_info *chip_info;
struct clk *mclk;
struct iio_trigger *trig;
- struct completion completion;
unsigned int sampling_freq;
enum ad7779_filter filter_enabled;
struct iio_backend *back;
@@ -842,8 +841,7 @@ static int ad7779_setup_without_backend(struct ad7779_state *st, struct iio_dev
IRQF_NO_THREAD | IRQF_NO_AUTOEN, indio_dev->name,
st->trig);
if (ret)
- return dev_err_probe(dev, ret, "request IRQ %d failed\n",
- st->spi->irq);
+ return ret;
ret = devm_iio_trigger_register(dev, st->trig);
if (ret)
@@ -851,8 +849,6 @@ static int ad7779_setup_without_backend(struct ad7779_state *st, struct iio_dev
indio_dev->trig = iio_trigger_get(st->trig);
- init_completion(&st->completion);
-
ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
&iio_pollfunc_store_time,
&ad7779_trigger_handler,
diff --git a/drivers/iio/adc/ade9000.c b/drivers/iio/adc/ade9000.c
index b80cdd8ad982..c6c3ea953fea 100644
--- a/drivers/iio/adc/ade9000.c
+++ b/drivers/iio/adc/ade9000.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/**
+/*
* ADE9000 driver
*
* Copyright 2025 Analog Devices Inc.
diff --git a/drivers/iio/adc/envelope-detector.c b/drivers/iio/adc/envelope-detector.c
index 30672e584c10..aace7e103770 100644
--- a/drivers/iio/adc/envelope-detector.c
+++ b/drivers/iio/adc/envelope-detector.c
@@ -405,3 +405,4 @@ module_platform_driver(envelope_detector_driver);
MODULE_DESCRIPTION("Envelope detector using a DAC and a comparator");
MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/iio/adc/max1241.c b/drivers/iio/adc/max1241.c
index fb7f53316e3d..b3cecbf9a89e 100644
--- a/drivers/iio/adc/max1241.c
+++ b/drivers/iio/adc/max1241.c
@@ -175,6 +175,7 @@ static const struct spi_device_id max1241_id[] = {
{ .name = "max1241" },
{ }
};
+MODULE_DEVICE_TABLE(spi, max1241_id);
static const struct of_device_id max1241_dt_ids[] = {
{ .compatible = "maxim,max1241" },
diff --git a/drivers/iio/adc/mt6323-auxadc.c b/drivers/iio/adc/mt6323-auxadc.c
new file mode 100644
index 000000000000..c450fb6f09cb
--- /dev/null
+++ b/drivers/iio/adc/mt6323-auxadc.c
@@ -0,0 +1,314 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2026 Roman Vivchar <rva333@protonmail.com>
+ *
+ * Based on drivers/iio/adc/mt6359-auxadc.c
+ */
+
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/cleanup.h>
+#include <linux/delay.h>
+#include <linux/iio/iio.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/stringify.h>
+#include <linux/time.h>
+#include <linux/types.h>
+
+#include <linux/mfd/mt6323/registers.h>
+
+#include <dt-bindings/iio/adc/mediatek,mt6323-auxadc.h>
+
+#define AUXADC_STRUP_CON10_RSTB_SEL BIT(7)
+#define AUXADC_STRUP_CON10_RSTB_SW BIT(5)
+
+#define AUXADC_TOP_CKPDN2_CTL_CK BIT(5)
+
+#define AUXADC_TRIM_CH2_MASK GENMASK(11, 10)
+#define AUXADC_TRIM_CH4_MASK GENMASK(9, 8)
+#define AUXADC_TRIM_CH5_MASK GENMASK(5, 4)
+#define AUXADC_TRIM_CH6_MASK GENMASK(3, 2)
+
+#define AUXADC_CON27_VREF18_ENB_MD BIT(15)
+#define AUXADC_CON27_MD_STATUS BIT(0)
+
+#define AUXADC_CON19_GPS_STATUS BIT(1)
+
+#define AUXADC_CON26_VREF18_SELB BIT(1)
+#define AUXADC_CON26_DECI_GDLY_SEL BIT(0)
+
+#define AUXADC_CON11_VBUF_EN BIT(4)
+
+#define AUXADC_CON19_DECI_GDLY_MASK GENMASK(15, 14)
+#define AUXADC_ADC19_BUSY_MASK GENMASK(15, 1)
+#define AUXADC_READY_MASK BIT(15)
+#define AUXADC_DATA_MASK GENMASK(14, 0)
+
+#define AUXADC_CON9_OSR_MASK GENMASK(12, 10)
+#define AUXADC_DEFAULT_OSR 3
+
+#define MTK_PMIC_IIO_CHAN(_name, _chan, _addr) \
+{ \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = _chan, \
+ .address = _addr, \
+ .datasheet_name = __stringify(_name), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
+}
+
+/*
+ * AUXADC reports everything in mV, including temperature and
+ * current channels. Channel macros are mapped such that their
+ * ID matches their respective hardware bit position in CON22.
+ */
+static const struct iio_chan_spec mt6323_auxadc_channels[] = {
+ MTK_PMIC_IIO_CHAN(baton2, MT6323_AUXADC_BATON2, MT6323_AUXADC_ADC6),
+ MTK_PMIC_IIO_CHAN(ch6, MT6323_AUXADC_CH6, MT6323_AUXADC_ADC11),
+ MTK_PMIC_IIO_CHAN(bat_temp, MT6323_AUXADC_BAT_TEMP, MT6323_AUXADC_ADC5),
+ MTK_PMIC_IIO_CHAN(chip_temp, MT6323_AUXADC_CHIP_TEMP, MT6323_AUXADC_ADC4),
+ MTK_PMIC_IIO_CHAN(vcdt, MT6323_AUXADC_VCDT, MT6323_AUXADC_ADC2),
+ MTK_PMIC_IIO_CHAN(baton1, MT6323_AUXADC_BATON1, MT6323_AUXADC_ADC3),
+ MTK_PMIC_IIO_CHAN(isense, MT6323_AUXADC_ISENSE, MT6323_AUXADC_ADC1),
+ MTK_PMIC_IIO_CHAN(batsns, MT6323_AUXADC_BATSNS, MT6323_AUXADC_ADC0),
+ MTK_PMIC_IIO_CHAN(accdet, MT6323_AUXADC_ACCDET, MT6323_AUXADC_ADC7),
+};
+
+/*
+ * The MediaTek MT6323 (as well as a lot of other PMICs) has the following hierarchy:
+ * PMIC AUXADC <- PMIC MFD <- SoC PWRAP (wrapper for PWRAP FSM)
+ *
+ * Therefore, PWRAP regmap should be obtained using dev->parent->parent.
+ */
+struct mt6323_auxadc {
+ struct regmap *regmap;
+ /* AUXADC doesn't support reading multiple channels simultaneously. */
+ struct mutex lock;
+};
+
+static int mt6323_auxadc_prepare_channel(struct mt6323_auxadc *auxadc)
+{
+ struct regmap *map = auxadc->regmap;
+ u32 val;
+ int ret;
+
+ ret = regmap_read(map, MT6323_AUXADC_CON19, &val);
+ if (ret)
+ return ret;
+
+ /* The ADC is idle. */
+ if (!(val & AUXADC_CON19_DECI_GDLY_MASK))
+ return 0;
+
+ ret = regmap_read_poll_timeout(map, MT6323_AUXADC_ADC19,
+ val, !(val & AUXADC_ADC19_BUSY_MASK),
+ 10, 500);
+ if (ret)
+ return ret;
+
+ return regmap_clear_bits(map, MT6323_AUXADC_CON19,
+ AUXADC_CON19_DECI_GDLY_MASK);
+}
+
+static int mt6323_auxadc_request(struct mt6323_auxadc *auxadc,
+ unsigned long channel)
+{
+ struct regmap *map = auxadc->regmap;
+ int ret;
+
+ ret = regmap_set_bits(map, MT6323_AUXADC_CON11, AUXADC_CON11_VBUF_EN);
+ if (ret)
+ return ret;
+
+ return regmap_set_bits(map, MT6323_AUXADC_CON22, BIT(channel));
+}
+
+static int mt6323_auxadc_release(struct mt6323_auxadc *auxadc,
+ unsigned long channel)
+{
+ struct regmap *map = auxadc->regmap;
+ int ret;
+
+ ret = regmap_clear_bits(map, MT6323_AUXADC_CON22, BIT(channel));
+ if (ret)
+ return ret;
+
+ return regmap_clear_bits(map, MT6323_AUXADC_CON11, AUXADC_CON11_VBUF_EN);
+}
+
+static int mt6323_auxadc_read(struct mt6323_auxadc *auxadc,
+ const struct iio_chan_spec *chan, int *out)
+{
+ struct regmap *map = auxadc->regmap;
+ u32 val;
+ int ret;
+
+ ret = regmap_read_poll_timeout(map, chan->address,
+ val, (val & AUXADC_READY_MASK),
+ 1 * USEC_PER_MSEC, 100 * USEC_PER_MSEC);
+ if (ret)
+ return ret;
+
+ *out = FIELD_GET(AUXADC_DATA_MASK, val);
+
+ return 0;
+}
+
+static int mt6323_auxadc_read_raw(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ int *val, int *val2, long mask)
+{
+ struct mt6323_auxadc *auxadc = iio_priv(indio_dev);
+ int ret, mult;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ if (chan->channel == MT6323_AUXADC_ISENSE ||
+ chan->channel == MT6323_AUXADC_BATSNS)
+ mult = 4;
+ else
+ mult = 1;
+
+ /* 1800mV full range with 15-bit resolution. */
+ *val = mult * 1800;
+ *val2 = 15;
+
+ return IIO_VAL_FRACTIONAL_LOG2;
+ case IIO_CHAN_INFO_RAW: {
+ guard(mutex)(&auxadc->lock);
+
+ ret = mt6323_auxadc_prepare_channel(auxadc);
+ if (ret)
+ return ret;
+
+ ret = mt6323_auxadc_request(auxadc, chan->channel);
+ if (ret)
+ return ret;
+
+ /* Hardware limitation: the AUXADC needs a delay to become ready. */
+ fsleep(300);
+
+ ret = mt6323_auxadc_read(auxadc, chan, val);
+
+ if (mt6323_auxadc_release(auxadc, chan->channel))
+ dev_err(&indio_dev->dev,
+ "failed to release channel %d\n", chan->channel);
+
+ if (ret)
+ return ret;
+
+ return IIO_VAL_INT;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mt6323_auxadc_init(struct mt6323_auxadc *auxadc)
+{
+ struct regmap *map = auxadc->regmap;
+ int ret;
+
+ ret = regmap_set_bits(map, MT6323_STRUP_CON10,
+ AUXADC_STRUP_CON10_RSTB_SW |
+ AUXADC_STRUP_CON10_RSTB_SEL);
+ if (ret)
+ return ret;
+
+ ret = regmap_set_bits(map, MT6323_TOP_CKPDN2, AUXADC_TOP_CKPDN2_CTL_CK);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(map, MT6323_AUXADC_CON10,
+ AUXADC_TRIM_CH2_MASK | AUXADC_TRIM_CH4_MASK |
+ AUXADC_TRIM_CH5_MASK | AUXADC_TRIM_CH6_MASK,
+ FIELD_PREP(AUXADC_TRIM_CH2_MASK, 1) |
+ FIELD_PREP(AUXADC_TRIM_CH4_MASK, 1) |
+ FIELD_PREP(AUXADC_TRIM_CH5_MASK, 1) |
+ FIELD_PREP(AUXADC_TRIM_CH6_MASK, 1));
+ if (ret)
+ return ret;
+
+ ret = regmap_set_bits(map, MT6323_AUXADC_CON27,
+ AUXADC_CON27_VREF18_ENB_MD |
+ AUXADC_CON27_MD_STATUS);
+ if (ret)
+ return ret;
+
+ ret = regmap_set_bits(map, MT6323_AUXADC_CON19, AUXADC_CON19_GPS_STATUS);
+ if (ret)
+ return ret;
+
+ ret = regmap_set_bits(map, MT6323_AUXADC_CON26,
+ AUXADC_CON26_VREF18_SELB |
+ AUXADC_CON26_DECI_GDLY_SEL);
+ if (ret)
+ return ret;
+
+ return regmap_update_bits(map, MT6323_AUXADC_CON9, AUXADC_CON9_OSR_MASK,
+ FIELD_PREP(AUXADC_CON9_OSR_MASK, AUXADC_DEFAULT_OSR));
+}
+
+static const struct iio_info mt6323_auxadc_iio_info = {
+ .read_raw = mt6323_auxadc_read_raw,
+};
+
+static int mt6323_auxadc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mt6323_auxadc *auxadc;
+ struct regmap *regmap;
+ struct iio_dev *iio;
+ int ret;
+
+ regmap = dev_get_regmap(dev->parent->parent, NULL);
+ if (!regmap)
+ return dev_err_probe(dev, -ENODEV, "failed to get regmap\n");
+
+ iio = devm_iio_device_alloc(dev, sizeof(*auxadc));
+ if (!iio)
+ return -ENOMEM;
+
+ auxadc = iio_priv(iio);
+ auxadc->regmap = regmap;
+
+ ret = devm_mutex_init(dev, &auxadc->lock);
+ if (ret)
+ return ret;
+
+ ret = mt6323_auxadc_init(auxadc);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to initialize auxadc\n");
+
+ iio->name = "mt6323-auxadc";
+ iio->info = &mt6323_auxadc_iio_info;
+ iio->modes = INDIO_DIRECT_MODE;
+ iio->channels = mt6323_auxadc_channels;
+ iio->num_channels = ARRAY_SIZE(mt6323_auxadc_channels);
+
+ return devm_iio_device_register(dev, iio);
+}
+
+static const struct of_device_id mt6323_auxadc_of_match[] = {
+ { .compatible = "mediatek,mt6323-auxadc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mt6323_auxadc_of_match);
+
+static struct platform_driver mt6323_auxadc_driver = {
+ .driver = {
+ .name = "mt6323-auxadc",
+ .of_match_table = mt6323_auxadc_of_match,
+ },
+ .probe = mt6323_auxadc_probe,
+};
+module_platform_driver(mt6323_auxadc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MediaTek MT6323 PMIC AUXADC Driver");
diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c
index e33a2f4bf66c..2df8f1c21c2a 100644
--- a/drivers/iio/adc/ti-adc081c.c
+++ b/drivers/iio/adc/ti-adc081c.c
@@ -189,10 +189,8 @@ static int adc081c_probe(struct i2c_client *client)
err = devm_iio_triggered_buffer_setup(&client->dev, iio, NULL,
adc081c_trigger_handler, NULL);
- if (err < 0) {
- dev_err(&client->dev, "iio triggered buffer setup failed\n");
- return err;
- }
+ if (err < 0)
+ return dev_err_probe(&client->dev, err, "iio triggered buffer setup failed\n");
return devm_iio_device_register(&client->dev, iio);
}
diff --git a/drivers/iio/adc/ti-adc084s021.c b/drivers/iio/adc/ti-adc084s021.c
index b08a5de9b6b2..cf2f6ee59411 100644
--- a/drivers/iio/adc/ti-adc084s021.c
+++ b/drivers/iio/adc/ti-adc084s021.c
@@ -228,10 +228,8 @@ static int adc084s021_probe(struct spi_device *spi)
ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, NULL,
adc084s021_buffer_trigger_handler,
&adc084s021_buffer_setup_ops);
- if (ret) {
- dev_err(&spi->dev, "Failed to setup triggered buffer\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(&spi->dev, ret, "Failed to setup triggered buffer\n");
return devm_iio_device_register(&spi->dev, indio_dev);
}
diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c
index 8a272af69f7d..0fbfa4e499aa 100644
--- a/drivers/iio/adc/ti-ads1015.c
+++ b/drivers/iio/adc/ti-ads1015.c
@@ -930,6 +930,17 @@ static int ads1015_set_conv_mode(struct ads1015_data *data, int mode)
mode << ADS1015_CFG_MOD_SHIFT);
}
+static void ads1015_power_down(void *p)
+{
+ struct ads1015_data *data = p;
+ int ret;
+
+ ret = ads1015_set_conv_mode(data, ADS1015_SINGLESHOT);
+ if (ret)
+ dev_warn(regmap_get_device(data->regmap),
+ "Failed to power down (%pe)\n", ERR_PTR(ret));
+}
+
static int ads1015_probe(struct i2c_client *client)
{
const struct ads1015_chip_data *chip;
@@ -1030,6 +1041,10 @@ static int ads1015_probe(struct i2c_client *client)
if (ret)
return ret;
+ ret = devm_add_action_or_reset(&client->dev, ads1015_power_down, data);
+ if (ret)
+ return ret;
+
data->conv_invalid = true;
ret = pm_runtime_set_active(&client->dev);
@@ -1037,33 +1052,11 @@ static int ads1015_probe(struct i2c_client *client)
return ret;
pm_runtime_set_autosuspend_delay(&client->dev, ADS1015_SLEEP_DELAY_MS);
pm_runtime_use_autosuspend(&client->dev);
- pm_runtime_enable(&client->dev);
-
- ret = iio_device_register(indio_dev);
- if (ret < 0) {
- dev_err(&client->dev, "Failed to register IIO device\n");
+ ret = devm_pm_runtime_enable(&client->dev);
+ if (ret)
return ret;
- }
-
- return 0;
-}
-static void ads1015_remove(struct i2c_client *client)
-{
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
- struct ads1015_data *data = iio_priv(indio_dev);
- int ret;
-
- iio_device_unregister(indio_dev);
-
- pm_runtime_disable(&client->dev);
- pm_runtime_set_suspended(&client->dev);
-
- /* power down single shot mode */
- ret = ads1015_set_conv_mode(data, ADS1015_SINGLESHOT);
- if (ret)
- dev_warn(&client->dev, "Failed to power down (%pe)\n",
- ERR_PTR(ret));
+ return devm_iio_device_register(&client->dev, indio_dev);
}
#ifdef CONFIG_PM
@@ -1150,7 +1143,6 @@ static struct i2c_driver ads1015_driver = {
.pm = &ads1015_pm_ops,
},
.probe = ads1015_probe,
- .remove = ads1015_remove,
.id_table = ads1015_id,
};
diff --git a/drivers/iio/adc/versal-sysmon-core.c b/drivers/iio/adc/versal-sysmon-core.c
new file mode 100644
index 000000000000..1b55d343982e
--- /dev/null
+++ b/drivers/iio/adc/versal-sysmon-core.c
@@ -0,0 +1,1052 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * AMD Versal SysMon core driver
+ *
+ * Copyright (C) 2019 - 2022, Xilinx, Inc.
+ * Copyright (C) 2022 - 2026, Advanced Micro Devices, Inc.
+ */
+
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/cleanup.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/limits.h>
+#include <linux/minmax.h>
+#include <linux/module.h>
+#include <linux/overflow.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/string.h>
+#include <linux/sysfs.h>
+#include <linux/units.h>
+
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+
+#include "versal-sysmon.h"
+
+/*
+ * Oversampling ratio values exposed to userspace via IIO.
+ * Actual number of samples averaged: 1=none, 2=2x, 4=4x, 8=8x, 16=16x.
+ */
+static const int sysmon_oversampling_avail[] = { 1, 2, 4, 8, 16 };
+
+/* TEMP hysteresis mode bit in SYSMON_TEMP_EV_CFG */
+#define SYSMON_TEMP_HYST_MASK BIT(1)
+
+/* Compute alarm register offset from a channel address */
+#define SYSMON_ALARM_OFFSET(addr) \
+ (SYSMON_ALARM_REG + ((addr) / SYSMON_ALARM_BITS_PER_REG) * SYSMON_REG_STRIDE)
+
+#define SYSMON_CHAN_TEMP(_chan, _address, _name) \
+{ \
+ .type = IIO_TEMP, \
+ .indexed = 1, \
+ .address = _address, \
+ .channel = _chan, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+ .info_mask_shared_by_type_available = \
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+ .datasheet_name = _name, \
+}
+
+enum sysmon_alarm_bit {
+ SYSMON_BIT_ALARM0 = 0,
+ SYSMON_BIT_ALARM1 = 1,
+ SYSMON_BIT_ALARM2 = 2,
+ SYSMON_BIT_ALARM3 = 3,
+ SYSMON_BIT_ALARM4 = 4,
+ SYSMON_BIT_TEMP = 9,
+};
+
+/* Temperature event specification: rising threshold + hysteresis only */
+static const struct iio_event_spec sysmon_temp_events[] = {
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_RISING,
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE) |
+ BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_HYSTERESIS),
+ },
+};
+
+/* Supply event specifications */
+static const struct iio_event_spec sysmon_supply_events[] = {
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_RISING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
+ },
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_FALLING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
+ },
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_EITHER,
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE),
+ },
+};
+
+/*
+ * Static temperature channels (always present).
+ *
+ * These are hardware-computed aggregate registers across all active
+ * temperature satellites:
+ * temp: current max temperature across all active satellites
+ * min: current min temperature across all active satellites
+ * max_max: highest peak recorded since last hardware reset
+ * min_min: lowest trough recorded since last hardware reset
+ */
+static const struct iio_chan_spec temp_channels[] = {
+ SYSMON_CHAN_TEMP(0, SYSMON_TEMP_MAX, "temp"),
+ SYSMON_CHAN_TEMP(1, SYSMON_TEMP_MIN, "min"),
+ SYSMON_CHAN_TEMP(2, SYSMON_TEMP_MAX_MAX, "max_max"),
+ SYSMON_CHAN_TEMP(3, SYSMON_TEMP_MIN_MIN, "min_min"),
+};
+
+static void sysmon_q8p7_to_millicelsius(s16 raw_data, int *val)
+{
+ *val = (raw_data * MILLIDEGREE_PER_DEGREE) >> SYSMON_FRACTIONAL_SHIFT;
+}
+
+static void sysmon_millicelsius_to_q8p7(u32 *raw_data, int val)
+{
+ *raw_data = (val << SYSMON_FRACTIONAL_SHIFT) / MILLIDEGREE_PER_DEGREE;
+}
+
+static void sysmon_supply_rawtoprocessed(int raw_data, int *val)
+{
+ int mantissa, format, exponent;
+
+ mantissa = FIELD_GET(SYSMON_MANTISSA_MASK, raw_data);
+ exponent = SYSMON_SUPPLY_MANTISSA_BITS - FIELD_GET(SYSMON_MODE_MASK, raw_data);
+ format = FIELD_GET(SYSMON_FMT_MASK, raw_data);
+ /*
+ * When format bit is set the mantissa is two's complement
+ * (per hardware spec); sign-extend to int for correct arithmetic.
+ */
+ if (format)
+ mantissa = sign_extend32(mantissa, 15);
+
+ *val = (mantissa * (int)MILLI) >> exponent;
+}
+
+static void sysmon_supply_processedtoraw(int val, u32 reg_val, u32 *raw_data)
+{
+ int exponent = FIELD_GET(SYSMON_MODE_MASK, reg_val);
+ int format = FIELD_GET(SYSMON_FMT_MASK, reg_val);
+ int scale, tmp;
+
+ scale = BIT(SYSMON_SUPPLY_MANTISSA_BITS - exponent);
+ tmp = (val * scale) / (int)MILLI;
+
+ if (format)
+ tmp = clamp(tmp, S16_MIN, S16_MAX);
+ else
+ tmp = clamp(tmp, 0, U16_MAX);
+
+ *raw_data = (u16)tmp;
+}
+
+static int sysmon_supply_thresh_offset(unsigned long address, enum iio_event_direction dir)
+{
+ if (dir == IIO_EV_DIR_RISING)
+ return (address * SYSMON_REG_STRIDE) + SYSMON_SUPPLY_TH_UP;
+ if (dir == IIO_EV_DIR_FALLING)
+ return (address * SYSMON_REG_STRIDE) + SYSMON_SUPPLY_TH_LOW;
+
+ return -EINVAL;
+}
+
+static int sysmon_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct sysmon *sysmon = iio_priv(indio_dev);
+ unsigned int regval;
+ int ret;
+
+ guard(mutex)(&sysmon->lock);
+
+ if (mask == IIO_CHAN_INFO_OVERSAMPLING_RATIO) {
+ *val = (chan->type == IIO_TEMP) ? sysmon->temp_oversampling :
+ sysmon->supply_oversampling;
+ return IIO_VAL_INT;
+ }
+
+ switch (chan->type) {
+ case IIO_TEMP:
+ if (mask == IIO_CHAN_INFO_SCALE) {
+ /* Q8.7 to millicelsius: raw * 1000 / 128 */
+ *val = MILLIDEGREE_PER_DEGREE;
+ *val2 = BIT(SYSMON_FRACTIONAL_SHIFT);
+ return IIO_VAL_FRACTIONAL;
+ }
+ if (mask != IIO_CHAN_INFO_RAW)
+ return -EINVAL;
+
+ ret = regmap_read(sysmon->regmap, chan->address, &regval);
+ if (ret)
+ return ret;
+
+ *val = sign_extend32(regval, 15);
+ return IIO_VAL_INT;
+
+ case IIO_VOLTAGE:
+ if (mask != IIO_CHAN_INFO_PROCESSED)
+ return -EINVAL;
+
+ ret = regmap_read(sysmon->regmap,
+ chan->address * SYSMON_REG_STRIDE +
+ SYSMON_SUPPLY_BASE, &regval);
+ if (ret)
+ return ret;
+
+ sysmon_supply_rawtoprocessed(regval, val);
+ return IIO_VAL_INT;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static u32 sysmon_get_event_mask(const struct iio_chan_spec *chan)
+{
+ if (chan->type == IIO_TEMP)
+ return BIT(SYSMON_BIT_TEMP);
+
+ return BIT(chan->address / SYSMON_ALARM_BITS_PER_REG);
+}
+
+static int sysmon_read_alarm_config(struct sysmon *sysmon,
+ unsigned long address)
+{
+ u32 shift = address % SYSMON_ALARM_BITS_PER_REG;
+ u32 offset = SYSMON_ALARM_OFFSET(address);
+
+ return regmap_test_bits(sysmon->regmap, offset, BIT(shift));
+}
+
+static int sysmon_write_alarm_config(struct sysmon *sysmon,
+ unsigned long address, bool enable)
+{
+ u32 shift = address % SYSMON_ALARM_BITS_PER_REG;
+ u32 offset = SYSMON_ALARM_OFFSET(address);
+
+ return regmap_assign_bits(sysmon->regmap, offset, BIT(shift), enable);
+}
+
+static int sysmon_read_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir)
+{
+ struct sysmon *sysmon = iio_priv(indio_dev);
+ u32 mask = sysmon_get_event_mask(chan);
+ unsigned int imr;
+ int config_value;
+ int ret;
+
+ ret = regmap_read(sysmon->regmap, SYSMON_IMR, &imr);
+ if (ret)
+ return ret;
+
+ /* IMR bits are 1=masked, invert to get 1=enabled */
+ imr = ~imr;
+
+ switch (chan->type) {
+ case IIO_VOLTAGE:
+ config_value = sysmon_read_alarm_config(sysmon, chan->address);
+ if (config_value < 0)
+ return config_value;
+ return config_value && (imr & mask);
+
+ case IIO_TEMP:
+ /*
+ * Return the administrative state, not the hardware IMR.
+ * The IRQ handler temporarily masks the interrupt during
+ * the polling window; reading IMR would show it as disabled.
+ * temp_mask bit is set when administratively disabled.
+ */
+ return !(sysmon->temp_mask & mask);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int sysmon_write_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ bool state)
+{
+ u32 offset = SYSMON_ALARM_OFFSET(chan->address);
+ struct sysmon *sysmon = iio_priv(indio_dev);
+ u32 mask = sysmon_get_event_mask(chan);
+ unsigned int alarm_config;
+ int ret;
+
+ guard(mutex)(&sysmon->lock);
+
+ switch (chan->type) {
+ case IIO_VOLTAGE:
+ ret = sysmon_write_alarm_config(sysmon, chan->address, state);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(sysmon->regmap, offset, &alarm_config);
+ if (ret)
+ return ret;
+
+ if (alarm_config)
+ return regmap_write(sysmon->regmap, SYSMON_IER, mask);
+
+ return regmap_write(sysmon->regmap, SYSMON_IDR, mask);
+
+ case IIO_TEMP:
+ if (state) {
+ ret = regmap_write(sysmon->regmap, SYSMON_IER, mask);
+ if (ret)
+ return ret;
+
+ scoped_guard(spinlock_irq, &sysmon->irq_lock)
+ sysmon->temp_mask &= ~mask;
+ } else {
+ ret = regmap_write(sysmon->regmap, SYSMON_IDR, mask);
+ if (ret)
+ return ret;
+
+ scoped_guard(spinlock_irq, &sysmon->irq_lock)
+ sysmon->temp_mask |= mask;
+ }
+ return 0;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+/*
+ * Recompute the lower threshold register from upper threshold and
+ * cached hysteresis. Called when either upper threshold or hysteresis
+ * is written.
+ */
+static int sysmon_update_temp_lower(struct sysmon *sysmon)
+{
+ unsigned int upper_reg;
+ int upper_mc, lower_mc;
+ u32 raw_val;
+ int ret;
+
+ ret = regmap_read(sysmon->regmap, SYSMON_TEMP_TH_UP, &upper_reg);
+ if (ret)
+ return ret;
+
+ sysmon_q8p7_to_millicelsius(upper_reg, &upper_mc);
+ lower_mc = clamp(upper_mc - sysmon->temp_hysteresis, -256000, 255992);
+ sysmon_millicelsius_to_q8p7(&raw_val, lower_mc);
+
+ return regmap_write(sysmon->regmap, SYSMON_TEMP_TH_LOW, raw_val);
+}
+
+static int sysmon_read_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int *val, int *val2)
+{
+ struct sysmon *sysmon = iio_priv(indio_dev);
+ unsigned int reg_val;
+ int offset;
+ int ret;
+
+ guard(mutex)(&sysmon->lock);
+
+ switch (chan->type) {
+ case IIO_TEMP:
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ ret = regmap_read(sysmon->regmap, SYSMON_TEMP_TH_UP, &reg_val);
+ if (ret)
+ return ret;
+
+ sysmon_q8p7_to_millicelsius(reg_val, val);
+
+ return IIO_VAL_INT;
+
+ case IIO_EV_INFO_HYSTERESIS:
+ *val = sysmon->temp_hysteresis;
+ return IIO_VAL_INT;
+
+ default:
+ return -EINVAL;
+ }
+
+ case IIO_VOLTAGE:
+ offset = sysmon_supply_thresh_offset(chan->address, dir);
+ if (offset < 0)
+ return offset;
+
+ ret = regmap_read(sysmon->regmap, offset, &reg_val);
+ if (ret)
+ return ret;
+
+ sysmon_supply_rawtoprocessed(reg_val, val);
+
+ return IIO_VAL_INT;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int sysmon_write_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int val, int val2)
+{
+ struct sysmon *sysmon = iio_priv(indio_dev);
+ unsigned int reg_val;
+ u32 raw_val;
+ int offset;
+ int ret;
+
+ guard(mutex)(&sysmon->lock);
+
+ switch (chan->type) {
+ case IIO_TEMP:
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ /* Q8.7 signed range: -256000 to +255992 mC */
+ if (val < -256000 || val > 255992)
+ return -EINVAL;
+
+ sysmon_millicelsius_to_q8p7(&raw_val, val);
+
+ ret = regmap_write(sysmon->regmap, SYSMON_TEMP_TH_UP, raw_val);
+ if (ret)
+ return ret;
+
+ /* Recompute lower = upper - hysteresis */
+ return sysmon_update_temp_lower(sysmon);
+
+ case IIO_EV_INFO_HYSTERESIS:
+ if (val < 0)
+ return -EINVAL;
+
+ sysmon->temp_hysteresis = val;
+
+ return sysmon_update_temp_lower(sysmon);
+
+ default:
+ return -EINVAL;
+ }
+
+ case IIO_VOLTAGE:
+ offset = sysmon_supply_thresh_offset(chan->address, dir);
+ if (offset < 0)
+ return offset;
+
+ ret = regmap_read(sysmon->regmap, offset, &reg_val);
+ if (ret)
+ return ret;
+
+ /* Clamp to prevent overflow in processedtoraw conversion */
+ if (val < -32768 || val > 32767)
+ return -EINVAL;
+
+ sysmon_supply_processedtoraw(val, reg_val, &raw_val);
+
+ /*
+ * The hardware threshold register returns FMT and MODE
+ * bits in the upper 16 bits on read, but only the lower
+ * 16-bit mantissa is used on write.
+ */
+ return regmap_write(sysmon->regmap, offset, raw_val);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int sysmon_set_avg_enable(struct sysmon *sysmon,
+ u32 base, u32 count, u32 val)
+{
+ struct regmap *map = sysmon->regmap;
+ int ret;
+
+ for (unsigned int i = 0; i < count; i++) {
+ ret = regmap_write(map, base + i * SYSMON_REG_STRIDE, val);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int sysmon_osr_write_temp(struct sysmon *sysmon, unsigned int val)
+{
+ /*
+ * HW register encoding is sample_count / 2:
+ * 0=none, 1=2x, 2=4x, 4=8x, 8=16x (not log2-based).
+ */
+ unsigned int hw_val = val >> 1;
+ unsigned int readback;
+ int ret;
+
+ ret = regmap_update_bits(sysmon->regmap, SYSMON_CONFIG,
+ SYSMON_CONFIG_TEMP_SAT_OSR,
+ FIELD_PREP(SYSMON_CONFIG_TEMP_SAT_OSR, hw_val));
+ if (ret)
+ return ret;
+
+ /*
+ * Readback fence: the SysMon CONFIG register resides in the
+ * PMC domain behind the NoC. A posted write may not reach the
+ * hardware before the next MMIO access. Reading the register
+ * back forces the interconnect to complete the write, preventing
+ * a bus hang on the subsequent access.
+ */
+ regmap_read(sysmon->regmap, SYSMON_CONFIG, &readback);
+
+ return sysmon_set_avg_enable(sysmon, SYSMON_TEMP_EN_AVG_BASE,
+ SYSMON_TEMP_EN_AVG_COUNT,
+ hw_val ? ~0 : 0);
+}
+
+static int sysmon_osr_write_supply(struct sysmon *sysmon, unsigned int val)
+{
+ /* HW encoding: sample_count / 2 (see sysmon_osr_write_temp) */
+ unsigned int hw_val = val >> 1;
+ unsigned int readback;
+ int ret;
+
+ ret = regmap_update_bits(sysmon->regmap, SYSMON_CONFIG,
+ SYSMON_CONFIG_SUPPLY_OSR,
+ FIELD_PREP(SYSMON_CONFIG_SUPPLY_OSR, hw_val));
+ if (ret)
+ return ret;
+
+ /* Readback fence -- see sysmon_osr_write_temp for details */
+ regmap_read(sysmon->regmap, SYSMON_CONFIG, &readback);
+
+ return sysmon_set_avg_enable(sysmon, SYSMON_SUPPLY_EN_AVG_BASE,
+ SYSMON_SUPPLY_EN_AVG_COUNT,
+ hw_val ? ~0 : 0);
+}
+
+static int sysmon_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct sysmon *sysmon = iio_priv(indio_dev);
+ unsigned int i;
+ int ret;
+
+ if (mask != IIO_CHAN_INFO_OVERSAMPLING_RATIO)
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(sysmon_oversampling_avail); i++) {
+ if (val == sysmon_oversampling_avail[i])
+ break;
+ }
+ if (i == ARRAY_SIZE(sysmon_oversampling_avail))
+ return -EINVAL;
+
+ guard(mutex)(&sysmon->lock);
+
+ if (chan->type == IIO_TEMP) {
+ ret = sysmon_osr_write_temp(sysmon, val);
+ if (ret)
+ return ret;
+ sysmon->temp_oversampling = val;
+ } else {
+ ret = sysmon_osr_write_supply(sysmon, val);
+ if (ret)
+ return ret;
+ sysmon->supply_oversampling = val;
+ }
+
+ return 0;
+}
+
+static int sysmon_write_raw_get_fmt(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ long mask)
+{
+ if (mask == IIO_CHAN_INFO_OVERSAMPLING_RATIO)
+ return IIO_VAL_INT;
+
+ return -EINVAL;
+}
+
+static int sysmon_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type,
+ int *length, long mask)
+{
+ if (mask != IIO_CHAN_INFO_OVERSAMPLING_RATIO)
+ return -EINVAL;
+
+ *vals = sysmon_oversampling_avail;
+ *type = IIO_VAL_INT;
+ *length = ARRAY_SIZE(sysmon_oversampling_avail);
+
+ return IIO_AVAIL_LIST;
+}
+
+static int sysmon_read_label(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ char *label)
+{
+ if (chan->datasheet_name)
+ return sysfs_emit(label, "%s\n", chan->datasheet_name);
+
+ return -EINVAL;
+}
+
+static const struct iio_info sysmon_iio_info = {
+ .read_raw = sysmon_read_raw,
+ .write_raw = sysmon_write_raw,
+ .write_raw_get_fmt = sysmon_write_raw_get_fmt,
+ .read_avail = sysmon_read_avail,
+ .read_label = sysmon_read_label,
+ .read_event_config = sysmon_read_event_config,
+ .write_event_config = sysmon_write_event_config,
+ .read_event_value = sysmon_read_event_value,
+ .write_event_value = sysmon_write_event_value,
+};
+
+static void sysmon_push_event(struct iio_dev *indio_dev, u32 address)
+{
+ const struct iio_chan_spec *chan;
+ enum iio_event_direction dir;
+
+ for (unsigned int i = 0; i < indio_dev->num_channels; i++) {
+ if (indio_dev->channels[i].address != address)
+ continue;
+
+ chan = &indio_dev->channels[i];
+ /* Temp uses hysteresis mode (rising only), voltage uses window */
+ dir = (chan->type == IIO_TEMP) ? IIO_EV_DIR_RISING :
+ IIO_EV_DIR_EITHER;
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(chan->type,
+ chan->channel,
+ IIO_EV_TYPE_THRESH,
+ dir),
+ iio_get_time_ns(indio_dev));
+ }
+}
+
+static int sysmon_handle_event(struct iio_dev *indio_dev, u32 event)
+{
+ u32 alarm_flag_offset = SYSMON_ALARM_FLAG + event * SYSMON_REG_STRIDE;
+ u32 alarm_reg_offset = SYSMON_ALARM_REG + event * SYSMON_REG_STRIDE;
+ struct sysmon *sysmon = iio_priv(indio_dev);
+ unsigned long alarm_flag_reg;
+ unsigned int reg_val;
+ u32 address, bit;
+ int ret;
+
+ switch (event) {
+ case SYSMON_BIT_TEMP:
+ sysmon_push_event(indio_dev, SYSMON_TEMP_MAX);
+
+ ret = regmap_write(sysmon->regmap, SYSMON_IDR, BIT(SYSMON_BIT_TEMP));
+ if (ret)
+ return ret;
+
+ sysmon->masked_temp |= BIT(SYSMON_BIT_TEMP);
+ return 0;
+
+ case SYSMON_BIT_ALARM0:
+ case SYSMON_BIT_ALARM1:
+ case SYSMON_BIT_ALARM2:
+ case SYSMON_BIT_ALARM3:
+ case SYSMON_BIT_ALARM4:
+ ret = regmap_read(sysmon->regmap, alarm_flag_offset, &reg_val);
+ if (ret)
+ return ret;
+
+ alarm_flag_reg = reg_val;
+
+ for_each_set_bit(bit, &alarm_flag_reg, SYSMON_ALARM_BITS_PER_REG) {
+ address = bit + SYSMON_ALARM_BITS_PER_REG * event;
+ sysmon_push_event(indio_dev, address);
+ ret = regmap_clear_bits(sysmon->regmap, alarm_reg_offset, BIT(bit));
+ if (ret)
+ return ret;
+ }
+
+ return regmap_write(sysmon->regmap, alarm_flag_offset, alarm_flag_reg);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static void sysmon_handle_events(struct iio_dev *indio_dev,
+ unsigned long events)
+{
+ unsigned int bit;
+
+ for_each_set_bit(bit, &events, SYSMON_NO_OF_EVENTS)
+ sysmon_handle_event(indio_dev, bit);
+}
+
+static void sysmon_unmask_temp(struct sysmon *sysmon, unsigned int isr)
+{
+ unsigned int status;
+ u32 ier;
+
+ status = isr & SYSMON_TEMP_INTR_MASK;
+
+ ier = ~status & sysmon->masked_temp;
+ sysmon->masked_temp &= status;
+
+ /* Only unmask if not administratively disabled by userspace */
+ ier &= ~sysmon->temp_mask;
+
+ regmap_write(sysmon->regmap, SYSMON_IER, ier);
+}
+
+/*
+ * Versal threshold interrupts are level-sensitive. Active threshold
+ * interrupts are masked in the handler and polled via delayed work
+ * until the condition clears, then unmasked.
+ */
+static void sysmon_unmask_worker(struct work_struct *work)
+{
+ struct sysmon *sysmon =
+ container_of(work, struct sysmon, sysmon_unmask_work.work);
+ unsigned int isr;
+
+ /*
+ * If the ISR read fails, skip processing to avoid acting
+ * on undefined data.
+ */
+ scoped_guard(spinlock_irq, &sysmon->irq_lock) {
+ if (regmap_read(sysmon->regmap, SYSMON_ISR, &isr))
+ break;
+ regmap_write(sysmon->regmap, SYSMON_ISR, isr);
+ sysmon_unmask_temp(sysmon, isr);
+ }
+
+ if (sysmon->masked_temp)
+ schedule_delayed_work(&sysmon->sysmon_unmask_work,
+ msecs_to_jiffies(SYSMON_UNMASK_WORK_DELAY_MS));
+ else
+ regmap_write(sysmon->regmap, SYSMON_STATUS_RESET, 1);
+}
+
+static irqreturn_t sysmon_iio_irq(int irq, void *data)
+{
+ struct iio_dev *indio_dev = data;
+ struct sysmon *sysmon = iio_priv(indio_dev);
+ unsigned int isr, imr;
+
+ guard(spinlock)(&sysmon->irq_lock);
+
+ if (regmap_read(sysmon->regmap, SYSMON_ISR, &isr) ||
+ regmap_read(sysmon->regmap, SYSMON_IMR, &imr))
+ return IRQ_NONE;
+
+ isr &= ~imr;
+ if (!isr)
+ return IRQ_NONE;
+
+ regmap_write(sysmon->regmap, SYSMON_ISR, isr);
+
+ sysmon_handle_events(indio_dev, isr);
+ schedule_delayed_work(&sysmon->sysmon_unmask_work,
+ msecs_to_jiffies(SYSMON_UNMASK_WORK_DELAY_MS));
+
+ return IRQ_HANDLED;
+}
+
+static void sysmon_disable_interrupts(void *data)
+{
+ struct sysmon *sysmon = data;
+
+ regmap_write(sysmon->regmap, SYSMON_IDR, SYSMON_INTR_ALL_MASK);
+
+ scoped_guard(spinlock_irq, &sysmon->irq_lock)
+ sysmon->masked_temp = 0;
+
+ cancel_delayed_work_sync(&sysmon->sysmon_unmask_work);
+}
+
+static int sysmon_init_interrupt(struct sysmon *sysmon,
+ struct device *dev,
+ struct iio_dev *indio_dev,
+ int irq)
+{
+ unsigned int imr;
+ int ret;
+
+ /* Events not supported without IRQ (e.g. I2C path) */
+ if (!irq)
+ return 0;
+
+ INIT_DELAYED_WORK(&sysmon->sysmon_unmask_work, sysmon_unmask_worker);
+
+ ret = regmap_read(sysmon->regmap, SYSMON_IMR, &imr);
+ if (ret)
+ return ret;
+ sysmon->temp_mask = imr & SYSMON_TEMP_INTR_MASK;
+
+ ret = devm_request_irq(dev, irq, sysmon_iio_irq, 0, "sysmon-irq", indio_dev);
+ if (ret)
+ return ret;
+
+ return devm_add_action_or_reset(dev, sysmon_disable_interrupts, sysmon);
+}
+
+/*
+ * Initialize the cached hysteresis for a temperature channel from the
+ * current hardware threshold registers: hysteresis = upper - lower.
+ */
+static int sysmon_init_hysteresis(struct sysmon *sysmon, int *hysteresis)
+{
+ unsigned int upper_reg, lower_reg;
+ int upper_mc, lower_mc;
+ int ret;
+
+ ret = regmap_read(sysmon->regmap, SYSMON_TEMP_TH_UP, &upper_reg);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(sysmon->regmap, SYSMON_TEMP_TH_LOW, &lower_reg);
+ if (ret)
+ return ret;
+
+ sysmon_q8p7_to_millicelsius(upper_reg, &upper_mc);
+ sysmon_q8p7_to_millicelsius(lower_reg, &lower_mc);
+ *hysteresis = upper_mc - lower_mc;
+
+ return 0;
+}
+
+/**
+ * sysmon_parse_fw() - Parse firmware nodes and configure IIO channels.
+ * @indio_dev: IIO device instance
+ * @dev: Parent device
+ * @irq: IRQ number (positive enables event channels, 0 disables)
+ *
+ * Reads voltage-channels and temperature-channels container nodes from
+ * firmware and builds the IIO channel array. Static temperature channels
+ * and event channels are prepended, followed by supply and satellite
+ * channels from DT.
+ *
+ * Event channels and per-channel event specs are only added when the
+ * device has an IRQ. I2C devices have no interrupt line, and the I2C
+ * regmap cannot be called from atomic context, so events are not
+ * supported on that path.
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+static int sysmon_parse_fw(struct iio_dev *indio_dev, struct device *dev, int irq)
+{
+ unsigned int num_chan, num_static, num_supply, num_temp;
+ unsigned int idx, temp_chan_idx, volt_chan_idx;
+ struct iio_chan_spec *sysmon_channels;
+ const char *label;
+ u32 reg;
+ int ret;
+
+ struct fwnode_handle *supply_node __free(fwnode_handle) =
+ device_get_named_child_node(dev, "voltage-channels");
+ num_supply = fwnode_get_child_node_count(supply_node);
+
+ struct fwnode_handle *temp_node __free(fwnode_handle) =
+ device_get_named_child_node(dev, "temperature-channels");
+ num_temp = fwnode_get_child_node_count(temp_node);
+
+ num_static = ARRAY_SIZE(temp_channels);
+ num_chan = size_add(num_temp, size_add(num_static, num_supply));
+ sysmon_channels = devm_kcalloc(dev, num_chan, sizeof(*sysmon_channels), GFP_KERNEL);
+ if (!sysmon_channels)
+ return -ENOMEM;
+
+ memcpy(sysmon_channels, temp_channels, sizeof(temp_channels));
+
+ /* Attach event spec to channel 0 when IRQ is available */
+ if (irq > 0) {
+ sysmon_channels[0].event_spec = sysmon_temp_events;
+ sysmon_channels[0].num_event_specs = ARRAY_SIZE(sysmon_temp_events);
+ }
+
+ idx = num_static;
+
+ /* Supply channels from DT */
+ fwnode_for_each_child_node_scoped(supply_node, child) {
+ ret = fwnode_property_read_u32(child, "reg", &reg);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "missing reg for supply channel\n");
+
+ if (reg > SYSMON_SUPPLY_IDX_MAX)
+ return dev_err_probe(dev, -EINVAL,
+ "supply reg %u exceeds max %u\n",
+ reg, SYSMON_SUPPLY_IDX_MAX);
+
+ ret = fwnode_property_read_string(child, "label", &label);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "missing label for supply channel\n");
+
+ sysmon_channels[idx++] = (struct iio_chan_spec) {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .address = reg,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+ .info_mask_shared_by_type =
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_type_available =
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .event_spec = irq > 0 ?
+ sysmon_supply_events : NULL,
+ .num_event_specs = irq > 0 ?
+ ARRAY_SIZE(sysmon_supply_events) : 0,
+ .datasheet_name = label,
+ };
+ }
+
+ /* Temperature satellite channels from DT */
+ fwnode_for_each_child_node_scoped(temp_node, child) {
+ ret = fwnode_property_read_u32(child, "reg", &reg);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "missing reg for temp channel\n");
+
+ if (reg < 1 || reg > SYSMON_TEMP_SAT_MAX)
+ return dev_err_probe(dev, -EINVAL,
+ "temp reg %u out of range [1..%u]\n",
+ reg, SYSMON_TEMP_SAT_MAX);
+
+ ret = fwnode_property_read_string(child, "label", &label);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "missing label for temp channel\n");
+
+ sysmon_channels[idx++] = (struct iio_chan_spec) {
+ .type = IIO_TEMP,
+ .indexed = 1,
+ .address = SYSMON_TEMP_SAT_BASE +
+ (reg - 1) * SYSMON_REG_STRIDE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type =
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_type_available =
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .datasheet_name = label,
+ };
+ }
+
+ indio_dev->num_channels = idx;
+ indio_dev->info = &sysmon_iio_info;
+
+ /*
+ * Assign per-type sequential channel numbers.
+ * IIO sysfs uses type prefix (in_tempN, in_voltageN)
+ * so numbers only need to be unique within each type.
+ */
+ temp_chan_idx = 0;
+ volt_chan_idx = 0;
+ for (unsigned int idx = 0; idx < indio_dev->num_channels; idx++) {
+ if (sysmon_channels[idx].type == IIO_TEMP)
+ sysmon_channels[idx].channel = temp_chan_idx++;
+ else
+ sysmon_channels[idx].channel = volt_chan_idx++;
+ }
+
+ indio_dev->channels = sysmon_channels;
+
+ return 0;
+}
+
+/**
+ * devm_versal_sysmon_core_probe() - Initialize Versal SysMon core
+ * @dev: Parent device
+ * @regmap: Register map for hardware access
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int devm_versal_sysmon_core_probe(struct device *dev, struct regmap *regmap)
+{
+ struct iio_dev *indio_dev;
+ struct sysmon *sysmon;
+ int irq;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*sysmon));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ sysmon = iio_priv(indio_dev);
+ sysmon->regmap = regmap;
+ sysmon->temp_oversampling = 1;
+ sysmon->supply_oversampling = 1;
+
+ ret = devm_mutex_init(dev, &sysmon->lock);
+ if (ret)
+ return ret;
+ spin_lock_init(&sysmon->irq_lock);
+
+ /* Disable all interrupts and clear pending status */
+ ret = regmap_write(sysmon->regmap, SYSMON_IDR, SYSMON_INTR_ALL_MASK);
+ if (ret)
+ return ret;
+ ret = regmap_write(sysmon->regmap, SYSMON_ISR, SYSMON_INTR_ALL_MASK);
+ if (ret)
+ return ret;
+
+ irq = fwnode_irq_get(dev_fwnode(dev), 0);
+ if (irq == -EPROBE_DEFER)
+ return dev_err_probe(dev, irq, "failed to get IRQ\n");
+
+ indio_dev->name = "versal-sysmon";
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = sysmon_parse_fw(indio_dev, dev, irq);
+ if (ret)
+ return ret;
+
+ if (irq > 0) {
+ /* Set hysteresis mode for temperature threshold */
+ ret = regmap_set_bits(sysmon->regmap, SYSMON_TEMP_EV_CFG,
+ SYSMON_TEMP_HYST_MASK);
+ if (ret)
+ return ret;
+
+ /* Initialize cached hysteresis from hardware registers */
+ ret = sysmon_init_hysteresis(sysmon, &sysmon->temp_hysteresis);
+ if (ret)
+ return ret;
+
+ ret = sysmon_init_interrupt(sysmon, dev, indio_dev, irq);
+ if (ret)
+ return ret;
+ }
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+EXPORT_SYMBOL_NS_GPL(devm_versal_sysmon_core_probe, "VERSAL_SYSMON");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("AMD Versal SysMon Core Driver");
+MODULE_AUTHOR("Salih Erim <salih.erim@amd.com>");
diff --git a/drivers/iio/adc/versal-sysmon-i2c.c b/drivers/iio/adc/versal-sysmon-i2c.c
new file mode 100644
index 000000000000..e9a7629159ab
--- /dev/null
+++ b/drivers/iio/adc/versal-sysmon-i2c.c
@@ -0,0 +1,134 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * AMD Versal SysMon I2C driver
+ *
+ * Copyright (C) 2023 - 2026, Advanced Micro Devices, Inc.
+ */
+
+#include <linux/bits.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+#include <linux/unaligned.h>
+
+#include "versal-sysmon.h"
+
+#define SYSMON_I2C_INSTR_READ BIT(2)
+#define SYSMON_I2C_INSTR_WRITE BIT(3)
+
+/*
+ * I2C command frame layout (8 bytes):
+ * [0..3] data payload (little-endian u32)
+ * [4..5] register offset >> 2 (little-endian u16)
+ * [6] instruction (read/write)
+ * [7] reserved
+ */
+#define SYSMON_I2C_DATA_OFS 0
+#define SYSMON_I2C_REG_OFS 4
+#define SYSMON_I2C_INSTR_OFS 6
+
+static int sysmon_i2c_reg_read(void *context, unsigned int reg,
+ unsigned int *val)
+{
+ struct i2c_client *client = context;
+ u8 write_buf[8] = { };
+ u8 read_buf[4];
+ int ret;
+
+ put_unaligned_le16(reg >> 2, &write_buf[SYSMON_I2C_REG_OFS]);
+ write_buf[SYSMON_I2C_INSTR_OFS] = SYSMON_I2C_INSTR_READ;
+
+ ret = i2c_master_send(client, write_buf, sizeof(write_buf));
+ if (ret < 0)
+ return ret;
+ if (ret != sizeof(write_buf))
+ return -EIO;
+
+ ret = i2c_master_recv(client, read_buf, sizeof(read_buf));
+ if (ret < 0)
+ return ret;
+ if (ret != sizeof(read_buf))
+ return -EIO;
+
+ *val = get_unaligned_le32(read_buf);
+
+ return 0;
+}
+
+static int sysmon_i2c_reg_write(void *context, unsigned int reg,
+ unsigned int val)
+{
+ struct i2c_client *client = context;
+ u8 write_buf[8] = { };
+ int ret;
+
+ put_unaligned_le32(val, &write_buf[SYSMON_I2C_DATA_OFS]);
+ put_unaligned_le16(reg >> 2, &write_buf[SYSMON_I2C_REG_OFS]);
+ write_buf[SYSMON_I2C_INSTR_OFS] = SYSMON_I2C_INSTR_WRITE;
+
+ ret = i2c_master_send(client, write_buf, sizeof(write_buf));
+ if (ret < 0)
+ return ret;
+ if (ret != sizeof(write_buf))
+ return -EIO;
+
+ return 0;
+}
+
+/*
+ * Almost all registers are volatile (live ADC readings, interrupt
+ * status). The rest are not accessed often enough to benefit from
+ * caching.
+ */
+static const struct regmap_config sysmon_i2c_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = SYSMON_REG_STRIDE,
+ .max_register = SYSMON_MAX_REG,
+ .reg_read = sysmon_i2c_reg_read,
+ .reg_write = sysmon_i2c_reg_write,
+};
+
+static int sysmon_i2c_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init(dev, NULL, client, &sysmon_i2c_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ /* I2C has no IRQ connection; events are not supported */
+ return devm_versal_sysmon_core_probe(dev, regmap);
+}
+
+static const struct of_device_id sysmon_i2c_of_match_table[] = {
+ { .compatible = "xlnx,versal-sysmon" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, sysmon_i2c_of_match_table);
+
+static const struct i2c_device_id sysmon_i2c_id_table[] = {
+ { .name = "versal-sysmon" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, sysmon_i2c_id_table);
+
+static struct i2c_driver sysmon_i2c_driver = {
+ .probe = sysmon_i2c_probe,
+ .driver = {
+ .name = "versal-sysmon-i2c",
+ .of_match_table = sysmon_i2c_of_match_table,
+ },
+ .id_table = sysmon_i2c_id_table,
+};
+module_i2c_driver(sysmon_i2c_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("AMD Versal SysMon I2C Driver");
+MODULE_IMPORT_NS("VERSAL_SYSMON");
+MODULE_AUTHOR("Conall O'Griofa <conall.ogriofa@amd.com>");
+MODULE_AUTHOR("Salih Erim <salih.erim@amd.com>");
diff --git a/drivers/iio/adc/versal-sysmon.c b/drivers/iio/adc/versal-sysmon.c
new file mode 100644
index 000000000000..529d0486c9f9
--- /dev/null
+++ b/drivers/iio/adc/versal-sysmon.c
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * AMD Versal SysMon MMIO platform driver
+ *
+ * Copyright (C) 2019 - 2022, Xilinx, Inc.
+ * Copyright (C) 2022 - 2026, Advanced Micro Devices, Inc.
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+#include "versal-sysmon.h"
+
+struct sysmon_mmio {
+ void __iomem *base;
+};
+
+static int sysmon_mmio_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+ struct sysmon_mmio *mmio = context;
+
+ *val = readl(mmio->base + reg);
+ return 0;
+}
+
+static int sysmon_mmio_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+ struct sysmon_mmio *mmio = context;
+
+ /* NPI must be unlocked before any register write except to NPI_LOCK */
+ if (reg != SYSMON_NPI_LOCK)
+ writel(SYSMON_NPI_UNLOCK_CODE, mmio->base + SYSMON_NPI_LOCK);
+ writel(val, mmio->base + reg);
+
+ return 0;
+}
+
+static const struct regmap_config sysmon_mmio_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = SYSMON_REG_STRIDE,
+ .max_register = SYSMON_MAX_REG,
+ .reg_read = sysmon_mmio_reg_read,
+ .reg_write = sysmon_mmio_reg_write,
+ .fast_io = true,
+};
+
+static int sysmon_platform_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct sysmon_mmio *mmio;
+ struct regmap *regmap;
+
+ mmio = devm_kzalloc(dev, sizeof(*mmio), GFP_KERNEL);
+ if (!mmio)
+ return -ENOMEM;
+
+ mmio->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(mmio->base))
+ return PTR_ERR(mmio->base);
+
+ regmap = devm_regmap_init(dev, NULL, mmio, &sysmon_mmio_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return devm_versal_sysmon_core_probe(dev, regmap);
+}
+
+static const struct of_device_id sysmon_of_match_table[] = {
+ { .compatible = "xlnx,versal-sysmon" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, sysmon_of_match_table);
+
+static struct platform_driver sysmon_platform_driver = {
+ .probe = sysmon_platform_probe,
+ .driver = {
+ .name = "versal-sysmon",
+ .of_match_table = sysmon_of_match_table,
+ },
+};
+module_platform_driver(sysmon_platform_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("AMD Versal SysMon Platform Driver");
+MODULE_IMPORT_NS("VERSAL_SYSMON");
+MODULE_AUTHOR("Salih Erim <salih.erim@amd.com>");
diff --git a/drivers/iio/adc/versal-sysmon.h b/drivers/iio/adc/versal-sysmon.h
new file mode 100644
index 000000000000..bb9a75bf71c0
--- /dev/null
+++ b/drivers/iio/adc/versal-sysmon.h
@@ -0,0 +1,120 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * AMD Versal SysMon driver
+ *
+ * Copyright (C) 2019 - 2022, Xilinx, Inc.
+ * Copyright (C) 2022 - 2026, Advanced Micro Devices, Inc.
+ */
+
+#ifndef _VERSAL_SYSMON_H_
+#define _VERSAL_SYSMON_H_
+
+#include <linux/bits.h>
+#include <linux/mutex.h>
+#include <linux/spinlock_types.h>
+#include <linux/workqueue.h>
+
+struct device;
+struct regmap;
+
+/* Register offsets (sorted by address) */
+#define SYSMON_NPI_LOCK 0x000C
+#define SYSMON_ISR 0x0044
+#define SYSMON_IMR 0x0048
+#define SYSMON_IER 0x004C
+#define SYSMON_IDR 0x0050
+#define SYSMON_CONFIG 0x0100
+#define SYSMON_TEMP_MAX 0x1030
+#define SYSMON_TEMP_MIN 0x1034
+#define SYSMON_SUPPLY_BASE 0x1040
+#define SYSMON_ALARM_FLAG 0x1018
+#define SYSMON_ALARM_REG 0x1940
+#define SYSMON_SUPPLY_EN_AVG_BASE 0x1958
+#define SYSMON_TEMP_TH_LOW 0x1970
+#define SYSMON_TEMP_TH_UP 0x1974
+#define SYSMON_SUPPLY_TH_LOW 0x1980
+#define SYSMON_SUPPLY_TH_UP 0x1C80
+#define SYSMON_TEMP_EV_CFG 0x1F84
+#define SYSMON_TEMP_MIN_MIN 0x1F8C
+#define SYSMON_TEMP_MAX_MAX 0x1F90
+#define SYSMON_STATUS_RESET 0x1F94
+#define SYSMON_TEMP_SAT_BASE 0x1FAC
+#define SYSMON_TEMP_EN_AVG_BASE 0x24B4
+#define SYSMON_MAX_REG 0x24C0
+
+/* NPI unlock value written to SYSMON_NPI_LOCK */
+#define SYSMON_NPI_UNLOCK_CODE 0xF9E8D7C6
+
+/* Register stride: 4 bytes per 32-bit register */
+#define SYSMON_REG_STRIDE 4
+
+#define SYSMON_SUPPLY_IDX_MAX 159
+#define SYSMON_TEMP_SAT_MAX 64
+#define SYSMON_NO_OF_EVENTS 32
+#define SYSMON_INTR_ALL_MASK GENMASK(31, 0)
+
+/* ISR/IMR temperature alarm mask (bit 9) */
+#define SYSMON_TEMP_INTR_MASK BIT(9)
+
+/* SYSMON_CONFIG: supply oversampling ratio */
+#define SYSMON_CONFIG_SUPPLY_OSR GENMASK(17, 14)
+
+/* SYSMON_CONFIG: temperature satellite oversampling ratio */
+#define SYSMON_CONFIG_TEMP_SAT_OSR GENMASK(27, 24)
+
+/* Per-channel averaging enable register counts */
+#define SYSMON_SUPPLY_EN_AVG_COUNT 5
+#define SYSMON_TEMP_EN_AVG_COUNT 2
+
+/* Supply voltage conversion register fields */
+#define SYSMON_MANTISSA_MASK GENMASK(15, 0)
+#define SYSMON_FMT_MASK BIT(16)
+#define SYSMON_MODE_MASK GENMASK(18, 17)
+
+/* Q8.7 fractional shift */
+#define SYSMON_FRACTIONAL_SHIFT 7U
+#define SYSMON_SUPPLY_MANTISSA_BITS 16
+
+/* Bits per alarm register */
+#define SYSMON_ALARM_BITS_PER_REG 32
+
+#define SYSMON_UNMASK_WORK_DELAY_MS 500
+
+/**
+ * struct sysmon - Driver data for Versal SysMon
+ * @regmap: register map for hardware access
+ * @lock: protects read-modify-write sequences on threshold registers
+ * and cached state that spans multiple regmap calls
+ * @irq_lock: protects interrupt mask register updates (MMIO path only)
+ * @masked_temp: currently masked temperature alarm bits
+ * @temp_mask: temperature interrupt configuration mask
+ * @temp_hysteresis: cached DEVICE_TEMP hysteresis in millicelsius
+ * @sysmon_unmask_work: re-enables events after alarm condition clears
+ * @temp_oversampling: current temp oversampling ratio
+ * @supply_oversampling: current supply oversampling ratio
+ */
+struct sysmon {
+ struct regmap *regmap;
+ /*
+ * Protects read-modify-write sequences on threshold registers
+ * and cached state (oversampling ratios, hysteresis values)
+ * that spans multiple regmap calls.
+ */
+ struct mutex lock;
+ /*
+ * Protects interrupt mask register updates. Only used on the
+ * MMIO path (fast_io regmap); I2C has no IRQ and never reaches
+ * the event code that takes this lock.
+ */
+ spinlock_t irq_lock;
+ unsigned int masked_temp;
+ unsigned int temp_mask;
+ int temp_hysteresis;
+ struct delayed_work sysmon_unmask_work;
+ unsigned int temp_oversampling;
+ unsigned int supply_oversampling;
+};
+
+int devm_versal_sysmon_core_probe(struct device *dev, struct regmap *regmap);
+
+#endif /* _VERSAL_SYSMON_H_ */
diff --git a/drivers/iio/afe/iio-rescale.c b/drivers/iio/afe/iio-rescale.c
index 654a3a50eb4f..3a6a09ffa526 100644
--- a/drivers/iio/afe/iio-rescale.c
+++ b/drivers/iio/afe/iio-rescale.c
@@ -608,3 +608,4 @@ module_platform_driver(rescale_driver);
MODULE_DESCRIPTION("IIO rescale driver");
MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/iio/buffer/industrialio-buffer-cb.c b/drivers/iio/buffer/industrialio-buffer-cb.c
index 0c266c216525..b58263bcf3cb 100644
--- a/drivers/iio/buffer/industrialio-buffer-cb.c
+++ b/drivers/iio/buffer/industrialio-buffer-cb.c
@@ -154,3 +154,4 @@ EXPORT_SYMBOL_GPL(iio_channel_cb_get_iio_dev);
MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
MODULE_DESCRIPTION("Industrial I/O callback buffer");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/iio/buffer/industrialio-hw-consumer.c b/drivers/iio/buffer/industrialio-hw-consumer.c
index 10e912bbf0c5..d035aa33b357 100644
--- a/drivers/iio/buffer/industrialio-hw-consumer.c
+++ b/drivers/iio/buffer/industrialio-hw-consumer.c
@@ -216,3 +216,4 @@ EXPORT_SYMBOL_GPL(iio_hw_consumer_disable);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("Hardware consumer buffer the IIO framework");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/iio/chemical/scd30_core.c b/drivers/iio/chemical/scd30_core.c
index 23895744c42d..f85cdd8bd84f 100644
--- a/drivers/iio/chemical/scd30_core.c
+++ b/drivers/iio/chemical/scd30_core.c
@@ -2,7 +2,7 @@
/*
* Sensirion SCD30 carbon dioxide sensor core driver
*
- * Copyright (c) 2020 Tomasz Duszynski <tomasz.duszynski@octakon.com>
+ * Copyright (c) 2020 Tomasz Duszynski <tduszyns@gmail.com>
*/
#include <linux/bitfield.h>
@@ -774,6 +774,6 @@ int scd30_probe(struct device *dev, int irq, const char *name, void *priv,
}
EXPORT_SYMBOL_NS(scd30_probe, "IIO_SCD30");
-MODULE_AUTHOR("Tomasz Duszynski <tomasz.duszynski@octakon.com>");
+MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>");
MODULE_DESCRIPTION("Sensirion SCD30 carbon dioxide sensor core driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/chemical/scd30_i2c.c b/drivers/iio/chemical/scd30_i2c.c
index abceccdddc71..bcef1e473e34 100644
--- a/drivers/iio/chemical/scd30_i2c.c
+++ b/drivers/iio/chemical/scd30_i2c.c
@@ -2,7 +2,7 @@
/*
* Sensirion SCD30 carbon dioxide sensor i2c driver
*
- * Copyright (c) 2020 Tomasz Duszynski <tomasz.duszynski@octakon.com>
+ * Copyright (c) 2020 Tomasz Duszynski <tduszyns@gmail.com>
*
* I2C slave address: 0x61
*/
@@ -136,7 +136,7 @@ static struct i2c_driver scd30_i2c_driver = {
};
module_i2c_driver(scd30_i2c_driver);
-MODULE_AUTHOR("Tomasz Duszynski <tomasz.duszynski@octakon.com>");
+MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>");
MODULE_DESCRIPTION("Sensirion SCD30 carbon dioxide sensor i2c driver");
MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS("IIO_SCD30");
diff --git a/drivers/iio/chemical/scd30_serial.c b/drivers/iio/chemical/scd30_serial.c
index 7fefdadbfa0a..31b0fc957b08 100644
--- a/drivers/iio/chemical/scd30_serial.c
+++ b/drivers/iio/chemical/scd30_serial.c
@@ -2,7 +2,7 @@
/*
* Sensirion SCD30 carbon dioxide sensor serial driver
*
- * Copyright (c) 2020 Tomasz Duszynski <tomasz.duszynski@octakon.com>
+ * Copyright (c) 2020 Tomasz Duszynski <tduszyns@gmail.com>
*/
#include <linux/crc16.h>
#include <linux/device.h>
@@ -257,7 +257,7 @@ static struct serdev_device_driver scd30_serdev_driver = {
};
module_serdev_device_driver(scd30_serdev_driver);
-MODULE_AUTHOR("Tomasz Duszynski <tomasz.duszynski@octakon.com>");
+MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>");
MODULE_DESCRIPTION("Sensirion SCD30 carbon dioxide sensor serial driver");
MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS("IIO_SCD30");
diff --git a/drivers/iio/chemical/sps30_i2c.c b/drivers/iio/chemical/sps30_i2c.c
index 90f1adb8c89f..2d3a876cc06e 100644
--- a/drivers/iio/chemical/sps30_i2c.c
+++ b/drivers/iio/chemical/sps30_i2c.c
@@ -2,7 +2,7 @@
/*
* Sensirion SPS30 particulate matter sensor i2c driver
*
- * Copyright (c) 2020 Tomasz Duszynski <tomasz.duszynski@octakon.com>
+ * Copyright (c) 2020 Tomasz Duszynski <tduszyns@gmail.com>
*
* I2C slave address: 0x69
*/
@@ -252,7 +252,7 @@ static struct i2c_driver sps30_i2c_driver = {
};
module_i2c_driver(sps30_i2c_driver);
-MODULE_AUTHOR("Tomasz Duszynski <tomasz.duszynski@octakon.com>");
+MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>");
MODULE_DESCRIPTION("Sensirion SPS30 particulate matter sensor i2c driver");
MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS("IIO_SPS30");
diff --git a/drivers/iio/chemical/sps30_serial.c b/drivers/iio/chemical/sps30_serial.c
index 80eab9b2e4bf..0cdba8703e93 100644
--- a/drivers/iio/chemical/sps30_serial.c
+++ b/drivers/iio/chemical/sps30_serial.c
@@ -2,7 +2,7 @@
/*
* Sensirion SPS30 particulate matter sensor serial driver
*
- * Copyright (c) 2021 Tomasz Duszynski <tomasz.duszynski@octakon.com>
+ * Copyright (c) 2021 Tomasz Duszynski <tduszyns@gmail.com>
*/
#include <linux/completion.h>
#include <linux/device.h>
@@ -425,7 +425,7 @@ static struct serdev_device_driver sps30_serial_driver = {
};
module_serdev_device_driver(sps30_serial_driver);
-MODULE_AUTHOR("Tomasz Duszynski <tomasz.duszynski@octakon.com>");
+MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>");
MODULE_DESCRIPTION("Sensirion SPS30 particulate matter sensor serial driver");
MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS("IIO_SPS30");
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c
index c115a72832b2..9e7c26e37880 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c
+++ b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c
@@ -72,8 +72,7 @@ static const struct {
{HID_USAGE_SENSOR_HUMAN_ATTENTION, 0, 1, 0},
};
-static void simple_div(int dividend, int divisor, int *whole,
- int *micro_frac)
+static void simple_div(int dividend, int divisor, int *whole, int *micro_frac)
{
int rem;
int exp = 0;
@@ -111,7 +110,7 @@ for 10^-2.
Negative numbers are 2's complement
*/
static void convert_from_vtf_format(u32 value, int size, int exp,
- int *val1, int *val2)
+ int *val1, int *val2)
{
int sign = 1;
@@ -176,7 +175,7 @@ s32 hid_sensor_read_poll_value(struct hid_sensor_common *st)
EXPORT_SYMBOL_NS(hid_sensor_read_poll_value, "IIO_HID_ATTRIBUTES");
int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st,
- int *val1, int *val2)
+ int *val1, int *val2)
{
s32 value;
int ret;
@@ -203,7 +202,7 @@ int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st,
EXPORT_SYMBOL_NS(hid_sensor_read_samp_freq_value, "IIO_HID");
int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st,
- int val1, int val2)
+ int val1, int val2)
{
s32 value;
int ret;
@@ -238,15 +237,15 @@ int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st,
EXPORT_SYMBOL_NS(hid_sensor_write_samp_freq_value, "IIO_HID");
int hid_sensor_read_raw_hyst_value(struct hid_sensor_common *st,
- int *val1, int *val2)
+ int *val1, int *val2)
{
s32 value;
int ret;
ret = sensor_hub_get_feature(st->hsdev,
st->sensitivity.report_id,
- st->sensitivity.index, sizeof(value),
- &value);
+ st->sensitivity.index,
+ sizeof(value), &value);
if (ret < 0 || value < 0) {
*val1 = *val2 = 0;
return -EINVAL;
@@ -268,8 +267,8 @@ int hid_sensor_read_raw_hyst_rel_value(struct hid_sensor_common *st, int *val1,
ret = sensor_hub_get_feature(st->hsdev,
st->sensitivity_rel.report_id,
- st->sensitivity_rel.index, sizeof(value),
- &value);
+ st->sensitivity_rel.index,
+ sizeof(value), &value);
if (ret < 0 || value < 0) {
*val1 = *val2 = 0;
return -EINVAL;
@@ -282,9 +281,8 @@ int hid_sensor_read_raw_hyst_rel_value(struct hid_sensor_common *st, int *val1,
}
EXPORT_SYMBOL_NS(hid_sensor_read_raw_hyst_rel_value, "IIO_HID");
-
int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st,
- int val1, int val2)
+ int val1, int val2)
{
s32 value;
int ret;
@@ -293,8 +291,8 @@ int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st,
return -EINVAL;
value = convert_to_vtf_format(st->sensitivity.size,
- st->sensitivity.unit_expo,
- val1, val2);
+ st->sensitivity.unit_expo,
+ val1, val2);
ret = sensor_hub_set_feature(st->hsdev, st->sensitivity.report_id,
st->sensitivity.index, sizeof(value),
&value);
@@ -303,8 +301,8 @@ int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st,
ret = sensor_hub_get_feature(st->hsdev,
st->sensitivity.report_id,
- st->sensitivity.index, sizeof(value),
- &value);
+ st->sensitivity.index,
+ sizeof(value), &value);
if (ret < 0 || value < 0)
return -EINVAL;
@@ -324,8 +322,8 @@ int hid_sensor_write_raw_hyst_rel_value(struct hid_sensor_common *st,
return -EINVAL;
value = convert_to_vtf_format(st->sensitivity_rel.size,
- st->sensitivity_rel.unit_expo,
- val1, val2);
+ st->sensitivity_rel.unit_expo,
+ val1, val2);
ret = sensor_hub_set_feature(st->hsdev, st->sensitivity_rel.report_id,
st->sensitivity_rel.index, sizeof(value),
&value);
@@ -334,8 +332,8 @@ int hid_sensor_write_raw_hyst_rel_value(struct hid_sensor_common *st,
ret = sensor_hub_get_feature(st->hsdev,
st->sensitivity_rel.report_id,
- st->sensitivity_rel.index, sizeof(value),
- &value);
+ st->sensitivity_rel.index,
+ sizeof(value), &value);
if (ret < 0 || value < 0)
return -EINVAL;
@@ -356,8 +354,8 @@ EXPORT_SYMBOL_NS(hid_sensor_write_raw_hyst_rel_value, "IIO_HID");
* 1.001745329 ->exp:4-> val0[10017]val1[453290000]
* 9.806650000 ->exp:-2-> val0[0]val1[98066500]
*/
-static void adjust_exponent_nano(int *val0, int *val1, int scale0,
- int scale1, int exp)
+static void adjust_exponent_nano(int *val0, int *val1,
+ int scale0, int scale1, int exp)
{
int divisor;
int i;
@@ -404,8 +402,8 @@ static void adjust_exponent_nano(int *val0, int *val1, int scale0,
}
int hid_sensor_format_scale(u32 usage_id,
- struct hid_sensor_hub_attribute_info *attr_info,
- int *val0, int *val1)
+ struct hid_sensor_hub_attribute_info *attr_info,
+ int *val0, int *val1)
{
int i;
int exp;
@@ -415,12 +413,11 @@ int hid_sensor_format_scale(u32 usage_id,
for (i = 0; i < ARRAY_SIZE(unit_conversion); ++i) {
if (unit_conversion[i].usage_id == usage_id &&
- unit_conversion[i].unit == attr_info->units) {
- exp = hid_sensor_convert_exponent(
- attr_info->unit_expo);
+ unit_conversion[i].unit == attr_info->units) {
+ exp = hid_sensor_convert_exponent(attr_info->unit_expo);
adjust_exponent_nano(val0, val1,
- unit_conversion[i].scale_val0,
- unit_conversion[i].scale_val1, exp);
+ unit_conversion[i].scale_val0,
+ unit_conversion[i].scale_val1, exp);
break;
}
}
@@ -438,8 +435,8 @@ EXPORT_SYMBOL_NS(hid_sensor_convert_timestamp, "IIO_HID");
static
int hid_sensor_get_reporting_interval(struct hid_sensor_hub_device *hsdev,
- u32 usage_id,
- struct hid_sensor_common *st)
+ u32 usage_id,
+ struct hid_sensor_common *st)
{
sensor_hub_input_get_attribute_info(hsdev,
HID_FEATURE_REPORT, usage_id,
@@ -473,9 +470,10 @@ int hid_sensor_get_report_latency(struct hid_sensor_common *st)
int ret;
int value;
- ret = sensor_hub_get_feature(st->hsdev, st->report_latency.report_id,
- st->report_latency.index, sizeof(value),
- &value);
+ ret = sensor_hub_get_feature(st->hsdev,
+ st->report_latency.report_id,
+ st->report_latency.index,
+ sizeof(value), &value);
if (ret < 0)
return ret;
@@ -498,10 +496,10 @@ bool hid_sensor_batch_mode_supported(struct hid_sensor_common *st)
EXPORT_SYMBOL_NS(hid_sensor_batch_mode_supported, "IIO_HID_ATTRIBUTES");
int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
- u32 usage_id,
- struct hid_sensor_common *st,
- const u32 *sensitivity_addresses,
- u32 sensitivity_addresses_len)
+ u32 usage_id,
+ struct hid_sensor_common *st,
+ const u32 *sensitivity_addresses,
+ u32 sensitivity_addresses_len)
{
struct hid_sensor_hub_attribute_info timestamp;
@@ -527,7 +525,7 @@ int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
sensor_hub_input_get_attribute_info(hsdev,
HID_FEATURE_REPORT, usage_id,
HID_USAGE_SENSOR_PROP_SENSITIVITY_ABS,
- &st->sensitivity);
+ &st->sensitivity);
sensor_hub_input_get_attribute_info(hsdev,
HID_FEATURE_REPORT, usage_id,
@@ -578,8 +576,9 @@ int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
timestamp.index, timestamp.report_id);
ret = sensor_hub_get_feature(hsdev,
- st->power_state.report_id,
- st->power_state.index, sizeof(value), &value);
+ st->power_state.report_id,
+ st->power_state.index,
+ sizeof(value), &value);
if (ret < 0)
return ret;
if (value < 0)
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
index 417c4ab8c1b2..60808e2430ca 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
+++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
@@ -233,7 +233,7 @@ void hid_sensor_remove_trigger(struct iio_dev *indio_dev,
EXPORT_SYMBOL_NS(hid_sensor_remove_trigger, "IIO_HID");
int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
- struct hid_sensor_common *attrb)
+ struct hid_sensor_common *attrb)
{
const struct iio_dev_attr **fifo_attrs;
int ret;
@@ -266,7 +266,7 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
trig = iio_trigger_alloc(indio_dev->dev.parent,
"%s-dev%d", name, iio_device_id(indio_dev));
- if (trig == NULL) {
+ if (!trig) {
dev_err(&indio_dev->dev, "Trigger Allocate Failed\n");
return -ENOMEM;
}
@@ -314,7 +314,9 @@ static int __maybe_unused hid_sensor_resume(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev);
+
schedule_work(&attrb->work);
+
return 0;
}
@@ -322,6 +324,7 @@ static int __maybe_unused hid_sensor_runtime_resume(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev);
+
return _hid_sensor_power_state(attrb, true);
}
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.h b/drivers/iio/common/hid-sensors/hid-sensor-trigger.h
index f94fca4f1edf..589de858e369 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.h
+++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.h
@@ -15,7 +15,7 @@ struct iio_dev;
extern const struct dev_pm_ops hid_sensor_pm_ops;
int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
- struct hid_sensor_common *attrb);
+ struct hid_sensor_common *attrb);
void hid_sensor_remove_trigger(struct iio_dev *indio_dev,
struct hid_sensor_common *attrb);
int hid_sensor_power_state(struct hid_sensor_common *st, bool state);
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index 657c68e75542..17529509da9d 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -11,8 +11,11 @@ config AD3530R
depends on SPI
select REGMAP_SPI
help
- Say yes here to build support for Analog Devices AD3530R, AD3531R
- Digital to Analog Converter.
+ Say yes here to build support for the following Analog Devices
+ Digital to Analog Converters:
+ - AD3530/AD3530R (8-channel)
+ - AD3531/AD3531R (4-channel)
+ - AD3532/AD3532R (16-channel)
To compile this driver as a module, choose M here: the
module will be called ad3530r.
@@ -527,6 +530,17 @@ config MAX5821
Say yes here to build support for Maxim MAX5821
10 bits DAC.
+config MCF54415_DAC
+ tristate "NXP MCF54415 DAC driver"
+ depends on M5441x || COMPILE_TEST
+ select REGMAP_MMIO
+ help
+ Say yes here if you want to build support for NXP ColdFire
+ MCF54415/6/7/8 12-bit DAC module.
+
+ To compile this driver as a module, choose M here: the module
+ will be called mcf54415_dac.
+
config MCP4725
tristate "MCP4725/6 DAC driver"
depends on I2C
diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
index 003431798498..5d20d37e44ce 100644
--- a/drivers/iio/dac/Makefile
+++ b/drivers/iio/dac/Makefile
@@ -52,6 +52,7 @@ obj-$(CONFIG_MAX517) += max517.o
obj-$(CONFIG_MAX22007) += max22007.o
obj-$(CONFIG_MAX5522) += max5522.o
obj-$(CONFIG_MAX5821) += max5821.o
+obj-$(CONFIG_MCF54415_DAC) += mcf54415_dac.o
obj-$(CONFIG_MCP4725) += mcp4725.o
obj-$(CONFIG_MCP4728) += mcp4728.o
obj-$(CONFIG_MCP47FEB02) += mcp47feb02.o
diff --git a/drivers/iio/dac/ad3530r.c b/drivers/iio/dac/ad3530r.c
index 6ff7ee208541..06b7f280f61b 100644
--- a/drivers/iio/dac/ad3530r.c
+++ b/drivers/iio/dac/ad3530r.c
@@ -2,6 +2,7 @@
/*
* AD3530R/AD3530 8-channel, 16-bit Voltage Output DAC Driver
* AD3531R/AD3531 4-channel, 16-bit Voltage Output DAC Driver
+ * AD3532R/AD3532 16-channel, 16-bit Voltage Output DAC Driver
*
* Copyright 2025 Analog Devices Inc.
*/
@@ -38,6 +39,25 @@
#define AD3531R_SW_LDAC_TRIG_A 0xDD
#define AD3531R_INPUT_CH 0xE3
+/* AD3532R/AD3532 bank 0 registers (channels 0-7) */
+#define AD3532R_INTERFACE_CONFIG_A_0 0x1000
+#define AD3532R_OUTPUT_OPERATING_MODE_0 0x1020
+#define AD3532R_OUTPUT_OPERATING_MODE_1 0x1021
+#define AD3532R_OUTPUT_CONTROL_0 0x102A
+#define AD3532R_REFERENCE_CONTROL_0 0x103C
+#define AD3532R_SW_LDAC_TRIG_0 0x10E5
+#define AD3532R_INPUT_CH_0 0x10EB
+
+/* AD3532R/AD3532 bank 1 registers (channels 8-15) */
+#define AD3532R_INTERFACE_CONFIG_A_1 0x3000
+#define AD3532R_OUTPUT_OPERATING_MODE_2 0x3020
+#define AD3532R_OUTPUT_OPERATING_MODE_3 0x3021
+#define AD3532R_OUTPUT_CONTROL_1 0x302A
+#define AD3532R_REFERENCE_CONTROL_1 0x303C
+#define AD3532R_SW_LDAC_TRIG_1 0x30E5
+#define AD3532R_INPUT_CH_1 0x30EB
+#define AD3532R_MAX_REG_ADDR 0x30F9
+
#define AD3530R_SLD_TRIG_A BIT(7)
#define AD3530R_OUTPUT_CONTROL_RANGE BIT(2)
#define AD3530R_REFERENCE_CONTROL_SEL BIT(0)
@@ -49,8 +69,10 @@
#define AD3530R_LDAC_PULSE_US 100
#define AD3530R_DAC_MAX_VAL GENMASK(15, 0)
-#define AD3530R_MAX_CHANNELS 8
+#define AD3530R_CH_PER_REG 4
+#define AD3530R_CH_PER_BANK 8
#define AD3531R_MAX_CHANNELS 4
+#define AD3532R_MAX_CHANNELS 16
enum ad3530r_mode {
AD3530R_NORMAL_OP,
@@ -67,9 +89,16 @@ struct ad3530r_chan {
struct ad3530r_chip_info {
const char *name;
const struct iio_chan_spec *channels;
+ const struct regmap_config *regmap_config;
int (*input_ch_reg)(unsigned int channel);
+ int (*sw_ldac_trig_reg)(unsigned int channel);
+ const unsigned int *interface_config_a;
+ const unsigned int *output_control;
+ const unsigned int *reference_control;
+ const unsigned int *op_mode;
unsigned int num_channels;
- unsigned int sw_ldac_trig_reg;
+ unsigned int num_banks;
+ unsigned int num_op_mode_regs;
bool internal_ref_support;
};
@@ -77,7 +106,7 @@ struct ad3530r_state {
struct regmap *regmap;
/* lock to protect against multiple access to the device and shared data */
struct mutex lock;
- struct ad3530r_chan chan[AD3530R_MAX_CHANNELS];
+ struct ad3530r_chan chan[AD3532R_MAX_CHANNELS];
const struct ad3530r_chip_info *chip_info;
struct gpio_desc *ldac_gpio;
int vref_mV;
@@ -98,6 +127,14 @@ static int ad3531r_input_ch_reg(unsigned int channel)
return 2 * channel + AD3531R_INPUT_CH;
}
+static int ad3532r_input_ch_reg(unsigned int channel)
+{
+ unsigned int bank = channel / AD3530R_CH_PER_BANK;
+ unsigned int local_ch = channel % AD3530R_CH_PER_BANK;
+
+ return 2 * local_ch + (bank ? AD3532R_INPUT_CH_1 : AD3532R_INPUT_CH_0);
+}
+
static const char * const ad3530r_powerdown_modes[] = {
"1kohm_to_gnd",
"7.7kohm_to_gnd",
@@ -110,6 +147,12 @@ static const char * const ad3531r_powerdown_modes[] = {
"16kohm_to_gnd",
};
+static const char * const ad3532r_powerdown_modes[] = {
+ "1kohm_to_gnd",
+ "10kohm_to_gnd",
+ "three_state",
+};
+
static int ad3530r_get_powerdown_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
@@ -145,6 +188,13 @@ static const struct iio_enum ad3531r_powerdown_mode_enum = {
.set = ad3530r_set_powerdown_mode,
};
+static const struct iio_enum ad3532r_powerdown_mode_enum = {
+ .items = ad3532r_powerdown_modes,
+ .num_items = ARRAY_SIZE(ad3532r_powerdown_modes),
+ .get = ad3530r_get_powerdown_mode,
+ .set = ad3530r_set_powerdown_mode,
+};
+
static ssize_t ad3530r_get_dac_powerdown(struct iio_dev *indio_dev,
uintptr_t private,
const struct iio_chan_spec *chan,
@@ -189,6 +239,62 @@ static ssize_t ad3530r_set_dac_powerdown(struct iio_dev *indio_dev,
return len;
}
+static ssize_t ad3532r_set_dac_powerdown(struct iio_dev *indio_dev,
+ uintptr_t private,
+ const struct iio_chan_spec *chan,
+ const char *buf, size_t len)
+{
+ struct ad3530r_state *st = iio_priv(indio_dev);
+ unsigned int bank, local_ch, reg_in_bank, ch_in_reg;
+ unsigned int reg, mask, val;
+ bool powerdown;
+ int ret;
+
+ ret = kstrtobool(buf, &powerdown);
+ if (ret)
+ return ret;
+
+ bank = chan->channel / AD3530R_CH_PER_BANK;
+ local_ch = chan->channel % AD3530R_CH_PER_BANK;
+ reg_in_bank = local_ch / AD3530R_CH_PER_REG;
+ ch_in_reg = local_ch % AD3530R_CH_PER_REG;
+
+ reg = reg_in_bank + (bank ? AD3532R_OUTPUT_OPERATING_MODE_2 :
+ AD3532R_OUTPUT_OPERATING_MODE_0);
+ mask = AD3530R_OP_MODE_CHAN_MSK(ch_in_reg);
+
+ guard(mutex)(&st->lock);
+ if (powerdown) {
+ val = field_prep(mask, st->chan[chan->channel].powerdown_mode);
+ ret = regmap_update_bits(st->regmap, reg, mask, val);
+ } else {
+ ret = regmap_clear_bits(st->regmap, reg, mask);
+ }
+ if (ret)
+ return ret;
+
+ st->chan[chan->channel].powerdown = powerdown;
+
+ return len;
+}
+
+static int ad3530r_trigger_sw_ldac_reg(unsigned int channel)
+{
+ return AD3530R_SW_LDAC_TRIG_A;
+}
+
+static int ad3531r_trigger_sw_ldac_reg(unsigned int channel)
+{
+ return AD3531R_SW_LDAC_TRIG_A;
+}
+
+static int ad3532r_trigger_sw_ldac_reg(unsigned int channel)
+{
+ unsigned int bank = channel / AD3530R_CH_PER_BANK;
+
+ return bank ? AD3532R_SW_LDAC_TRIG_1 : AD3532R_SW_LDAC_TRIG_0;
+}
+
static int ad3530r_trigger_hw_ldac(struct gpio_desc *ldac_gpio)
{
gpiod_set_value_cansleep(ldac_gpio, 1);
@@ -214,7 +320,7 @@ static int ad3530r_dac_write(struct ad3530r_state *st, unsigned int chan,
if (st->ldac_gpio)
return ad3530r_trigger_hw_ldac(st->ldac_gpio);
- return regmap_set_bits(st->regmap, st->chip_info->sw_ldac_trig_reg,
+ return regmap_set_bits(st->regmap, st->chip_info->sw_ldac_trig_reg(chan),
AD3530R_SLD_TRIG_A);
}
@@ -301,6 +407,19 @@ static const struct iio_chan_spec_ext_info ad3531r_ext_info[] = {
{ }
};
+static const struct iio_chan_spec_ext_info ad3532r_ext_info[] = {
+ {
+ .name = "powerdown",
+ .shared = IIO_SEPARATE,
+ .read = ad3530r_get_dac_powerdown,
+ .write = ad3532r_set_dac_powerdown,
+ },
+ IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad3532r_powerdown_mode_enum),
+ IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE,
+ &ad3532r_powerdown_mode_enum),
+ { }
+};
+
#define AD3530R_CHAN(_chan, _ext_info) \
{ \
.type = IIO_VOLTAGE, \
@@ -330,48 +449,215 @@ static const struct iio_chan_spec ad3531r_channels[] = {
AD3530R_CHAN(3, ad3531r_ext_info),
};
+static const struct iio_chan_spec ad3532r_channels[] = {
+ AD3530R_CHAN(0, ad3532r_ext_info),
+ AD3530R_CHAN(1, ad3532r_ext_info),
+ AD3530R_CHAN(2, ad3532r_ext_info),
+ AD3530R_CHAN(3, ad3532r_ext_info),
+ AD3530R_CHAN(4, ad3532r_ext_info),
+ AD3530R_CHAN(5, ad3532r_ext_info),
+ AD3530R_CHAN(6, ad3532r_ext_info),
+ AD3530R_CHAN(7, ad3532r_ext_info),
+ AD3530R_CHAN(8, ad3532r_ext_info),
+ AD3530R_CHAN(9, ad3532r_ext_info),
+ AD3530R_CHAN(10, ad3532r_ext_info),
+ AD3530R_CHAN(11, ad3532r_ext_info),
+ AD3530R_CHAN(12, ad3532r_ext_info),
+ AD3530R_CHAN(13, ad3532r_ext_info),
+ AD3530R_CHAN(14, ad3532r_ext_info),
+ AD3530R_CHAN(15, ad3532r_ext_info),
+};
+
+static const unsigned int ad3530r_if_config[] = {
+ AD3530R_INTERFACE_CONFIG_A,
+};
+
+static const unsigned int ad3530r_out_ctrl[] = {
+ AD3530R_OUTPUT_CONTROL_0,
+};
+
+static const unsigned int ad3530r_ref_ctrl[] = {
+ AD3530R_REFERENCE_CONTROL_0,
+};
+
+static const unsigned int ad3530r_op_mode[] = {
+ AD3530R_OUTPUT_OPERATING_MODE_0,
+ AD3530R_OUTPUT_OPERATING_MODE_1,
+};
+
+static const unsigned int ad3531r_op_mode[] = {
+ AD3530R_OUTPUT_OPERATING_MODE_0,
+};
+
+static const unsigned int ad3532r_if_config[] = {
+ AD3532R_INTERFACE_CONFIG_A_0,
+ AD3532R_INTERFACE_CONFIG_A_1,
+};
+
+static const unsigned int ad3532r_out_ctrl[] = {
+ AD3532R_OUTPUT_CONTROL_0,
+ AD3532R_OUTPUT_CONTROL_1,
+};
+
+static const unsigned int ad3532r_ref_ctrl[] = {
+ AD3532R_REFERENCE_CONTROL_0,
+ AD3532R_REFERENCE_CONTROL_1,
+};
+
+static const unsigned int ad3532r_op_mode[] = {
+ AD3532R_OUTPUT_OPERATING_MODE_0,
+ AD3532R_OUTPUT_OPERATING_MODE_1,
+ AD3532R_OUTPUT_OPERATING_MODE_2,
+ AD3532R_OUTPUT_OPERATING_MODE_3,
+};
+
+static const struct regmap_config ad3530r_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .max_register = AD3530R_MAX_REG_ADDR,
+};
+
+static const struct regmap_config ad3532r_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .max_register = AD3532R_MAX_REG_ADDR,
+};
+
static const struct ad3530r_chip_info ad3530_chip = {
.name = "ad3530",
.channels = ad3530r_channels,
+ .regmap_config = &ad3530r_regmap_config,
.num_channels = ARRAY_SIZE(ad3530r_channels),
- .sw_ldac_trig_reg = AD3530R_SW_LDAC_TRIG_A,
+ .sw_ldac_trig_reg = ad3530r_trigger_sw_ldac_reg,
.input_ch_reg = ad3530r_input_ch_reg,
+ .interface_config_a = ad3530r_if_config,
+ .output_control = ad3530r_out_ctrl,
+ .reference_control = ad3530r_ref_ctrl,
+ .op_mode = ad3530r_op_mode,
+ .num_banks = ARRAY_SIZE(ad3530r_if_config),
+ .num_op_mode_regs = ARRAY_SIZE(ad3530r_op_mode),
.internal_ref_support = false,
};
static const struct ad3530r_chip_info ad3530r_chip = {
.name = "ad3530r",
.channels = ad3530r_channels,
+ .regmap_config = &ad3530r_regmap_config,
.num_channels = ARRAY_SIZE(ad3530r_channels),
- .sw_ldac_trig_reg = AD3530R_SW_LDAC_TRIG_A,
+ .sw_ldac_trig_reg = ad3530r_trigger_sw_ldac_reg,
.input_ch_reg = ad3530r_input_ch_reg,
+ .interface_config_a = ad3530r_if_config,
+ .output_control = ad3530r_out_ctrl,
+ .reference_control = ad3530r_ref_ctrl,
+ .op_mode = ad3530r_op_mode,
+ .num_banks = ARRAY_SIZE(ad3530r_if_config),
+ .num_op_mode_regs = ARRAY_SIZE(ad3530r_op_mode),
.internal_ref_support = true,
};
static const struct ad3530r_chip_info ad3531_chip = {
.name = "ad3531",
.channels = ad3531r_channels,
+ .regmap_config = &ad3530r_regmap_config,
.num_channels = ARRAY_SIZE(ad3531r_channels),
- .sw_ldac_trig_reg = AD3531R_SW_LDAC_TRIG_A,
+ .sw_ldac_trig_reg = ad3531r_trigger_sw_ldac_reg,
.input_ch_reg = ad3531r_input_ch_reg,
+ .interface_config_a = ad3530r_if_config,
+ .output_control = ad3530r_out_ctrl,
+ .reference_control = ad3530r_ref_ctrl,
+ .op_mode = ad3531r_op_mode,
+ .num_banks = ARRAY_SIZE(ad3530r_if_config),
+ .num_op_mode_regs = ARRAY_SIZE(ad3531r_op_mode),
.internal_ref_support = false,
};
static const struct ad3530r_chip_info ad3531r_chip = {
.name = "ad3531r",
.channels = ad3531r_channels,
+ .regmap_config = &ad3530r_regmap_config,
.num_channels = ARRAY_SIZE(ad3531r_channels),
- .sw_ldac_trig_reg = AD3531R_SW_LDAC_TRIG_A,
+ .sw_ldac_trig_reg = ad3531r_trigger_sw_ldac_reg,
.input_ch_reg = ad3531r_input_ch_reg,
+ .interface_config_a = ad3530r_if_config,
+ .output_control = ad3530r_out_ctrl,
+ .reference_control = ad3530r_ref_ctrl,
+ .op_mode = ad3531r_op_mode,
+ .num_banks = ARRAY_SIZE(ad3530r_if_config),
+ .num_op_mode_regs = ARRAY_SIZE(ad3531r_op_mode),
+ .internal_ref_support = true,
+};
+
+static const struct ad3530r_chip_info ad3532_chip = {
+ .name = "ad3532",
+ .channels = ad3532r_channels,
+ .regmap_config = &ad3532r_regmap_config,
+ .num_channels = ARRAY_SIZE(ad3532r_channels),
+ .sw_ldac_trig_reg = ad3532r_trigger_sw_ldac_reg,
+ .input_ch_reg = ad3532r_input_ch_reg,
+ .interface_config_a = ad3532r_if_config,
+ .output_control = ad3532r_out_ctrl,
+ .reference_control = ad3532r_ref_ctrl,
+ .op_mode = ad3532r_op_mode,
+ .num_banks = ARRAY_SIZE(ad3532r_if_config),
+ .num_op_mode_regs = ARRAY_SIZE(ad3532r_op_mode),
+ .internal_ref_support = false,
+};
+
+static const struct ad3530r_chip_info ad3532r_chip = {
+ .name = "ad3532r",
+ .channels = ad3532r_channels,
+ .regmap_config = &ad3532r_regmap_config,
+ .num_channels = ARRAY_SIZE(ad3532r_channels),
+ .sw_ldac_trig_reg = ad3532r_trigger_sw_ldac_reg,
+ .input_ch_reg = ad3532r_input_ch_reg,
+ .interface_config_a = ad3532r_if_config,
+ .output_control = ad3532r_out_ctrl,
+ .reference_control = ad3532r_ref_ctrl,
+ .op_mode = ad3532r_op_mode,
+ .num_banks = ARRAY_SIZE(ad3532r_if_config),
+ .num_op_mode_regs = ARRAY_SIZE(ad3532r_op_mode),
.internal_ref_support = true,
};
+static int ad3530r_set_reg_bank_bits(const struct ad3530r_state *st,
+ const unsigned int *regs,
+ unsigned int num_regs,
+ unsigned int mask)
+{
+ int ret;
+
+ for (unsigned int i = 0; i < num_regs; i++) {
+ ret = regmap_set_bits(st->regmap, regs[i], mask);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ad3530r_write_reg_banks(const struct ad3530r_state *st,
+ const unsigned int *regs,
+ unsigned int num_regs,
+ unsigned int val)
+{
+ int ret;
+
+ for (unsigned int i = 0; i < num_regs; i++) {
+ ret = regmap_write(st->regmap, regs[i], val);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static int ad3530r_setup(struct ad3530r_state *st, int external_vref_uV)
{
+ const struct ad3530r_chip_info *chip_info = st->chip_info;
struct device *dev = regmap_get_device(st->regmap);
struct gpio_desc *reset_gpio;
- int i, ret;
u8 range_multiplier, val;
+ int ret;
reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(reset_gpio))
@@ -384,8 +670,9 @@ static int ad3530r_setup(struct ad3530r_state *st, int external_vref_uV)
gpiod_set_value_cansleep(reset_gpio, 0);
} else {
/* Perform software reset */
- ret = regmap_update_bits(st->regmap, AD3530R_INTERFACE_CONFIG_A,
- AD3530R_SW_RESET, AD3530R_SW_RESET);
+ ret = ad3530r_set_reg_bank_bits(st, chip_info->interface_config_a,
+ chip_info->num_banks,
+ AD3530R_SW_RESET);
if (ret)
return ret;
}
@@ -394,8 +681,9 @@ static int ad3530r_setup(struct ad3530r_state *st, int external_vref_uV)
range_multiplier = 1;
if (device_property_read_bool(dev, "adi,range-double")) {
- ret = regmap_set_bits(st->regmap, AD3530R_OUTPUT_CONTROL_0,
- AD3530R_OUTPUT_CONTROL_RANGE);
+ ret = ad3530r_set_reg_bank_bits(st, chip_info->output_control,
+ chip_info->num_banks,
+ AD3530R_OUTPUT_CONTROL_RANGE);
if (ret)
return ret;
@@ -405,8 +693,9 @@ static int ad3530r_setup(struct ad3530r_state *st, int external_vref_uV)
if (external_vref_uV) {
st->vref_mV = range_multiplier * external_vref_uV / MILLI;
} else {
- ret = regmap_set_bits(st->regmap, AD3530R_REFERENCE_CONTROL_0,
- AD3530R_REFERENCE_CONTROL_SEL);
+ ret = ad3530r_set_reg_bank_bits(st, chip_info->reference_control,
+ chip_info->num_banks,
+ AD3530R_REFERENCE_CONTROL_SEL);
if (ret)
return ret;
@@ -419,18 +708,12 @@ static int ad3530r_setup(struct ad3530r_state *st, int external_vref_uV)
FIELD_PREP(AD3530R_OP_MODE_CHAN_MSK(2), AD3530R_NORMAL_OP) |
FIELD_PREP(AD3530R_OP_MODE_CHAN_MSK(3), AD3530R_NORMAL_OP);
- ret = regmap_write(st->regmap, AD3530R_OUTPUT_OPERATING_MODE_0, val);
+ ret = ad3530r_write_reg_banks(st, st->chip_info->op_mode,
+ st->chip_info->num_op_mode_regs, val);
if (ret)
return ret;
- if (st->chip_info->num_channels > 4) {
- ret = regmap_write(st->regmap, AD3530R_OUTPUT_OPERATING_MODE_1,
- val);
- if (ret)
- return ret;
- }
-
- for (i = 0; i < st->chip_info->num_channels; i++)
+ for (unsigned int i = 0; i < st->chip_info->num_channels; i++)
st->chan[i].powerdown_mode = AD3530R_POWERDOWN_32K;
st->ldac_gpio = devm_gpiod_get_optional(dev, "ldac", GPIOD_OUT_LOW);
@@ -441,12 +724,6 @@ static int ad3530r_setup(struct ad3530r_state *st, int external_vref_uV)
return 0;
}
-static const struct regmap_config ad3530r_regmap_config = {
- .reg_bits = 16,
- .val_bits = 8,
- .max_register = AD3530R_MAX_REG_ADDR,
-};
-
static const struct iio_info ad3530r_info = {
.read_raw = ad3530r_read_raw,
.write_raw = ad3530r_write_raw,
@@ -467,7 +744,11 @@ static int ad3530r_probe(struct spi_device *spi)
st = iio_priv(indio_dev);
- st->regmap = devm_regmap_init_spi(spi, &ad3530r_regmap_config);
+ st->chip_info = spi_get_device_match_data(spi);
+ if (!st->chip_info)
+ return -ENODEV;
+
+ st->regmap = devm_regmap_init_spi(spi, st->chip_info->regmap_config);
if (IS_ERR(st->regmap))
return dev_err_probe(dev, PTR_ERR(st->regmap),
"Failed to init regmap");
@@ -476,10 +757,6 @@ static int ad3530r_probe(struct spi_device *spi)
if (ret)
return ret;
- st->chip_info = spi_get_device_match_data(spi);
- if (!st->chip_info)
- return -ENODEV;
-
ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulators),
regulators);
if (ret)
@@ -513,6 +790,8 @@ static const struct spi_device_id ad3530r_id[] = {
{ .name = "ad3530r", .driver_data = (kernel_ulong_t)&ad3530r_chip },
{ .name = "ad3531", .driver_data = (kernel_ulong_t)&ad3531_chip },
{ .name = "ad3531r", .driver_data = (kernel_ulong_t)&ad3531r_chip },
+ { .name = "ad3532", .driver_data = (kernel_ulong_t)&ad3532_chip },
+ { .name = "ad3532r", .driver_data = (kernel_ulong_t)&ad3532r_chip },
{ }
};
MODULE_DEVICE_TABLE(spi, ad3530r_id);
@@ -522,6 +801,8 @@ static const struct of_device_id ad3530r_of_match[] = {
{ .compatible = "adi,ad3530r", .data = &ad3530r_chip },
{ .compatible = "adi,ad3531", .data = &ad3531_chip },
{ .compatible = "adi,ad3531r", .data = &ad3531r_chip },
+ { .compatible = "adi,ad3532", .data = &ad3532_chip },
+ { .compatible = "adi,ad3532r", .data = &ad3532r_chip },
{ }
};
MODULE_DEVICE_TABLE(of, ad3530r_of_match);
diff --git a/drivers/iio/dac/ad8460.c b/drivers/iio/dac/ad8460.c
index ddec62b6e57b..a2292810e4cf 100644
--- a/drivers/iio/dac/ad8460.c
+++ b/drivers/iio/dac/ad8460.c
@@ -954,3 +954,4 @@ MODULE_AUTHOR("Mariel Tinaco <mariel.tinaco@analog.com");
MODULE_DESCRIPTION("AD8460 DAC driver");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS("IIO_DMAENGINE_BUFFER");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/iio/dac/dpot-dac.c b/drivers/iio/dac/dpot-dac.c
index cf6d94e7af84..de36e2e27330 100644
--- a/drivers/iio/dac/dpot-dac.c
+++ b/drivers/iio/dac/dpot-dac.c
@@ -253,3 +253,4 @@ module_platform_driver(dpot_dac_driver);
MODULE_DESCRIPTION("DAC emulation driver using a digital potentiometer");
MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/iio/dac/mcf54415_dac.c b/drivers/iio/dac/mcf54415_dac.c
new file mode 100644
index 000000000000..e2c12241a534
--- /dev/null
+++ b/drivers/iio/dac/mcf54415_dac.c
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * NXP mcf54415 DAC driver
+ *
+ * Copyright 2026 BayLibre - adureghello@baylibre.com
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+#include <linux/iio/iio.h>
+
+#define MCF54415_DAC_CR 0x00
+#define MCF54415_DAC_CR_PDN BIT(0)
+#define MCF54415_DAC_CR_HSLS BIT(6)
+#define MCF54415_DAC_CR_WMLVL GENMASK(9, 8)
+#define MCF54415_DAC_CR_FILT BIT(12)
+
+#define MCF54415_DAC_DATA 0x02
+
+struct mcf54415_dac {
+ struct regmap *map;
+ struct clk *clk;
+};
+
+static const struct regmap_config mcf54415_dac_regmap_config = {
+ .reg_bits = 16,
+ .reg_stride = 2,
+ .val_bits = 16,
+ .max_register = 0x0c, /* DACX_FILTCNT, R.M. Table 30-2 */
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+ .reg_format_endian = REGMAP_ENDIAN_BIG,
+};
+
+static int mcf54415_dac_init(struct mcf54415_dac *info)
+{
+ u16 val = MCF54415_DAC_CR_FILT | FIELD_PREP(MCF54415_DAC_CR_WMLVL, 1);
+ int ret;
+
+ /* Fixed defaults and enable DAC (bit 0 set to 0) */
+ ret = regmap_write(info->map, MCF54415_DAC_CR, val);
+ if (ret)
+ return ret;
+
+ /* DAC is ready after 12us, from RM table 40-3 */
+ fsleep(12);
+
+ return 0;
+}
+
+static void mcf54415_dac_exit(void *data)
+{
+ struct mcf54415_dac *info = data;
+
+ regmap_set_bits(info->map, MCF54415_DAC_CR, MCF54415_DAC_CR_PDN);
+}
+
+static const struct iio_chan_spec mcf54415_dac_iio_channel = {
+ .type = IIO_VOLTAGE,
+ .output = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+};
+
+static int mcf54415_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct mcf54415_dac *info = iio_priv(indio_dev);
+ unsigned int reg;
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = regmap_read(info->map, MCF54415_DAC_DATA, &reg);
+ if (ret)
+ return ret;
+ *val = reg & GENMASK(11, 0);
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ /* Reference voltage as per ColdFire datasheet is 3.3V */
+ *val = 3300 /* mV */;
+ *val2 = 12;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mcf54415_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct mcf54415_dac *info = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ /* Check based on RM 30.3.2 (DACn_DATA) reg. resolution */
+ if (val < 0 || val > 4095)
+ return -EINVAL;
+ return regmap_write(info->map, MCF54415_DAC_DATA, val);
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info mcf54415_dac_iio_info = {
+ .read_raw = &mcf54415_read_raw,
+ .write_raw = &mcf54415_write_raw,
+};
+
+static int mcf54415_dac_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct iio_dev *indio_dev;
+ struct mcf54415_dac *info;
+ void __iomem *regs;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*info));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ info = iio_priv(indio_dev);
+
+ regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(regs))
+ return dev_err_probe(dev, PTR_ERR(regs), "failed to get io regs\n");
+
+ info->map = devm_regmap_init_mmio(dev, regs, &mcf54415_dac_regmap_config);
+ if (IS_ERR(info->map))
+ return PTR_ERR(info->map);
+
+ info->clk = devm_clk_get_enabled(dev, "dac");
+ if (IS_ERR(info->clk))
+ return dev_err_probe(dev, PTR_ERR(info->clk), "failed getting clock\n");
+
+ indio_dev->name = "mcf54415";
+ indio_dev->info = &mcf54415_dac_iio_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = &mcf54415_dac_iio_channel;
+ indio_dev->num_channels = 1;
+
+ ret = mcf54415_dac_init(info);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, mcf54415_dac_exit, info);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct platform_device_id mcf54415_dac_ids[] = {
+ { .name = "mcfdac" },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, mcf54415_dac_ids);
+
+static struct platform_driver mcf54415_dac_driver = {
+ .driver = {
+ .name = "mcf54415_dac",
+ },
+ .probe = mcf54415_dac_probe,
+ .id_table = mcf54415_dac_ids,
+};
+module_platform_driver(mcf54415_dac_driver);
+
+MODULE_AUTHOR("Angelo Dureghello <angelo@kernel-space.org>");
+MODULE_DESCRIPTION("NXP MCF54415 DAC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c
index 4bc3c387cb17..58250a972567 100644
--- a/drivers/iio/gyro/hid-sensor-gyro-3d.c
+++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c
@@ -84,9 +84,8 @@ static const struct iio_chan_spec gyro_3d_channels[] = {
/* Channel read_raw handler */
static int gyro_3d_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int *val, int *val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
{
struct gyro_3d_state *gyro_state = iio_priv(indio_dev);
int report_id = -1;
@@ -111,8 +110,7 @@ static int gyro_3d_read_raw(struct iio_dev *indio_dev,
min < 0);
else {
*val = 0;
- hid_sensor_power_state(&gyro_state->common_attributes,
- false);
+ hid_sensor_power_state(&gyro_state->common_attributes, false);
return -EINVAL;
}
hid_sensor_power_state(&gyro_state->common_attributes, false);
@@ -145,10 +143,8 @@ static int gyro_3d_read_raw(struct iio_dev *indio_dev,
/* Channel write_raw handler */
static int gyro_3d_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val,
- int val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
{
struct gyro_3d_state *gyro_state = iio_priv(indio_dev);
int ret = 0;
@@ -176,8 +172,7 @@ static const struct iio_info gyro_3d_info = {
/* Callback handler to send event after all samples are received and captured */
static int gyro_3d_proc_event(struct hid_sensor_hub_device *hsdev,
- u32 usage_id,
- void *priv)
+ u32 usage_id, void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct gyro_3d_state *gyro_state = iio_priv(indio_dev);
@@ -198,9 +193,9 @@ static int gyro_3d_proc_event(struct hid_sensor_hub_device *hsdev,
/* Capture samples in local storage */
static int gyro_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
- u32 usage_id,
- size_t raw_len, char *raw_data,
- void *priv)
+ u32 usage_id,
+ size_t raw_len, char *raw_data,
+ void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct gyro_3d_state *gyro_state = iio_priv(indio_dev);
@@ -253,10 +248,10 @@ static int gyro_3d_parse_report(struct platform_device *pdev,
};
}
dev_dbg(&pdev->dev, "gyro_3d %x:%x, %x:%x, %x:%x\n",
- st->gyro[0].index,
- st->gyro[0].report_id,
- st->gyro[1].index, st->gyro[1].report_id,
- st->gyro[2].index, st->gyro[2].report_id);
+ st->gyro[0].index,
+ st->gyro[0].report_id,
+ st->gyro[1].index, st->gyro[1].report_id,
+ st->gyro[2].index, st->gyro[2].report_id);
st->scale_precision = hid_sensor_format_scale(
HID_USAGE_SENSOR_GYRO_3D,
@@ -317,32 +312,32 @@ static int hid_gyro_3d_probe(struct platform_device *pdev)
atomic_set(&gyro_state->common_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name,
- &gyro_state->common_attributes);
+ &gyro_state->common_attributes);
if (ret < 0) {
dev_err(&pdev->dev, "trigger setup failed\n");
return ret;
}
- ret = iio_device_register(indio_dev);
- if (ret) {
- dev_err(&pdev->dev, "device register failed\n");
- goto error_remove_trigger;
- }
-
gyro_state->callbacks.send_event = gyro_3d_proc_event;
gyro_state->callbacks.capture_sample = gyro_3d_capture_sample;
gyro_state->callbacks.pdev = pdev;
ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D,
- &gyro_state->callbacks);
+ &gyro_state->callbacks);
if (ret < 0) {
dev_err(&pdev->dev, "callback reg failed\n");
- goto error_iio_unreg;
+ goto error_remove_trigger;
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "device register failed\n");
+ goto error_remove_callback;
}
return ret;
-error_iio_unreg:
- iio_device_unregister(indio_dev);
+error_remove_callback:
+ sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D);
error_remove_trigger:
hid_sensor_remove_trigger(indio_dev, &gyro_state->common_attributes);
return ret;
@@ -355,8 +350,8 @@ static void hid_gyro_3d_remove(struct platform_device *pdev)
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct gyro_3d_state *gyro_state = iio_priv(indio_dev);
- sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D);
iio_device_unregister(indio_dev);
+ sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D);
hid_sensor_remove_trigger(indio_dev, &gyro_state->common_attributes);
}
diff --git a/drivers/iio/humidity/hid-sensor-humidity.c b/drivers/iio/humidity/hid-sensor-humidity.c
index 7751abb58bb9..7cec81ff5685 100644
--- a/drivers/iio/humidity/hid-sensor-humidity.c
+++ b/drivers/iio/humidity/hid-sensor-humidity.c
@@ -44,7 +44,7 @@ static const struct iio_chan_spec humidity_channels[] = {
/* Adjust channel real bits based on report descriptor */
static void humidity_adjust_channel_bit_mask(struct iio_chan_spec *channels,
- int channel, int size)
+ int channel, int size)
{
channels[channel].scan_type.sign = 's';
/* Real storage bits will change based on the report desc. */
@@ -54,8 +54,8 @@ static void humidity_adjust_channel_bit_mask(struct iio_chan_spec *channels,
}
static int humidity_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int *val, int *val2, long mask)
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
{
struct hid_humidity_state *humid_st = iio_priv(indio_dev);
@@ -100,8 +100,8 @@ static int humidity_read_raw(struct iio_dev *indio_dev,
}
static int humidity_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val, int val2, long mask)
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
{
struct hid_humidity_state *humid_st = iio_priv(indio_dev);
@@ -126,7 +126,7 @@ static const struct iio_info humidity_info = {
/* Callback handler to send event after all samples are received and captured */
static int humidity_proc_event(struct hid_sensor_hub_device *hsdev,
- u32 usage_id, void *pdev)
+ u32 usage_id, void *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct hid_humidity_state *humid_st = iio_priv(indio_dev);
@@ -140,8 +140,9 @@ static int humidity_proc_event(struct hid_sensor_hub_device *hsdev,
/* Capture samples in local storage */
static int humidity_capture_sample(struct hid_sensor_hub_device *hsdev,
- u32 usage_id, size_t raw_len,
- char *raw_data, void *pdev)
+ u32 usage_id,
+ size_t raw_len, char *raw_data,
+ void *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct hid_humidity_state *humid_st = iio_priv(indio_dev);
@@ -158,10 +159,10 @@ static int humidity_capture_sample(struct hid_sensor_hub_device *hsdev,
/* Parse report which is specific to an usage id */
static int humidity_parse_report(struct platform_device *pdev,
- struct hid_sensor_hub_device *hsdev,
- struct iio_chan_spec *channels,
- u32 usage_id,
- struct hid_humidity_state *st)
+ struct hid_sensor_hub_device *hsdev,
+ struct iio_chan_spec *channels,
+ u32 usage_id,
+ struct hid_humidity_state *st)
{
int ret;
@@ -214,13 +215,13 @@ static int hid_humidity_probe(struct platform_device *pdev)
if (ret)
return ret;
- humid_chans = devm_kmemdup(&indio_dev->dev, humidity_channels,
- sizeof(humidity_channels), GFP_KERNEL);
+ humid_chans = devm_kmemdup(&pdev->dev, humidity_channels,
+ sizeof(humidity_channels), GFP_KERNEL);
if (!humid_chans)
return -ENOMEM;
ret = humidity_parse_report(pdev, hsdev, humid_chans,
- HID_USAGE_SENSOR_HUMIDITY, humid_st);
+ HID_USAGE_SENSOR_HUMIDITY, humid_st);
if (ret)
return ret;
@@ -233,7 +234,7 @@ static int hid_humidity_probe(struct platform_device *pdev)
atomic_set(&humid_st->common_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name,
- &humid_st->common_attributes);
+ &humid_st->common_attributes);
if (ret)
return ret;
@@ -241,7 +242,7 @@ static int hid_humidity_probe(struct platform_device *pdev)
humidity_callbacks.pdev = pdev;
ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_HUMIDITY,
- &humidity_callbacks);
+ &humidity_callbacks);
if (ret)
goto error_remove_trigger;
diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c
index 8603103cede0..5187566c1876 100644
--- a/drivers/iio/imu/adis16480.c
+++ b/drivers/iio/imu/adis16480.c
@@ -110,7 +110,7 @@
#define ADIS16480_REG_SERIAL_NUM ADIS16480_REG(0x04, 0x20)
-/* Each filter coefficent bank spans two pages */
+/* Each filter coefficient bank spans two pages */
#define ADIS16480_FIR_COEF(page) (x < 60 ? ADIS16480_REG(page, (x) + 8) : \
ADIS16480_REG((page) + 1, (x) - 60 + 8))
#define ADIS16480_FIR_COEF_A(x) ADIS16480_FIR_COEF(0x05, (x))
@@ -1467,7 +1467,7 @@ static irqreturn_t adis16480_trigger_handler(int irq, void *p)
* We need to perform the padding to have the buffer
* elements naturally aligned in case there are any
* 32-bit storage size channels enabled which are added
- * in the buffer after the temprature data. In case
+ * in the buffer after the temperature data. In case
* there is no data being added after the temperature
* data, the padding is harmless.
*/
diff --git a/drivers/iio/imu/adis16550.c b/drivers/iio/imu/adis16550.c
index 1e435d60cd6d..096a612865c4 100644
--- a/drivers/iio/imu/adis16550.c
+++ b/drivers/iio/imu/adis16550.c
@@ -88,25 +88,7 @@ struct adis16550_sync {
u16 max_rate;
};
-struct adis16550_chip_info {
- const struct iio_chan_spec *channels;
- const struct adis16550_sync *sync_mode;
- char *name;
- u32 num_channels;
- u32 gyro_max_val;
- u32 gyro_max_scale;
- u32 accel_max_val;
- u32 accel_max_scale;
- u32 temp_scale;
- u32 deltang_max_val;
- u32 deltvel_max_val;
- u32 int_clk;
- u16 max_dec;
- u16 num_sync;
-};
-
struct adis16550 {
- const struct adis16550_chip_info *info;
struct adis adis;
unsigned long clk_freq_hz;
u32 sync_mode;
@@ -449,8 +431,8 @@ static int adis16550_set_freq_hz(struct adis16550 *st, u32 freq_hz)
* The optimal sample rate for the supported IMUs is between
* int_clk - 1000 and int_clk + 500.
*/
- u32 max_sample_rate = st->info->int_clk * 1000 + 500000;
- u32 min_sample_rate = st->info->int_clk * 1000 - 1000000;
+ u32 max_sample_rate = 4000 * 1000 + 500000;
+ u32 min_sample_rate = 4000 * 1000 - 1000000;
if (!freq_hz)
return -EINVAL;
@@ -483,7 +465,7 @@ static int adis16550_set_freq_hz(struct adis16550 *st, u32 freq_hz)
if (dec)
dec--;
- dec = min(dec, st->info->max_dec);
+ dec = min(dec, 4095);
return __adis_write_reg_16(&st->adis, ADIS16550_REG_DEC_RATE, dec);
}
@@ -591,30 +573,30 @@ static int adis16550_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_ANGL_VEL:
- *val = st->info->gyro_max_val;
- *val2 = st->info->gyro_max_scale;
+ *val = 1;
+ *val2 = IIO_RAD_TO_DEGREE(80 << 16);
return IIO_VAL_FRACTIONAL;
case IIO_ACCEL:
- *val = st->info->accel_max_val;
- *val2 = st->info->accel_max_scale;
+ *val = 1;
+ *val2 = IIO_M_S_2_TO_G(102400000);
return IIO_VAL_FRACTIONAL;
case IIO_TEMP:
- *val = st->info->temp_scale;
+ *val = 4;
return IIO_VAL_INT;
case IIO_DELTA_ANGL:
- *val = st->info->deltang_max_val;
+ *val = IIO_DEGREE_TO_RAD(720);
*val2 = 31;
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_DELTA_VELOCITY:
- *val = st->info->deltvel_max_val;
+ *val = 125;
*val2 = 31;
return IIO_VAL_FRACTIONAL_LOG2;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_OFFSET:
- /* temperature centered at 25°C */
- *val = DIV_ROUND_CLOSEST(25000, st->info->temp_scale);
+ /* temperature centered at 25°C divided by temp scale */
+ *val = 25000 / 4;
return IIO_VAL_INT;
case IIO_CHAN_INFO_CALIBBIAS:
ret = adis_read_reg_32(&st->adis,
@@ -792,23 +774,6 @@ static const struct adis16550_sync adis16550_sync_modes[] = {
{ ADIS16550_SYNC_MODE_SCALED, 1, 128 },
};
-static const struct adis16550_chip_info adis16550_chip_info = {
- .num_channels = ARRAY_SIZE(adis16550_channels),
- .channels = adis16550_channels,
- .name = "adis16550",
- .gyro_max_val = 1,
- .gyro_max_scale = IIO_RAD_TO_DEGREE(80 << 16),
- .accel_max_val = 1,
- .accel_max_scale = IIO_M_S_2_TO_G(102400000),
- .temp_scale = 4,
- .deltang_max_val = IIO_DEGREE_TO_RAD(720),
- .deltvel_max_val = 125,
- .int_clk = 4000,
- .max_dec = 4095,
- .sync_mode = adis16550_sync_modes,
- .num_sync = ARRAY_SIZE(adis16550_sync_modes),
-};
-
static u32 adis16550_validate_crc(__be32 *buffer, const u8 n_elem)
{
int i;
@@ -917,21 +882,21 @@ static int adis16550_config_sync(struct adis16550 *st)
if (IS_ERR(clk))
return PTR_ERR(clk);
if (!clk) {
- st->clk_freq_hz = st->info->int_clk * 1000;
+ st->clk_freq_hz = 4000000;
return 0;
}
st->clk_freq_hz = clk_get_rate(clk);
- for (i = 0; i < st->info->num_sync; i++) {
- if (st->clk_freq_hz >= st->info->sync_mode[i].min_rate &&
- st->clk_freq_hz <= st->info->sync_mode[i].max_rate) {
- sync_mode_data = &st->info->sync_mode[i];
+ for (i = 0; i < ARRAY_SIZE(adis16550_sync_modes); i++) {
+ if (st->clk_freq_hz >= adis16550_sync_modes[i].min_rate &&
+ st->clk_freq_hz <= adis16550_sync_modes[i].max_rate) {
+ sync_mode_data = &adis16550_sync_modes[i];
break;
}
}
- if (i == st->info->num_sync)
+ if (i == ARRAY_SIZE(adis16550_sync_modes))
return dev_err_probe(dev, -EINVAL, "Clk rate: %lu not in a valid range",
st->clk_freq_hz);
@@ -942,7 +907,7 @@ static int adis16550_config_sync(struct adis16550 *st)
* of [3000 4500].
*/
- sync_scale = DIV_ROUND_CLOSEST(st->info->int_clk, st->clk_freq_hz);
+ sync_scale = DIV_ROUND_CLOSEST(4000, st->clk_freq_hz);
if (3000 > sync_scale || 4500 < sync_scale)
return dev_err_probe(dev, -EINVAL,
@@ -954,7 +919,7 @@ static int adis16550_config_sync(struct adis16550 *st)
if (ret)
return ret;
- st->clk_freq_hz = st->info->int_clk;
+ st->clk_freq_hz = 4000;
}
st->clk_freq_hz *= 1000;
@@ -1063,13 +1028,11 @@ static int adis16550_probe(struct spi_device *spi)
return -ENOMEM;
st = iio_priv(indio_dev);
- st->info = spi_get_device_match_data(spi);
- if (!st->info)
- return -EINVAL;
+
adis = &st->adis;
- indio_dev->name = st->info->name;
- indio_dev->channels = st->info->channels;
- indio_dev->num_channels = st->info->num_channels;
+ indio_dev->name = "adis16550";
+ indio_dev->channels = adis16550_channels;
+ indio_dev->num_channels = ARRAY_SIZE(adis16550_channels);
indio_dev->available_scan_masks = adis16550_channel_masks;
indio_dev->info = &adis16550_info;
indio_dev->modes = INDIO_DIRECT_MODE;
@@ -1116,13 +1079,13 @@ static int adis16550_probe(struct spi_device *spi)
}
static const struct spi_device_id adis16550_id[] = {
- { "adis16550", (kernel_ulong_t)&adis16550_chip_info},
+ { .name = "adis16550" },
{ }
};
MODULE_DEVICE_TABLE(spi, adis16550_id);
static const struct of_device_id adis16550_of_match[] = {
- { .compatible = "adi,adis16550", .data = &adis16550_chip_info },
+ { .compatible = "adi,adis16550" },
{ }
};
MODULE_DEVICE_TABLE(of, adis16550_of_match);
diff --git a/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c
index 86f6ecfd64aa..1e73a7f1f017 100644
--- a/drivers/iio/imu/bmi160/bmi160_core.c
+++ b/drivers/iio/imu/bmi160/bmi160_core.c
@@ -5,7 +5,7 @@
* Copyright (c) 2016, Intel Corporation.
* Copyright (c) 2019, Martin Kelly.
*
- * IIO core driver for BMI160, with support for I2C/SPI busses
+ * IIO core driver for BMI160, with support for I2C/SPI buses
*
* TODO: magnetometer, hardware FIFO
*/
diff --git a/drivers/iio/imu/bmi270/bmi270_spi.c b/drivers/iio/imu/bmi270/bmi270_spi.c
index b6cfc5f3844e..759b56b59e54 100644
--- a/drivers/iio/imu/bmi270/bmi270_spi.c
+++ b/drivers/iio/imu/bmi270/bmi270_spi.c
@@ -75,6 +75,7 @@ static const struct of_device_id bmi270_of_match[] = {
{ .compatible = "bosch,bmi270", .data = &bmi270_chip_info },
{ }
};
+MODULE_DEVICE_TABLE(of, bmi270_of_match);
static struct spi_driver bmi270_spi_driver = {
.driver = {
diff --git a/drivers/iio/imu/fxos8700_core.c b/drivers/iio/imu/fxos8700_core.c
index 281ebfd9c15a..9d2eb6fbab4a 100644
--- a/drivers/iio/imu/fxos8700_core.c
+++ b/drivers/iio/imu/fxos8700_core.c
@@ -2,7 +2,7 @@
/*
* FXOS8700 - NXP IMU (accelerometer plus magnetometer)
*
- * IIO core driver for FXOS8700, with support for I2C/SPI busses
+ * IIO core driver for FXOS8700, with support for I2C/SPI buses
*
* TODO: Buffer, trigger, and IRQ support
*/
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h
index c8b48a5c5ed0..b55d993f0264 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h
@@ -6,13 +6,15 @@
#ifndef INV_ICM42600_H_
#define INV_ICM42600_H_
-#include <linux/bits.h>
#include <linux/bitfield.h>
-#include <linux/regmap.h>
+#include <linux/bits.h>
#include <linux/mutex.h>
-#include <linux/regulator/consumer.h>
#include <linux/pm.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
#include <linux/iio/iio.h>
+
#include <linux/iio/common/inv_sensors_timestamp.h>
#include "inv_icm42600_buffer.h"
@@ -354,6 +356,8 @@ struct inv_icm42600_sensor_state {
cpu_to_le16((_wm) & GENMASK(11, 0))
/* FIFO is 2048 bytes, let 12 samples for reading latency */
#define INV_ICM42600_FIFO_WATERMARK_MAX (2048 - 12 * 16)
+/* INV_ICM42600_FIFO_WATERMARK_MAX / 8 = 232 */
+#define INV_ICM42600_FIFO_WATERMARK_MAX_SAMPLES 232
#define INV_ICM42600_REG_INT_CONFIG1 0x0064
#define INV_ICM42600_INT_CONFIG1_TPULSE_DURATION BIT(6)
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
index 532d5fdffaf8..4b0e3cd8a506 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
@@ -3,25 +3,26 @@
* Copyright (C) 2020 Invensense, Inc.
*/
-#include <linux/kernel.h>
+#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/math64.h>
+#include <linux/minmax.h>
#include <linux/mutex.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
-#include <linux/delay.h>
-#include <linux/math64.h>
-#include <linux/minmax.h>
#include <linux/units.h>
#include <linux/iio/buffer.h>
-#include <linux/iio/common/inv_sensors_timestamp.h>
#include <linux/iio/events.h>
#include <linux/iio/iio.h>
#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/common/inv_sensors_timestamp.h>
+
#include "inv_icm42600.h"
-#include "inv_icm42600_temp.h"
#include "inv_icm42600_buffer.h"
+#include "inv_icm42600_temp.h"
#define INV_ICM42600_ACCEL_CHAN(_modifier, _index, _ext_info) \
{ \
@@ -1170,10 +1171,10 @@ struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st)
accel_st->filter = INV_ICM42600_FILTER_AVG_16X;
/*
- * clock period is 32kHz (31250ns)
+ * clock period is 8kHz (125000ns)
* jitter is +/- 2% (20 per mille)
*/
- ts_chip.clock_period = 31250;
+ ts_chip.clock_period = 125000;
ts_chip.jitter = 20;
ts_chip.init_period = inv_icm42600_odr_to_period(st->conf.accel.odr);
inv_sensors_timestamp_init(&accel_st->ts, &ts_chip);
@@ -1186,8 +1187,9 @@ struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st)
indio_dev->num_channels = ARRAY_SIZE(inv_icm42600_accel_channels);
indio_dev->available_scan_masks = inv_icm42600_accel_scan_masks;
- ret = devm_iio_kfifo_buffer_setup(dev, indio_dev,
- &inv_icm42600_buffer_ops);
+ ret = devm_iio_kfifo_buffer_setup_ext(dev, indio_dev,
+ &inv_icm42600_buffer_ops,
+ inv_icm42600_buffer_attrs);
if (ret)
return ERR_PTR(ret);
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c
index 5c3840acf085..998d312f7bde 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c
@@ -3,17 +3,20 @@
* Copyright (C) 2020 Invensense, Inc.
*/
-#include <linux/kernel.h>
+#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/kernel.h>
#include <linux/minmax.h>
#include <linux/mutex.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
-#include <linux/delay.h>
+#include <linux/stringify.h>
#include <linux/iio/buffer.h>
-#include <linux/iio/common/inv_sensors_timestamp.h>
#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#include <linux/iio/common/inv_sensors_timestamp.h>
#include "inv_icm42600.h"
#include "inv_icm42600_buffer.h"
@@ -186,7 +189,7 @@ static unsigned int inv_icm42600_wm_truncate(unsigned int watermark,
* smallest latency but this is not as simple as choosing the smallest watermark
* value. Latency depends on watermark and ODR. It requires several steps:
* 1) compute gyro and accel latencies and choose the smallest value.
- * 2) adapt the choosen latency so that it is a multiple of both gyro and accel
+ * 2) adapt the chosen latency so that it is a multiple of both gyro and accel
* ones. Otherwise it is possible that you don't meet a requirement. (for
* example with gyro @100Hz wm 4 and accel @100Hz with wm 6, choosing the
* value of 4 will not meet accel latency requirement because 6 is not a
@@ -438,6 +441,40 @@ const struct iio_buffer_setup_ops inv_icm42600_buffer_ops = {
.postdisable = inv_icm42600_buffer_postdisable,
};
+static ssize_t hwfifo_watermark_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
+ unsigned int wm;
+
+ guard(mutex)(&st->lock);
+
+ if (indio_dev == st->indio_accel)
+ wm = st->fifo.watermark.eff_accel;
+ else if (indio_dev == st->indio_gyro)
+ wm = st->fifo.watermark.eff_gyro;
+ else
+ return -EINVAL;
+
+ return sysfs_emit(buf, "%u\n", wm);
+}
+
+IIO_STATIC_CONST_DEVICE_ATTR(hwfifo_watermark_min, "1");
+IIO_STATIC_CONST_DEVICE_ATTR(hwfifo_watermark_max,
+ __stringify(INV_ICM42600_FIFO_WATERMARK_MAX_SAMPLES));
+static IIO_DEVICE_ATTR_RO(hwfifo_watermark, 0);
+IIO_STATIC_CONST_DEVICE_ATTR(hwfifo_enabled, "1");
+
+const struct iio_dev_attr *inv_icm42600_buffer_attrs[] = {
+ &iio_dev_attr_hwfifo_watermark_min,
+ &iio_dev_attr_hwfifo_watermark_max,
+ &iio_dev_attr_hwfifo_watermark,
+ &iio_dev_attr_hwfifo_enabled,
+ NULL
+};
+
int inv_icm42600_buffer_fifo_read(struct inv_icm42600_state *st,
unsigned int max)
{
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h
index 88b8b9f780af..e37ee3416337 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h
@@ -6,8 +6,8 @@
#ifndef INV_ICM42600_BUFFER_H_
#define INV_ICM42600_BUFFER_H_
-#include <linux/kernel.h>
#include <linux/bits.h>
+#include <linux/kernel.h>
struct inv_icm42600_state;
@@ -80,6 +80,7 @@ ssize_t inv_icm42600_fifo_decode_packet(const void *packet, const void **accel,
const void **timestamp, unsigned int *odr);
extern const struct iio_buffer_setup_ops inv_icm42600_buffer_ops;
+extern const struct iio_dev_attr *inv_icm42600_buffer_attrs[];
int inv_icm42600_buffer_init(struct inv_icm42600_state *st);
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
index 76eb22488e5f..dc97d8a274e3 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
@@ -3,18 +3,18 @@
* Copyright (C) 2020 Invensense, Inc.
*/
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/slab.h>
#include <linux/delay.h>
-#include <linux/mutex.h>
+#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
-#include <linux/regulator/consumer.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
#include <linux/iio/iio.h>
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
index 11339ddf1da3..253bf571439d 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
@@ -3,22 +3,23 @@
* Copyright (C) 2020 Invensense, Inc.
*/
-#include <linux/kernel.h>
+#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/math64.h>
#include <linux/mutex.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
-#include <linux/delay.h>
-#include <linux/math64.h>
#include <linux/iio/buffer.h>
-#include <linux/iio/common/inv_sensors_timestamp.h>
#include <linux/iio/iio.h>
#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/common/inv_sensors_timestamp.h>
+
#include "inv_icm42600.h"
-#include "inv_icm42600_temp.h"
#include "inv_icm42600_buffer.h"
+#include "inv_icm42600_temp.h"
#define INV_ICM42600_GYRO_CHAN(_modifier, _index, _ext_info) \
{ \
@@ -755,10 +756,10 @@ struct iio_dev *inv_icm42600_gyro_init(struct inv_icm42600_state *st)
}
/*
- * clock period is 32kHz (31250ns)
+ * clock period is 8kHz (125000ns)
* jitter is +/- 2% (20 per mille)
*/
- ts_chip.clock_period = 31250;
+ ts_chip.clock_period = 125000;
ts_chip.jitter = 20;
ts_chip.init_period = inv_icm42600_odr_to_period(st->conf.accel.odr);
inv_sensors_timestamp_init(&gyro_st->ts, &ts_chip);
@@ -772,8 +773,9 @@ struct iio_dev *inv_icm42600_gyro_init(struct inv_icm42600_state *st)
indio_dev->available_scan_masks = inv_icm42600_gyro_scan_masks;
indio_dev->setup_ops = &inv_icm42600_buffer_ops;
- ret = devm_iio_kfifo_buffer_setup(dev, indio_dev,
- &inv_icm42600_buffer_ops);
+ ret = devm_iio_kfifo_buffer_setup_ext(dev, indio_dev,
+ &inv_icm42600_buffer_ops,
+ inv_icm42600_buffer_attrs);
if (ret)
return ERR_PTR(ret);
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c
index 1013aff4f0ab..28552d2db91d 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c
@@ -3,12 +3,12 @@
* Copyright (C) 2020 InvenSense, Inc.
*/
-#include <linux/kernel.h>
#include <linux/device.h>
-#include <linux/module.h>
#include <linux/i2c.h>
-#include <linux/regmap.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/property.h>
+#include <linux/regmap.h>
#include "inv_icm42600.h"
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c
index 11077f4df11b..faf743bc6444 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c
@@ -3,12 +3,12 @@
* Copyright (C) 2020 InvenSense, Inc.
*/
-#include <linux/kernel.h>
#include <linux/device.h>
+#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/spi/spi.h>
-#include <linux/regmap.h>
#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
#include "inv_icm42600.h"
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c
index 727b03d541a5..7f80bda471c3 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c
@@ -3,11 +3,12 @@
* Copyright (C) 2020 Invensense, Inc.
*/
-#include <linux/kernel.h>
#include <linux/device.h>
+#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
+
#include <linux/iio/iio.h>
#include "inv_icm42600.h"
diff --git a/drivers/iio/imu/inv_icm45600/inv_icm45600.h b/drivers/iio/imu/inv_icm45600/inv_icm45600.h
index 1c796d4b2a40..95fa934a42b4 100644
--- a/drivers/iio/imu/inv_icm45600/inv_icm45600.h
+++ b/drivers/iio/imu/inv_icm45600/inv_icm45600.h
@@ -190,7 +190,7 @@ struct inv_icm45600_sensor_state {
#define INV_ICM45600_REG_IREG_ADDR 0x7C
#define INV_ICM45600_REG_IREG_DATA 0x7E
-/* Direct acces registers */
+/* Direct access registers */
#define INV_ICM45600_REG_MISC2 0x007F
#define INV_ICM45600_MISC2_SOFT_RESET BIT(1)
diff --git a/drivers/iio/imu/inv_icm45600/inv_icm45600_buffer.c b/drivers/iio/imu/inv_icm45600/inv_icm45600_buffer.c
index 2b9ea317385c..42111c543d3c 100644
--- a/drivers/iio/imu/inv_icm45600/inv_icm45600_buffer.c
+++ b/drivers/iio/imu/inv_icm45600/inv_icm45600_buffer.c
@@ -422,8 +422,11 @@ int inv_icm45600_buffer_fifo_read(struct inv_icm45600_state *st,
if (max > 0 && fifo_nb > max)
fifo_nb = max;
- /* Try to read all FIFO data in internal buffer. */
- st->fifo.count = fifo_nb * packet_size;
+ /*
+ * Read all FIFO data into the internal buffer, clamping the
+ * device-reported count to the buffer capacity.
+ */
+ st->fifo.count = min(fifo_nb * packet_size, INV_ICM45600_FIFO_SIZE_MAX);
ret = regmap_noinc_read(st->map, INV_ICM45600_REG_FIFO_DATA,
st->fifo.data, st->fifo.count);
if (ret == -ENOTSUPP || ret == -EFBIG) {
diff --git a/drivers/iio/imu/inv_icm45600/inv_icm45600_core.c b/drivers/iio/imu/inv_icm45600/inv_icm45600_core.c
index d49053161a65..c1d7aa7e950d 100644
--- a/drivers/iio/imu/inv_icm45600/inv_icm45600_core.c
+++ b/drivers/iio/imu/inv_icm45600/inv_icm45600_core.c
@@ -716,7 +716,7 @@ int inv_icm45600_core_probe(struct regmap *regmap, const struct inv_icm45600_chi
dev_set_drvdata(dev, st);
- st->fifo.data = devm_kzalloc(dev, 8192, GFP_KERNEL);
+ st->fifo.data = devm_kzalloc(dev, INV_ICM45600_FIFO_SIZE_MAX, GFP_KERNEL);
if (!st->fifo.data)
return -ENOMEM;
diff --git a/drivers/iio/imu/inv_icm45600/inv_icm45600_i2c.c b/drivers/iio/imu/inv_icm45600/inv_icm45600_i2c.c
index 81ba1b60f04b..69acf9bac2db 100644
--- a/drivers/iio/imu/inv_icm45600/inv_icm45600_i2c.c
+++ b/drivers/iio/imu/inv_icm45600/inv_icm45600_i2c.c
@@ -22,7 +22,7 @@ static int inv_icm45600_probe(struct i2c_client *client)
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
return -ENODEV;
- chip_info = device_get_match_data(&client->dev);
+ chip_info = i2c_get_match_data(client);
if (!chip_info)
return -ENODEV;
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c
index 47394594d17a..6b858fdfd1c6 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c
@@ -106,9 +106,9 @@ static int inv_magn_init(struct inv_mpu6050_state *st)
return ret;
/*
- * Sensor sentivity
+ * Sensor sensitivity
* 1 uT = 0.01 G and value is in micron (1e6)
- * sensitvity = x uT * 0.01 * 1e6
+ * sensitivity = x uT * 0.01 * 1e6
*/
switch (st->chip_type) {
case INV_MPU9150:
diff --git a/drivers/iio/industrialio-backend.c b/drivers/iio/industrialio-backend.c
index 4763e224ebc6..f7a4be8ec320 100644
--- a/drivers/iio/industrialio-backend.c
+++ b/drivers/iio/industrialio-backend.c
@@ -649,7 +649,7 @@ EXPORT_SYMBOL_NS_GPL(iio_backend_ext_info_get, "IIO_BACKEND");
* @len: Buffer length
*
* This helper is intended to be used by backends that extend an IIO channel
- * (trough iio_backend_extend_chan_spec()) with extended info. In that case,
+ * (through iio_backend_extend_chan_spec()) with extended info. In that case,
* backends are not supposed to give their own callbacks (as they would not have
* a way to get the backend from indio_dev). This is the setter.
*
@@ -851,7 +851,7 @@ EXPORT_SYMBOL_NS_GPL(iio_backend_filter_type_set, "IIO_BACKEND");
* @back: Backend device
* @timeout_us: Timeout value in us.
*
- * When activated, it initates a proccess that aligns the sample's most
+ * When activated, it initiates a process that aligns the sample's most
* significant bit (MSB) based solely on the captured data, without
* considering any other external signals.
*
@@ -1017,7 +1017,7 @@ static struct iio_backend *__devm_iio_backend_fwnode_get(struct device *dev, con
* @dev: Consumer device for the backend
* @name: Backend name
*
- * Get's the backend associated with @dev.
+ * Gets the backend associated with @dev.
*
* RETURNS:
* A backend pointer, negative error pointer otherwise.
@@ -1050,7 +1050,7 @@ EXPORT_SYMBOL_NS_GPL(devm_iio_backend_get_by_index, "IIO_BACKEND");
* @name: Backend name
* @fwnode: Firmware node of the backend consumer
*
- * Get's the backend associated with a firmware node.
+ * Gets the backend associated with a firmware node.
*
* RETURNS:
* A backend pointer, negative error pointer otherwise.
diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c
index a0d6fcf2a9c9..e6730f52262a 100644
--- a/drivers/iio/industrialio-event.c
+++ b/drivers/iio/industrialio-event.c
@@ -207,6 +207,8 @@ static int iio_event_getfd(struct iio_dev *indio_dev)
goto unlock;
}
+ kfifo_reset_out(&ev_int->det_events);
+
iio_device_get(indio_dev);
fd = anon_inode_getfd("iio:event", &iio_event_chrdev_fileops,
@@ -214,10 +216,7 @@ static int iio_event_getfd(struct iio_dev *indio_dev)
if (fd < 0) {
clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
iio_device_put(indio_dev);
- } else {
- kfifo_reset_out(&ev_int->det_events);
}
-
unlock:
mutex_unlock(&iio_dev_opaque->mlock);
return fd;
diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index 9ce20cb05a9b..fb08e4f02520 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -281,7 +281,7 @@ struct iio_channel *fwnode_iio_channel_get_by_name(struct fwnode_handle *fwnode,
return ERR_PTR(-ENODEV);
}
-EXPORT_SYMBOL_GPL(fwnode_iio_channel_get_by_name);
+EXPORT_SYMBOL_NS_GPL(fwnode_iio_channel_get_by_name, "IIO_CONSUMER");
static struct iio_channel *fwnode_iio_channel_get_all(struct device *dev)
{
@@ -386,7 +386,7 @@ struct iio_channel *iio_channel_get(struct device *dev,
return iio_channel_get_sys(name, channel_name);
}
-EXPORT_SYMBOL_GPL(iio_channel_get);
+EXPORT_SYMBOL_NS_GPL(iio_channel_get, "IIO_CONSUMER");
void iio_channel_release(struct iio_channel *channel)
{
@@ -395,7 +395,7 @@ void iio_channel_release(struct iio_channel *channel)
iio_device_put(channel->indio_dev);
kfree(channel);
}
-EXPORT_SYMBOL_GPL(iio_channel_release);
+EXPORT_SYMBOL_NS_GPL(iio_channel_release, "IIO_CONSUMER");
static void devm_iio_channel_free(void *iio_channel)
{
@@ -418,7 +418,7 @@ struct iio_channel *devm_iio_channel_get(struct device *dev,
return channel;
}
-EXPORT_SYMBOL_GPL(devm_iio_channel_get);
+EXPORT_SYMBOL_NS_GPL(devm_iio_channel_get, "IIO_CONSUMER");
struct iio_channel *devm_fwnode_iio_channel_get_by_name(struct device *dev,
struct fwnode_handle *fwnode,
@@ -437,7 +437,7 @@ struct iio_channel *devm_fwnode_iio_channel_get_by_name(struct device *dev,
return channel;
}
-EXPORT_SYMBOL_GPL(devm_fwnode_iio_channel_get_by_name);
+EXPORT_SYMBOL_NS_GPL(devm_fwnode_iio_channel_get_by_name, "IIO_CONSUMER");
struct iio_channel *iio_channel_get_all(struct device *dev)
{
@@ -506,7 +506,7 @@ error_free_chans:
iio_device_put(chans[i].indio_dev);
return ERR_PTR(ret);
}
-EXPORT_SYMBOL_GPL(iio_channel_get_all);
+EXPORT_SYMBOL_NS_GPL(iio_channel_get_all, "IIO_CONSUMER");
void iio_channel_release_all(struct iio_channel *channels)
{
@@ -518,7 +518,7 @@ void iio_channel_release_all(struct iio_channel *channels)
}
kfree(channels);
}
-EXPORT_SYMBOL_GPL(iio_channel_release_all);
+EXPORT_SYMBOL_NS_GPL(iio_channel_release_all, "IIO_CONSUMER");
static void devm_iio_channel_free_all(void *iio_channels)
{
@@ -541,7 +541,7 @@ struct iio_channel *devm_iio_channel_get_all(struct device *dev)
return channels;
}
-EXPORT_SYMBOL_GPL(devm_iio_channel_get_all);
+EXPORT_SYMBOL_NS_GPL(devm_iio_channel_get_all, "IIO_CONSUMER");
static int iio_channel_read(struct iio_channel *chan, int *val, int *val2,
enum iio_chan_info_enum info)
@@ -585,7 +585,7 @@ int iio_read_channel_raw(struct iio_channel *chan, int *val)
return iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW);
}
-EXPORT_SYMBOL_GPL(iio_read_channel_raw);
+EXPORT_SYMBOL_NS_GPL(iio_read_channel_raw, "IIO_CONSUMER");
int iio_read_channel_average_raw(struct iio_channel *chan, int *val)
{
@@ -597,7 +597,7 @@ int iio_read_channel_average_raw(struct iio_channel *chan, int *val)
return iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_AVERAGE_RAW);
}
-EXPORT_SYMBOL_GPL(iio_read_channel_average_raw);
+EXPORT_SYMBOL_NS_GPL(iio_read_channel_average_raw, "IIO_CONSUMER");
int iio_multiply_value(int *result, s64 multiplier,
unsigned int type, int val, int val2)
@@ -701,7 +701,7 @@ int iio_convert_raw_to_processed(struct iio_channel *chan, int raw,
return iio_convert_raw_to_processed_unlocked(chan, raw, processed,
scale);
}
-EXPORT_SYMBOL_GPL(iio_convert_raw_to_processed);
+EXPORT_SYMBOL_NS_GPL(iio_convert_raw_to_processed, "IIO_CONSUMER");
int iio_read_channel_attribute(struct iio_channel *chan, int *val, int *val2,
enum iio_chan_info_enum attribute)
@@ -714,13 +714,13 @@ int iio_read_channel_attribute(struct iio_channel *chan, int *val, int *val2,
return iio_channel_read(chan, val, val2, attribute);
}
-EXPORT_SYMBOL_GPL(iio_read_channel_attribute);
+EXPORT_SYMBOL_NS_GPL(iio_read_channel_attribute, "IIO_CONSUMER");
int iio_read_channel_offset(struct iio_channel *chan, int *val, int *val2)
{
return iio_read_channel_attribute(chan, val, val2, IIO_CHAN_INFO_OFFSET);
}
-EXPORT_SYMBOL_GPL(iio_read_channel_offset);
+EXPORT_SYMBOL_NS_GPL(iio_read_channel_offset, "IIO_CONSUMER");
int iio_read_channel_processed_scale(struct iio_channel *chan, int *val,
unsigned int scale)
@@ -752,20 +752,20 @@ int iio_read_channel_processed_scale(struct iio_channel *chan, int *val,
scale);
}
}
-EXPORT_SYMBOL_GPL(iio_read_channel_processed_scale);
+EXPORT_SYMBOL_NS_GPL(iio_read_channel_processed_scale, "IIO_CONSUMER");
int iio_read_channel_processed(struct iio_channel *chan, int *val)
{
/* This is just a special case with scale factor 1 */
return iio_read_channel_processed_scale(chan, val, 1);
}
-EXPORT_SYMBOL_GPL(iio_read_channel_processed);
+EXPORT_SYMBOL_NS_GPL(iio_read_channel_processed, "IIO_CONSUMER");
int iio_read_channel_scale(struct iio_channel *chan, int *val, int *val2)
{
return iio_read_channel_attribute(chan, val, val2, IIO_CHAN_INFO_SCALE);
}
-EXPORT_SYMBOL_GPL(iio_read_channel_scale);
+EXPORT_SYMBOL_NS_GPL(iio_read_channel_scale, "IIO_CONSUMER");
static int iio_channel_read_avail(struct iio_channel *chan,
const int **vals, int *type, int *length,
@@ -794,7 +794,7 @@ int iio_read_avail_channel_attribute(struct iio_channel *chan,
return iio_channel_read_avail(chan, vals, type, length, attribute);
}
-EXPORT_SYMBOL_GPL(iio_read_avail_channel_attribute);
+EXPORT_SYMBOL_NS_GPL(iio_read_avail_channel_attribute, "IIO_CONSUMER");
int iio_read_avail_channel_raw(struct iio_channel *chan,
const int **vals, int *length)
@@ -811,7 +811,7 @@ int iio_read_avail_channel_raw(struct iio_channel *chan,
return ret;
}
-EXPORT_SYMBOL_GPL(iio_read_avail_channel_raw);
+EXPORT_SYMBOL_NS_GPL(iio_read_avail_channel_raw, "IIO_CONSUMER");
static int iio_channel_read_max(struct iio_channel *chan,
int *val, int *val2, int *type,
@@ -867,7 +867,7 @@ int iio_read_max_channel_raw(struct iio_channel *chan, int *val)
return iio_channel_read_max(chan, val, NULL, &type, IIO_CHAN_INFO_RAW);
}
-EXPORT_SYMBOL_GPL(iio_read_max_channel_raw);
+EXPORT_SYMBOL_NS_GPL(iio_read_max_channel_raw, "IIO_CONSUMER");
static int iio_channel_read_min(struct iio_channel *chan,
int *val, int *val2, int *type,
@@ -923,7 +923,7 @@ int iio_read_min_channel_raw(struct iio_channel *chan, int *val)
return iio_channel_read_min(chan, val, NULL, &type, IIO_CHAN_INFO_RAW);
}
-EXPORT_SYMBOL_GPL(iio_read_min_channel_raw);
+EXPORT_SYMBOL_NS_GPL(iio_read_min_channel_raw, "IIO_CONSUMER");
int iio_get_channel_type(struct iio_channel *chan, enum iio_chan_type *type)
{
@@ -937,7 +937,7 @@ int iio_get_channel_type(struct iio_channel *chan, enum iio_chan_type *type)
return 0;
}
-EXPORT_SYMBOL_GPL(iio_get_channel_type);
+EXPORT_SYMBOL_NS_GPL(iio_get_channel_type, "IIO_CONSUMER");
static int iio_channel_write(struct iio_channel *chan, int val, int val2,
enum iio_chan_info_enum info)
@@ -961,13 +961,13 @@ int iio_write_channel_attribute(struct iio_channel *chan, int val, int val2,
return iio_channel_write(chan, val, val2, attribute);
}
-EXPORT_SYMBOL_GPL(iio_write_channel_attribute);
+EXPORT_SYMBOL_NS_GPL(iio_write_channel_attribute, "IIO_CONSUMER");
int iio_write_channel_raw(struct iio_channel *chan, int val)
{
return iio_write_channel_attribute(chan, val, 0, IIO_CHAN_INFO_RAW);
}
-EXPORT_SYMBOL_GPL(iio_write_channel_raw);
+EXPORT_SYMBOL_NS_GPL(iio_write_channel_raw, "IIO_CONSUMER");
unsigned int iio_get_channel_ext_info_count(struct iio_channel *chan)
{
@@ -982,7 +982,7 @@ unsigned int iio_get_channel_ext_info_count(struct iio_channel *chan)
return i;
}
-EXPORT_SYMBOL_GPL(iio_get_channel_ext_info_count);
+EXPORT_SYMBOL_NS_GPL(iio_get_channel_ext_info_count, "IIO_CONSUMER");
static const struct iio_chan_spec_ext_info *
iio_lookup_ext_info(const struct iio_channel *chan, const char *attr)
@@ -1017,7 +1017,7 @@ ssize_t iio_read_channel_ext_info(struct iio_channel *chan,
return ext_info->read(chan->indio_dev, ext_info->private,
chan->channel, buf);
}
-EXPORT_SYMBOL_GPL(iio_read_channel_ext_info);
+EXPORT_SYMBOL_NS_GPL(iio_read_channel_ext_info, "IIO_CONSUMER");
ssize_t iio_write_channel_ext_info(struct iio_channel *chan, const char *attr,
const char *buf, size_t len)
@@ -1031,7 +1031,7 @@ ssize_t iio_write_channel_ext_info(struct iio_channel *chan, const char *attr,
return ext_info->write(chan->indio_dev, ext_info->private,
chan->channel, buf, len);
}
-EXPORT_SYMBOL_GPL(iio_write_channel_ext_info);
+EXPORT_SYMBOL_NS_GPL(iio_write_channel_ext_info, "IIO_CONSUMER");
ssize_t iio_read_channel_label(struct iio_channel *chan, char *buf)
{
@@ -1042,4 +1042,4 @@ ssize_t iio_read_channel_label(struct iio_channel *chan, char *buf)
return do_iio_read_channel_label(chan->indio_dev, chan->channel, buf);
}
-EXPORT_SYMBOL_GPL(iio_read_channel_label);
+EXPORT_SYMBOL_NS_GPL(iio_read_channel_label, "IIO_CONSUMER");
diff --git a/drivers/iio/light/al3010.c b/drivers/iio/light/al3010.c
index 62a77acfd075..49f6d8336dbe 100644
--- a/drivers/iio/light/al3010.c
+++ b/drivers/iio/light/al3010.c
@@ -41,7 +41,7 @@ enum al3xxxx_range {
};
static const int al3010_scales[][2] = {
- {0, 1187200}, {0, 296800}, {0, 74200}, {0, 18600}
+ { 1, 187200 }, { 0, 296800 }, { 0, 74200 }, { 0, 18600 },
};
static const struct regmap_config al3010_regmap_config = {
diff --git a/drivers/iio/light/cm3605.c b/drivers/iio/light/cm3605.c
index 98c84f33db60..9f799041edf9 100644
--- a/drivers/iio/light/cm3605.c
+++ b/drivers/iio/light/cm3605.c
@@ -324,3 +324,4 @@ module_platform_driver(cm3605_driver);
MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
MODULE_DESCRIPTION("CM3605 ambient light and proximity sensor driver");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/iio/light/gp2ap002.c b/drivers/iio/light/gp2ap002.c
index a8db514cca5e..8dd3704e6299 100644
--- a/drivers/iio/light/gp2ap002.c
+++ b/drivers/iio/light/gp2ap002.c
@@ -717,3 +717,4 @@ module_i2c_driver(gp2ap002_driver);
MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
MODULE_DESCRIPTION("GP2AP002 ambient light and proximity sensor driver");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c
index bc1df59241fb..6fb6ace26834 100644
--- a/drivers/iio/light/hid-sensor-als.c
+++ b/drivers/iio/light/hid-sensor-als.c
@@ -119,9 +119,8 @@ static const struct iio_chan_spec als_channels[] = {
/* Channel read_raw handler */
static int als_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int *val, int *val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
{
struct als_state *als_state = iio_priv(indio_dev);
struct hid_sensor_hub_device *hsdev = als_state->common_attributes.hsdev;
@@ -162,12 +161,12 @@ static int als_read_raw(struct iio_dev *indio_dev,
}
if (report_id >= 0) {
hid_sensor_power_state(&als_state->common_attributes,
- true);
+ true);
*val = sensor_hub_input_attr_get_raw_value(
hsdev, hsdev->usage, address, report_id,
SENSOR_HUB_SYNC, min < 0);
hid_sensor_power_state(&als_state->common_attributes,
- false);
+ false);
} else {
*val = 0;
return -EINVAL;
@@ -205,10 +204,8 @@ static int als_read_raw(struct iio_dev *indio_dev,
/* Channel write_raw handler */
static int als_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val,
- int val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
{
struct als_state *als_state = iio_priv(indio_dev);
int ret = 0;
@@ -240,8 +237,7 @@ static const struct iio_info als_info = {
/* Callback handler to send event after all samples are received and captured */
static int als_proc_event(struct hid_sensor_hub_device *hsdev,
- u32 usage_id,
- void *priv)
+ u32 usage_id, void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct als_state *als_state = iio_priv(indio_dev);
@@ -262,9 +258,9 @@ static int als_proc_event(struct hid_sensor_hub_device *hsdev,
/* Capture samples in local storage */
static int als_capture_sample(struct hid_sensor_hub_device *hsdev,
- u32 usage_id,
- size_t raw_len, char *raw_data,
- void *priv)
+ u32 usage_id,
+ size_t raw_len, char *raw_data,
+ void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct als_state *als_state = iio_priv(indio_dev);
@@ -303,9 +299,9 @@ static int als_capture_sample(struct hid_sensor_hub_device *hsdev,
/* Parse report which is specific to an usage id*/
static int als_parse_report(struct platform_device *pdev,
- struct hid_sensor_hub_device *hsdev,
- u32 usage_id,
- struct als_state *st)
+ struct hid_sensor_hub_device *hsdev,
+ u32 usage_id,
+ struct als_state *st)
{
struct iio_chan_spec *channels;
int ret, index = 0;
@@ -399,31 +395,31 @@ static int hid_als_probe(struct platform_device *pdev)
atomic_set(&als_state->common_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name,
- &als_state->common_attributes);
+ &als_state->common_attributes);
if (ret < 0) {
dev_err(&pdev->dev, "trigger setup failed\n");
return ret;
}
- ret = iio_device_register(indio_dev);
- if (ret) {
- dev_err(&pdev->dev, "device register failed\n");
- goto error_remove_trigger;
- }
-
als_state->callbacks.send_event = als_proc_event;
als_state->callbacks.capture_sample = als_capture_sample;
als_state->callbacks.pdev = pdev;
ret = sensor_hub_register_callback(hsdev, hsdev->usage, &als_state->callbacks);
if (ret < 0) {
dev_err(&pdev->dev, "callback reg failed\n");
- goto error_iio_unreg;
+ goto error_remove_trigger;
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "device register failed\n");
+ goto error_remove_callback;
}
return ret;
-error_iio_unreg:
- iio_device_unregister(indio_dev);
+error_remove_callback:
+ sensor_hub_remove_callback(hsdev, hsdev->usage);
error_remove_trigger:
hid_sensor_remove_trigger(indio_dev, &als_state->common_attributes);
return ret;
@@ -436,8 +432,8 @@ static void hid_als_remove(struct platform_device *pdev)
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct als_state *als_state = iio_priv(indio_dev);
- sensor_hub_remove_callback(hsdev, hsdev->usage);
iio_device_unregister(indio_dev);
+ sensor_hub_remove_callback(hsdev, hsdev->usage);
hid_sensor_remove_trigger(indio_dev, &als_state->common_attributes);
}
diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c
index fb8aef3744ae..63fd3eff171c 100644
--- a/drivers/iio/light/hid-sensor-prox.c
+++ b/drivers/iio/light/hid-sensor-prox.c
@@ -69,9 +69,8 @@ static const struct iio_chan_spec prox_channels[] = {
/* Channel read_raw handler */
static int prox_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int *val, int *val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
{
struct prox_state *prox_state = iio_priv(indio_dev);
struct hid_sensor_hub_device *hsdev;
@@ -134,10 +133,8 @@ static int prox_read_raw(struct iio_dev *indio_dev,
/* Channel write_raw handler */
static int prox_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val,
- int val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
{
struct prox_state *prox_state = iio_priv(indio_dev);
int ret = 0;
@@ -165,8 +162,7 @@ static const struct iio_info prox_info = {
/* Callback handler to send event after all samples are received and captured */
static int prox_proc_event(struct hid_sensor_hub_device *hsdev,
- u32 usage_id,
- void *priv)
+ u32 usage_id, void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct prox_state *prox_state = iio_priv(indio_dev);
@@ -182,9 +178,9 @@ static int prox_proc_event(struct hid_sensor_hub_device *hsdev,
/* Capture samples in local storage */
static int prox_capture_sample(struct hid_sensor_hub_device *hsdev,
- u32 usage_id,
- size_t raw_len, char *raw_data,
- void *priv)
+ u32 usage_id,
+ size_t raw_len, char *raw_data,
+ void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct prox_state *prox_state = iio_priv(indio_dev);
@@ -217,8 +213,8 @@ static int prox_capture_sample(struct hid_sensor_hub_device *hsdev,
/* Parse report which is specific to an usage id*/
static int prox_parse_report(struct platform_device *pdev,
- struct hid_sensor_hub_device *hsdev,
- struct prox_state *st)
+ struct hid_sensor_hub_device *hsdev,
+ struct prox_state *st)
{
struct iio_chan_spec *channels = st->channels;
int index = 0;
@@ -270,8 +266,7 @@ static int hid_prox_probe(struct platform_device *pdev)
struct iio_dev *indio_dev;
struct prox_state *prox_state;
- indio_dev = devm_iio_device_alloc(&pdev->dev,
- sizeof(struct prox_state));
+ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct prox_state));
if (!indio_dev)
return -ENOMEM;
platform_set_drvdata(pdev, indio_dev);
@@ -305,18 +300,12 @@ static int hid_prox_probe(struct platform_device *pdev)
atomic_set(&prox_state->common_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name,
- &prox_state->common_attributes);
+ &prox_state->common_attributes);
if (ret) {
dev_err(&pdev->dev, "trigger setup failed\n");
return ret;
}
- ret = iio_device_register(indio_dev);
- if (ret) {
- dev_err(&pdev->dev, "device register failed\n");
- goto error_remove_trigger;
- }
-
prox_state->callbacks.send_event = prox_proc_event;
prox_state->callbacks.capture_sample = prox_capture_sample;
prox_state->callbacks.pdev = pdev;
@@ -324,13 +313,19 @@ static int hid_prox_probe(struct platform_device *pdev)
&prox_state->callbacks);
if (ret < 0) {
dev_err(&pdev->dev, "callback reg failed\n");
- goto error_iio_unreg;
+ goto error_remove_trigger;
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "device register failed\n");
+ goto error_remove_callback;
}
return ret;
-error_iio_unreg:
- iio_device_unregister(indio_dev);
+error_remove_callback:
+ sensor_hub_remove_callback(hsdev, hsdev->usage);
error_remove_trigger:
hid_sensor_remove_trigger(indio_dev, &prox_state->common_attributes);
return ret;
@@ -343,8 +338,8 @@ static void hid_prox_remove(struct platform_device *pdev)
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct prox_state *prox_state = iio_priv(indio_dev);
- sensor_hub_remove_callback(hsdev, hsdev->usage);
iio_device_unregister(indio_dev);
+ sensor_hub_remove_callback(hsdev, hsdev->usage);
hid_sensor_remove_trigger(indio_dev, &prox_state->common_attributes);
}
diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
index d8b8bcc865c3..ad18f233ee16 100644
--- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c
+++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
@@ -134,9 +134,8 @@ static const struct iio_chan_spec magn_3d_channels[] = {
/* Channel read_raw handler */
static int magn_3d_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int *val, int *val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
{
struct magn_3d_state *magn_state = iio_priv(indio_dev);
int report_id = -1;
@@ -166,8 +165,7 @@ static int magn_3d_read_raw(struct iio_dev *indio_dev,
false);
return -EINVAL;
}
- hid_sensor_power_state(&magn_state->magn_flux_attributes,
- false);
+ hid_sensor_power_state(&magn_state->magn_flux_attributes, false);
ret_type = IIO_VAL_INT;
break;
case IIO_CHAN_INFO_SCALE:
@@ -228,10 +226,8 @@ static int magn_3d_read_raw(struct iio_dev *indio_dev,
/* Channel write_raw handler */
static int magn_3d_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val,
- int val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
{
struct magn_3d_state *magn_state = iio_priv(indio_dev);
int ret = 0;
@@ -269,8 +265,7 @@ static const struct iio_info magn_3d_info = {
/* Callback handler to send event after all samples are received and captured */
static int magn_3d_proc_event(struct hid_sensor_hub_device *hsdev,
- u32 usage_id,
- void *priv)
+ u32 usage_id, void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct magn_3d_state *magn_state = iio_priv(indio_dev);
@@ -291,9 +286,9 @@ static int magn_3d_proc_event(struct hid_sensor_hub_device *hsdev,
/* Capture samples in local storage */
static int magn_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
- u32 usage_id,
- size_t raw_len, char *raw_data,
- void *priv)
+ u32 usage_id,
+ size_t raw_len, char *raw_data,
+ void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct magn_3d_state *magn_state = iio_priv(indio_dev);
@@ -326,7 +321,7 @@ static int magn_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
iio_val = magn_state->magn_val_addr[offset];
- if (iio_val != NULL)
+ if (iio_val)
*iio_val = *((u32 *)raw_data);
else
ret = -EINVAL;
@@ -367,18 +362,17 @@ static int magn_3d_parse_report(struct platform_device *pdev,
return -EINVAL;
}
- dev_dbg(&pdev->dev, "magn_3d Found %d usage attributes\n",
- attr_count);
+ dev_dbg(&pdev->dev, "magn_3d Found %d usage attributes\n", attr_count);
dev_dbg(&pdev->dev, "magn_3d X: %x:%x Y: %x:%x Z: %x:%x\n",
- st->magn[0].index,
- st->magn[0].report_id,
- st->magn[1].index, st->magn[1].report_id,
- st->magn[2].index, st->magn[2].report_id);
+ st->magn[0].index,
+ st->magn[0].report_id,
+ st->magn[1].index, st->magn[1].report_id,
+ st->magn[2].index, st->magn[2].report_id);
/* Setup IIO channel array */
_channels = devm_kcalloc(&pdev->dev, attr_count,
- sizeof(struct iio_chan_spec),
- GFP_KERNEL);
+ sizeof(struct iio_chan_spec),
+ GFP_KERNEL);
if (!_channels) {
dev_err(&pdev->dev,
"failed to allocate space for iio channels\n");
@@ -425,8 +419,7 @@ static int magn_3d_parse_report(struct platform_device *pdev,
*channels = _channels;
- dev_dbg(&pdev->dev, "magn_3d Setup %d IIO channels\n",
- *chan_count);
+ dev_dbg(&pdev->dev, "magn_3d Setup %d IIO channels\n", *chan_count);
st->magn_flux_attr.scale_precision = hid_sensor_format_scale(
HID_USAGE_SENSOR_COMPASS_3D,
@@ -467,7 +460,7 @@ static int hid_magn_3d_probe(struct platform_device *pdev)
indio_dev = devm_iio_device_alloc(&pdev->dev,
sizeof(struct magn_3d_state));
- if (indio_dev == NULL)
+ if (!indio_dev)
return -ENOMEM;
platform_set_drvdata(pdev, indio_dev);
@@ -490,8 +483,8 @@ static int hid_magn_3d_probe(struct platform_device *pdev)
magn_state->rot_attributes.sensitivity.index = -1;
ret = magn_3d_parse_report(pdev, hsdev,
- &channels, &chan_count,
- HID_USAGE_SENSOR_COMPASS_3D, magn_state);
+ &channels, &chan_count,
+ HID_USAGE_SENSOR_COMPASS_3D, magn_state);
if (ret) {
dev_err(&pdev->dev, "failed to parse report\n");
return ret;
@@ -506,32 +499,32 @@ static int hid_magn_3d_probe(struct platform_device *pdev)
atomic_set(&magn_state->magn_flux_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name,
- &magn_state->magn_flux_attributes);
+ &magn_state->magn_flux_attributes);
if (ret < 0) {
dev_err(&pdev->dev, "trigger setup failed\n");
return ret;
}
- ret = iio_device_register(indio_dev);
- if (ret) {
- dev_err(&pdev->dev, "device register failed\n");
- goto error_remove_trigger;
- }
-
magn_state->callbacks.send_event = magn_3d_proc_event;
magn_state->callbacks.capture_sample = magn_3d_capture_sample;
magn_state->callbacks.pdev = pdev;
ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_COMPASS_3D,
- &magn_state->callbacks);
+ &magn_state->callbacks);
if (ret < 0) {
dev_err(&pdev->dev, "callback reg failed\n");
- goto error_iio_unreg;
+ goto error_remove_trigger;
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "device register failed\n");
+ goto error_remove_callback;
}
return ret;
-error_iio_unreg:
- iio_device_unregister(indio_dev);
+error_remove_callback:
+ sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_COMPASS_3D);
error_remove_trigger:
hid_sensor_remove_trigger(indio_dev, &magn_state->magn_flux_attributes);
return ret;
@@ -544,8 +537,8 @@ static void hid_magn_3d_remove(struct platform_device *pdev)
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct magn_3d_state *magn_state = iio_priv(indio_dev);
- sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_COMPASS_3D);
iio_device_unregister(indio_dev);
+ sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_COMPASS_3D);
hid_sensor_remove_trigger(indio_dev, &magn_state->magn_flux_attributes);
}
diff --git a/drivers/iio/multiplexer/iio-mux.c b/drivers/iio/multiplexer/iio-mux.c
index 4421dafcf94e..562457a67382 100644
--- a/drivers/iio/multiplexer/iio-mux.c
+++ b/drivers/iio/multiplexer/iio-mux.c
@@ -463,3 +463,4 @@ module_platform_driver(mux_driver);
MODULE_DESCRIPTION("IIO multiplexer driver");
MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/iio/orientation/hid-sensor-incl-3d.c b/drivers/iio/orientation/hid-sensor-incl-3d.c
index d96fa432048b..aea28321db95 100644
--- a/drivers/iio/orientation/hid-sensor-incl-3d.c
+++ b/drivers/iio/orientation/hid-sensor-incl-3d.c
@@ -85,8 +85,7 @@ static const struct iio_chan_spec incl_3d_channels[] = {
};
/* Adjust channel real bits based on report descriptor */
-static void incl_3d_adjust_channel_bit_mask(struct iio_chan_spec *chan,
- int size)
+static void incl_3d_adjust_channel_bit_mask(struct iio_chan_spec *chan, int size)
{
chan->scan_type.sign = 's';
/* Real storage bits will change based on the report desc. */
@@ -97,9 +96,8 @@ static void incl_3d_adjust_channel_bit_mask(struct iio_chan_spec *chan,
/* Channel read_raw handler */
static int incl_3d_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int *val, int *val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
{
struct incl_3d_state *incl_state = iio_priv(indio_dev);
int report_id = -1;
@@ -124,7 +122,7 @@ static int incl_3d_read_raw(struct iio_dev *indio_dev,
min < 0);
else {
hid_sensor_power_state(&incl_state->common_attributes,
- false);
+ false);
return -EINVAL;
}
hid_sensor_power_state(&incl_state->common_attributes, false);
@@ -157,10 +155,8 @@ static int incl_3d_read_raw(struct iio_dev *indio_dev,
/* Channel write_raw handler */
static int incl_3d_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val,
- int val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
{
struct incl_3d_state *incl_state = iio_priv(indio_dev);
int ret;
@@ -188,8 +184,7 @@ static const struct iio_info incl_3d_info = {
/* Callback handler to send event after all samples are received and captured */
static int incl_3d_proc_event(struct hid_sensor_hub_device *hsdev,
- u32 usage_id,
- void *priv)
+ u32 usage_id, void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct incl_3d_state *incl_state = iio_priv(indio_dev);
@@ -211,9 +206,9 @@ static int incl_3d_proc_event(struct hid_sensor_hub_device *hsdev,
/* Capture samples in local storage */
static int incl_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
- u32 usage_id,
- size_t raw_len, char *raw_data,
- void *priv)
+ u32 usage_id,
+ size_t raw_len, char *raw_data,
+ void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct incl_3d_state *incl_state = iio_priv(indio_dev);
@@ -306,7 +301,7 @@ static int hid_incl_3d_probe(struct platform_device *pdev)
indio_dev = devm_iio_device_alloc(&pdev->dev,
sizeof(struct incl_3d_state));
- if (indio_dev == NULL)
+ if (!indio_dev)
return -ENOMEM;
platform_set_drvdata(pdev, indio_dev);
@@ -349,33 +344,33 @@ static int hid_incl_3d_probe(struct platform_device *pdev)
atomic_set(&incl_state->common_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name,
- &incl_state->common_attributes);
+ &incl_state->common_attributes);
if (ret) {
dev_err(&pdev->dev, "trigger setup failed\n");
return ret;
}
- ret = iio_device_register(indio_dev);
- if (ret) {
- dev_err(&pdev->dev, "device register failed\n");
- goto error_remove_trigger;
- }
-
incl_state->callbacks.send_event = incl_3d_proc_event;
incl_state->callbacks.capture_sample = incl_3d_capture_sample;
incl_state->callbacks.pdev = pdev;
ret = sensor_hub_register_callback(hsdev,
- HID_USAGE_SENSOR_INCLINOMETER_3D,
- &incl_state->callbacks);
+ HID_USAGE_SENSOR_INCLINOMETER_3D,
+ &incl_state->callbacks);
if (ret) {
dev_err(&pdev->dev, "callback reg failed\n");
- goto error_iio_unreg;
+ goto error_remove_trigger;
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "device register failed\n");
+ goto error_remove_callback;
}
return 0;
-error_iio_unreg:
- iio_device_unregister(indio_dev);
+error_remove_callback:
+ sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_INCLINOMETER_3D);
error_remove_trigger:
hid_sensor_remove_trigger(indio_dev, &incl_state->common_attributes);
return ret;
@@ -388,8 +383,8 @@ static void hid_incl_3d_remove(struct platform_device *pdev)
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct incl_3d_state *incl_state = iio_priv(indio_dev);
- sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_INCLINOMETER_3D);
iio_device_unregister(indio_dev);
+ sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_INCLINOMETER_3D);
hid_sensor_remove_trigger(indio_dev, &incl_state->common_attributes);
}
diff --git a/drivers/iio/orientation/hid-sensor-rotation.c b/drivers/iio/orientation/hid-sensor-rotation.c
index 9e5c14357a00..f8c98f866cb0 100644
--- a/drivers/iio/orientation/hid-sensor-rotation.c
+++ b/drivers/iio/orientation/hid-sensor-rotation.c
@@ -80,9 +80,8 @@ static const struct iio_chan_spec dev_rot_channels[] = {
/* Channel read_raw handler */
static int dev_rot_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int size, int *vals, int *val_len,
- long mask)
+ struct iio_chan_spec const *chan,
+ int size, int *vals, int *val_len, long mask)
{
struct dev_rot_state *rot_state = iio_priv(indio_dev);
struct hid_sensor_hub_device *hsdev = rot_state->common_attributes.hsdev;
@@ -164,10 +163,8 @@ static int dev_rot_read_raw(struct iio_dev *indio_dev,
/* Channel write_raw handler */
static int dev_rot_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val,
- int val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
{
struct dev_rot_state *rot_state = iio_priv(indio_dev);
int ret;
@@ -211,8 +208,7 @@ static const struct iio_info dev_rot_info = {
/* Callback handler to send event after all samples are received and captured */
static int dev_rot_proc_event(struct hid_sensor_hub_device *hsdev,
- u32 usage_id,
- void *priv)
+ u32 usage_id, void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct dev_rot_state *rot_state = iio_priv(indio_dev);
@@ -244,9 +240,9 @@ static int dev_rot_proc_event(struct hid_sensor_hub_device *hsdev,
/* Capture samples in local storage */
static int dev_rot_capture_sample(struct hid_sensor_hub_device *hsdev,
- u32 usage_id,
- size_t raw_len, char *raw_data,
- void *priv)
+ u32 usage_id,
+ size_t raw_len, char *raw_data,
+ void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct dev_rot_state *rot_state = iio_priv(indio_dev);
@@ -313,7 +309,7 @@ static int hid_dev_rot_probe(struct platform_device *pdev)
indio_dev = devm_iio_device_alloc(&pdev->dev,
sizeof(struct dev_rot_state));
- if (indio_dev == NULL)
+ if (!indio_dev)
return -ENOMEM;
platform_set_drvdata(pdev, indio_dev);
@@ -361,32 +357,32 @@ static int hid_dev_rot_probe(struct platform_device *pdev)
atomic_set(&rot_state->common_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name,
- &rot_state->common_attributes);
+ &rot_state->common_attributes);
if (ret) {
dev_err(&pdev->dev, "trigger setup failed\n");
return ret;
}
- ret = iio_device_register(indio_dev);
- if (ret) {
- dev_err(&pdev->dev, "device register failed\n");
- goto error_remove_trigger;
- }
-
rot_state->callbacks.send_event = dev_rot_proc_event;
rot_state->callbacks.capture_sample = dev_rot_capture_sample;
rot_state->callbacks.pdev = pdev;
ret = sensor_hub_register_callback(hsdev, hsdev->usage,
- &rot_state->callbacks);
+ &rot_state->callbacks);
if (ret) {
dev_err(&pdev->dev, "callback reg failed\n");
- goto error_iio_unreg;
+ goto error_remove_trigger;
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "device register failed\n");
+ goto error_remove_callback;
}
return 0;
-error_iio_unreg:
- iio_device_unregister(indio_dev);
+error_remove_callback:
+ sensor_hub_remove_callback(hsdev, hsdev->usage);
error_remove_trigger:
hid_sensor_remove_trigger(indio_dev, &rot_state->common_attributes);
return ret;
@@ -399,8 +395,8 @@ static void hid_dev_rot_remove(struct platform_device *pdev)
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct dev_rot_state *rot_state = iio_priv(indio_dev);
- sensor_hub_remove_callback(hsdev, hsdev->usage);
iio_device_unregister(indio_dev);
+ sensor_hub_remove_callback(hsdev, hsdev->usage);
hid_sensor_remove_trigger(indio_dev, &rot_state->common_attributes);
}
diff --git a/drivers/iio/position/hid-sensor-custom-intel-hinge.c b/drivers/iio/position/hid-sensor-custom-intel-hinge.c
index a0b984357bf0..d275bc1413fe 100644
--- a/drivers/iio/position/hid-sensor-custom-intel-hinge.c
+++ b/drivers/iio/position/hid-sensor-custom-intel-hinge.c
@@ -106,8 +106,8 @@ static void hinge_adjust_channel_realbits(struct iio_chan_spec *channels,
/* Channel read_raw handler */
static int hinge_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan, int *val, int *val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
{
struct hinge_state *st = iio_priv(indio_dev);
struct hid_sensor_hub_device *hsdev;
@@ -153,8 +153,8 @@ static int hinge_read_raw(struct iio_dev *indio_dev,
/* Channel write_raw handler */
static int hinge_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan, int val, int val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
{
struct hinge_state *st = iio_priv(indio_dev);
@@ -208,8 +208,9 @@ static int hinge_proc_event(struct hid_sensor_hub_device *hsdev,
/* Capture samples in local storage */
static int hinge_capture_sample(struct hid_sensor_hub_device *hsdev,
- u32 usage_id, size_t raw_len,
- char *raw_data, void *priv)
+ u32 usage_id,
+ size_t raw_len, char *raw_data,
+ void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct hinge_state *st = iio_priv(indio_dev);
@@ -291,7 +292,7 @@ static int hid_hinge_probe(struct platform_device *pdev)
}
indio_dev->num_channels = ARRAY_SIZE(hinge_channels);
- indio_dev->channels = devm_kmemdup(&indio_dev->dev, hinge_channels,
+ indio_dev->channels = devm_kmemdup(&pdev->dev, hinge_channels,
sizeof(hinge_channels), GFP_KERNEL);
if (!indio_dev->channels)
return -ENOMEM;
diff --git a/drivers/iio/potentiostat/lmp91000.c b/drivers/iio/potentiostat/lmp91000.c
index 1984d990438c..00cb3fea97ca 100644
--- a/drivers/iio/potentiostat/lmp91000.c
+++ b/drivers/iio/potentiostat/lmp91000.c
@@ -422,3 +422,4 @@ module_i2c_driver(lmp91000_driver);
MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
MODULE_DESCRIPTION("LMP91000 digital potentiostat");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/iio/pressure/hid-sensor-press.c b/drivers/iio/pressure/hid-sensor-press.c
index 989d6d0fa94c..e688b0776547 100644
--- a/drivers/iio/pressure/hid-sensor-press.c
+++ b/drivers/iio/pressure/hid-sensor-press.c
@@ -55,9 +55,8 @@ static const struct iio_chan_spec press_channels[] = {
/* Channel read_raw handler */
static int press_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int *val, int *val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
{
struct press_state *press_state = iio_priv(indio_dev);
int report_id = -1;
@@ -81,7 +80,7 @@ static int press_read_raw(struct iio_dev *indio_dev,
}
if (report_id >= 0) {
hid_sensor_power_state(&press_state->common_attributes,
- true);
+ true);
*val = sensor_hub_input_attr_get_raw_value(
press_state->common_attributes.hsdev,
HID_USAGE_SENSOR_PRESSURE, address,
@@ -89,7 +88,7 @@ static int press_read_raw(struct iio_dev *indio_dev,
SENSOR_HUB_SYNC,
min < 0);
hid_sensor_power_state(&press_state->common_attributes,
- false);
+ false);
} else {
*val = 0;
return -EINVAL;
@@ -123,10 +122,8 @@ static int press_read_raw(struct iio_dev *indio_dev,
/* Channel write_raw handler */
static int press_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val,
- int val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
{
struct press_state *press_state = iio_priv(indio_dev);
int ret = 0;
@@ -154,8 +151,7 @@ static const struct iio_info press_info = {
/* Callback handler to send event after all samples are received and captured */
static int press_proc_event(struct hid_sensor_hub_device *hsdev,
- u32 usage_id,
- void *priv)
+ u32 usage_id, void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct press_state *press_state = iio_priv(indio_dev);
@@ -201,10 +197,10 @@ static int press_capture_sample(struct hid_sensor_hub_device *hsdev,
/* Parse report which is specific to an usage id*/
static int press_parse_report(struct platform_device *pdev,
- struct hid_sensor_hub_device *hsdev,
- struct iio_chan_spec *channels,
- u32 usage_id,
- struct press_state *st)
+ struct hid_sensor_hub_device *hsdev,
+ struct iio_chan_spec *channels,
+ u32 usage_id,
+ struct press_state *st)
{
int ret;
@@ -221,7 +217,7 @@ static int press_parse_report(struct platform_device *pdev,
};
dev_dbg(&pdev->dev, "press %x:%x\n", st->press_attr.index,
- st->press_attr.report_id);
+ st->press_attr.report_id);
st->scale_precision = hid_sensor_format_scale(
HID_USAGE_SENSOR_PRESSURE,
@@ -240,8 +236,7 @@ static int hid_press_probe(struct platform_device *pdev)
struct iio_dev *indio_dev;
struct press_state *press_state;
- indio_dev = devm_iio_device_alloc(&pdev->dev,
- sizeof(struct press_state));
+ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct press_state));
if (!indio_dev)
return -ENOMEM;
platform_set_drvdata(pdev, indio_dev);
@@ -284,32 +279,32 @@ static int hid_press_probe(struct platform_device *pdev)
atomic_set(&press_state->common_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name,
- &press_state->common_attributes);
+ &press_state->common_attributes);
if (ret) {
dev_err(&pdev->dev, "trigger setup failed\n");
return ret;
}
- ret = iio_device_register(indio_dev);
- if (ret) {
- dev_err(&pdev->dev, "device register failed\n");
- goto error_remove_trigger;
- }
-
press_state->callbacks.send_event = press_proc_event;
press_state->callbacks.capture_sample = press_capture_sample;
press_state->callbacks.pdev = pdev;
ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_PRESSURE,
- &press_state->callbacks);
+ &press_state->callbacks);
if (ret < 0) {
dev_err(&pdev->dev, "callback reg failed\n");
- goto error_iio_unreg;
+ goto error_remove_trigger;
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "device register failed\n");
+ goto error_remove_callback;
}
return ret;
-error_iio_unreg:
- iio_device_unregister(indio_dev);
+error_remove_callback:
+ sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PRESSURE);
error_remove_trigger:
hid_sensor_remove_trigger(indio_dev, &press_state->common_attributes);
return ret;
@@ -322,8 +317,8 @@ static void hid_press_remove(struct platform_device *pdev)
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct press_state *press_state = iio_priv(indio_dev);
- sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PRESSURE);
iio_device_unregister(indio_dev);
+ sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PRESSURE);
hid_sensor_remove_trigger(indio_dev, &press_state->common_attributes);
}
diff --git a/drivers/iio/pressure/rohm-bm1390.c b/drivers/iio/pressure/rohm-bm1390.c
index b3be9de03678..9d72ae64126c 100644
--- a/drivers/iio/pressure/rohm-bm1390.c
+++ b/drivers/iio/pressure/rohm-bm1390.c
@@ -621,17 +621,15 @@ static const struct iio_buffer_setup_ops bm1390_buffer_ops = {
.predisable = bm1390_buffer_predisable,
};
-static irqreturn_t bm1390_trigger_handler(int irq, void *p)
+static bool bm1390_handle_trigger(struct iio_dev *idev)
{
- struct iio_poll_func *pf = p;
- struct iio_dev *idev = pf->indio_dev;
struct bm1390_data *data = iio_priv(idev);
int ret, status;
/* DRDY is acked by reading status reg */
ret = regmap_read(data->regmap, BM1390_REG_STATUS, &status);
if (ret || !status)
- return IRQ_NONE;
+ return false;
dev_dbg(data->dev, "DRDY trig status 0x%x\n", status);
@@ -639,7 +637,7 @@ static irqreturn_t bm1390_trigger_handler(int irq, void *p)
ret = bm1390_pressure_read(data, &data->buf.pressure);
if (ret) {
dev_warn(data->dev, "sample read failed %d\n", ret);
- return IRQ_NONE;
+ return false;
}
}
@@ -648,15 +646,26 @@ static irqreturn_t bm1390_trigger_handler(int irq, void *p)
&data->buf.temp, sizeof(data->buf.temp));
if (ret) {
dev_warn(data->dev, "temp read failed %d\n", ret);
- return IRQ_HANDLED;
+ return true;
}
}
iio_push_to_buffers_with_ts(idev, &data->buf, sizeof(data->buf),
data->timestamp);
+
+ return true;
+}
+
+static irqreturn_t bm1390_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *idev = pf->indio_dev;
+ bool result;
+
+ result = bm1390_handle_trigger(idev);
iio_trigger_notify_done(idev->trig);
- return IRQ_HANDLED;
+ return IRQ_RETVAL(result);
}
/* Get timestamps and wake the thread if we need to read data */
diff --git a/drivers/iio/resolver/ad2s1210.c b/drivers/iio/resolver/ad2s1210.c
index db8e34e2ba73..3b5ec21e3446 100644
--- a/drivers/iio/resolver/ad2s1210.c
+++ b/drivers/iio/resolver/ad2s1210.c
@@ -1276,10 +1276,8 @@ static int ad2s1210_debugfs_reg_access(struct iio_dev *indio_dev,
return regmap_write(st->regmap, reg, writeval);
}
-static irqreturn_t ad2s1210_trigger_handler(int irq, void *p)
+static void ad2s1210_scan_to_buffers(struct iio_dev *indio_dev, s64 timestamp)
{
- struct iio_poll_func *pf = p;
- struct iio_dev *indio_dev = pf->indio_dev;
struct ad2s1210_state *st = iio_priv(indio_dev);
size_t chan = 0;
int ret;
@@ -1295,15 +1293,15 @@ static irqreturn_t ad2s1210_trigger_handler(int irq, void *p)
AD2S1210_REG_POSITION_MSB,
&st->sample.raw, 2);
if (ret < 0)
- goto error_ret;
+ return;
} else {
ret = ad2s1210_set_mode(st, MOD_POS);
if (ret < 0)
- goto error_ret;
+ return;
ret = spi_read(st->sdev, &st->sample, 3);
if (ret < 0)
- goto error_ret;
+ return;
}
memcpy(&st->scan.chan[chan++], &st->sample.raw, 2);
@@ -1315,15 +1313,15 @@ static irqreturn_t ad2s1210_trigger_handler(int irq, void *p)
AD2S1210_REG_VELOCITY_MSB,
&st->sample.raw, 2);
if (ret < 0)
- goto error_ret;
+ return;
} else {
ret = ad2s1210_set_mode(st, MOD_VEL);
if (ret < 0)
- goto error_ret;
+ return;
ret = spi_read(st->sdev, &st->sample, 3);
if (ret < 0)
- goto error_ret;
+ return;
}
memcpy(&st->scan.chan[chan++], &st->sample.raw, 2);
@@ -1334,16 +1332,22 @@ static irqreturn_t ad2s1210_trigger_handler(int irq, void *p)
ret = regmap_read(st->regmap, AD2S1210_REG_FAULT, &reg_val);
if (ret < 0)
- goto error_ret;
+ return;
st->sample.fault = reg_val;
}
- ad2s1210_push_events(indio_dev, st->sample.fault, pf->timestamp);
+ ad2s1210_push_events(indio_dev, st->sample.fault, timestamp);
iio_push_to_buffers_with_ts(indio_dev, &st->scan, sizeof(st->scan),
- pf->timestamp);
+ timestamp);
+}
+
+static irqreturn_t ad2s1210_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
-error_ret:
+ ad2s1210_scan_to_buffers(indio_dev, pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
diff --git a/drivers/iio/temperature/hid-sensor-temperature.c b/drivers/iio/temperature/hid-sensor-temperature.c
index 586b5bc002c7..76723176d6b6 100644
--- a/drivers/iio/temperature/hid-sensor-temperature.c
+++ b/drivers/iio/temperature/hid-sensor-temperature.c
@@ -44,7 +44,7 @@ static const struct iio_chan_spec temperature_channels[] = {
/* Adjust channel real bits based on report descriptor */
static void temperature_adjust_channel_bit_mask(struct iio_chan_spec *channels,
- int channel, int size)
+ int channel, int size)
{
channels[channel].scan_type.sign = 's';
/* Real storage bits will change based on the report desc. */
@@ -100,8 +100,8 @@ static int temperature_read_raw(struct iio_dev *indio_dev,
}
static int temperature_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val, int val2, long mask)
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
{
struct temperature_state *temp_st = iio_priv(indio_dev);
@@ -124,7 +124,7 @@ static const struct iio_info temperature_info = {
/* Callback handler to send event after all samples are received and captured */
static int temperature_proc_event(struct hid_sensor_hub_device *hsdev,
- u32 usage_id, void *pdev)
+ u32 usage_id, void *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct temperature_state *temp_st = iio_priv(indio_dev);
@@ -139,8 +139,9 @@ static int temperature_proc_event(struct hid_sensor_hub_device *hsdev,
/* Capture samples in local storage */
static int temperature_capture_sample(struct hid_sensor_hub_device *hsdev,
- u32 usage_id, size_t raw_len,
- char *raw_data, void *pdev)
+ u32 usage_id,
+ size_t raw_len, char *raw_data,
+ void *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct temperature_state *temp_st = iio_priv(indio_dev);
@@ -156,10 +157,10 @@ static int temperature_capture_sample(struct hid_sensor_hub_device *hsdev,
/* Parse report which is specific to an usage id*/
static int temperature_parse_report(struct platform_device *pdev,
- struct hid_sensor_hub_device *hsdev,
- struct iio_chan_spec *channels,
- u32 usage_id,
- struct temperature_state *st)
+ struct hid_sensor_hub_device *hsdev,
+ struct iio_chan_spec *channels,
+ u32 usage_id,
+ struct temperature_state *st)
{
int ret;
@@ -170,8 +171,7 @@ static int temperature_parse_report(struct platform_device *pdev,
if (ret < 0)
return ret;
- temperature_adjust_channel_bit_mask(channels, 0,
- st->temperature_attr.size);
+ temperature_adjust_channel_bit_mask(channels, 0, st->temperature_attr.size);
st->scale_precision = hid_sensor_format_scale(
HID_USAGE_SENSOR_TEMPERATURE,
@@ -212,13 +212,13 @@ static int hid_temperature_probe(struct platform_device *pdev)
if (ret)
return ret;
- temp_chans = devm_kmemdup(&indio_dev->dev, temperature_channels,
- sizeof(temperature_channels), GFP_KERNEL);
+ temp_chans = devm_kmemdup(&pdev->dev, temperature_channels,
+ sizeof(temperature_channels), GFP_KERNEL);
if (!temp_chans)
return -ENOMEM;
ret = temperature_parse_report(pdev, hsdev, temp_chans,
- HID_USAGE_SENSOR_TEMPERATURE, temp_st);
+ HID_USAGE_SENSOR_TEMPERATURE, temp_st);
if (ret)
return ret;
@@ -231,7 +231,7 @@ static int hid_temperature_probe(struct platform_device *pdev)
atomic_set(&temp_st->common_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name,
- &temp_st->common_attributes);
+ &temp_st->common_attributes);
if (ret)
return ret;
@@ -239,7 +239,7 @@ static int hid_temperature_probe(struct platform_device *pdev)
temperature_callbacks.pdev = pdev;
ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_TEMPERATURE,
- &temperature_callbacks);
+ &temperature_callbacks);
if (ret)
goto error_remove_trigger;
diff --git a/drivers/infiniband/hw/bng_re/bng_fw.c b/drivers/infiniband/hw/bng_re/bng_fw.c
index 50156c300b33..ab6a2d2e95b5 100644
--- a/drivers/infiniband/hw/bng_re/bng_fw.c
+++ b/drivers/infiniband/hw/bng_re/bng_fw.c
@@ -401,14 +401,15 @@ static int __wait_for_resp(struct bng_re_rcfw *rcfw, u16 cookie)
{
struct bng_re_cmdq_ctx *cmdq;
struct bng_re_crsqe *crsqe;
+ unsigned long time_left;
cmdq = &rcfw->cmdq;
crsqe = &rcfw->crsqe_tbl[cookie];
do {
- wait_event_timeout(cmdq->waitq,
- !crsqe->is_in_used,
- secs_to_jiffies(rcfw->max_timeout));
+ time_left = wait_event_timeout(cmdq->waitq,
+ !crsqe->is_in_used,
+ secs_to_jiffies(rcfw->max_timeout));
if (!crsqe->is_in_used)
return 0;
@@ -417,6 +418,9 @@ static int __wait_for_resp(struct bng_re_rcfw *rcfw, u16 cookie)
if (!crsqe->is_in_used)
return 0;
+
+ if (!time_left)
+ return -ENODEV;
} while (true);
};
diff --git a/drivers/infiniband/hw/hfi1/device.c b/drivers/infiniband/hw/hfi1/device.c
index a98a4175e53b..adcfb80d52d4 100644
--- a/drivers/infiniband/hw/hfi1/device.c
+++ b/drivers/infiniband/hw/hfi1/device.c
@@ -10,18 +10,6 @@
#include "hfi.h"
#include "device.h"
-static char *hfi1_devnode(const struct device *dev, umode_t *mode)
-{
- if (mode)
- *mode = 0600;
- return kasprintf(GFP_KERNEL, "%s", dev_name(dev));
-}
-
-static const struct class class = {
- .name = "hfi1",
- .devnode = hfi1_devnode,
-};
-
static char *hfi1_user_devnode(const struct device *dev, umode_t *mode)
{
if (mode)
@@ -38,7 +26,6 @@ static dev_t hfi1_dev;
int hfi1_cdev_init(int minor, const char *name,
const struct file_operations *fops,
struct cdev *cdev, struct device **devp,
- bool user_accessible,
struct kobject *parent)
{
const dev_t dev = MKDEV(MAJOR(hfi1_dev), minor);
@@ -57,10 +44,7 @@ int hfi1_cdev_init(int minor, const char *name,
goto done;
}
- if (user_accessible)
- device = device_create(&user_class, NULL, dev, NULL, "%s", name);
- else
- device = device_create(&class, NULL, dev, NULL, "%s", name);
+ device = device_create(&user_class, NULL, dev, NULL, "%s", name);
if (IS_ERR(device)) {
ret = PTR_ERR(device);
@@ -100,33 +84,21 @@ int __init dev_init(void)
ret = alloc_chrdev_region(&hfi1_dev, 0, HFI1_NMINORS, DRIVER_NAME);
if (ret < 0) {
pr_err("Could not allocate chrdev region (err %d)\n", -ret);
- goto done;
- }
-
- ret = class_register(&class);
- if (ret) {
- pr_err("Could not create device class (err %d)\n", -ret);
- unregister_chrdev_region(hfi1_dev, HFI1_NMINORS);
- goto done;
+ return ret;
}
ret = class_register(&user_class);
if (ret) {
pr_err("Could not create device class for user accessible files (err %d)\n",
-ret);
- class_unregister(&class);
unregister_chrdev_region(hfi1_dev, HFI1_NMINORS);
- goto done;
}
-done:
return ret;
}
void dev_cleanup(void)
{
- class_unregister(&class);
class_unregister(&user_class);
-
unregister_chrdev_region(hfi1_dev, HFI1_NMINORS);
}
diff --git a/drivers/infiniband/hw/hfi1/device.h b/drivers/infiniband/hw/hfi1/device.h
index a91bea426ba5..3e2d21770e6c 100644
--- a/drivers/infiniband/hw/hfi1/device.h
+++ b/drivers/infiniband/hw/hfi1/device.h
@@ -9,7 +9,6 @@
int hfi1_cdev_init(int minor, const char *name,
const struct file_operations *fops,
struct cdev *cdev, struct device **devp,
- bool user_accessible,
struct kobject *parent);
void hfi1_cdev_cleanup(struct cdev *cdev, struct device **devp);
const char *class_name(void);
diff --git a/drivers/infiniband/hw/hfi1/file_ops.c b/drivers/infiniband/hw/hfi1/file_ops.c
index 56031becb273..dc548e6802e2 100644
--- a/drivers/infiniband/hw/hfi1/file_ops.c
+++ b/drivers/infiniband/hw/hfi1/file_ops.c
@@ -1689,7 +1689,7 @@ static int user_add(struct hfi1_devdata *dd)
snprintf(name, sizeof(name), "%s_%d", class_name(), dd->unit);
ret = hfi1_cdev_init(dd->unit, name, &hfi1_file_ops,
&dd->user_cdev, &dd->user_device,
- true, &dd->verbs_dev.rdi.ibdev.dev.kobj);
+ &dd->verbs_dev.rdi.ibdev.dev.kobj);
if (ret)
user_remove(dd);
diff --git a/drivers/infiniband/hw/ionic/ionic_ibdev.h b/drivers/infiniband/hw/ionic/ionic_ibdev.h
index 63828240d659..53dab2d54844 100644
--- a/drivers/infiniband/hw/ionic/ionic_ibdev.h
+++ b/drivers/infiniband/hw/ionic/ionic_ibdev.h
@@ -33,7 +33,6 @@
#define IONIC_MAX_QPID 0xffffff
#define IONIC_SPEC_HIGH 8
#define IONIC_MAX_PD 1024
-#define IONIC_SPEC_HIGH 8
#define IONIC_SQCMB_ORDER 5
#define IONIC_RQCMB_ORDER 0
diff --git a/drivers/infiniband/hw/irdma/i40iw_hw.c b/drivers/infiniband/hw/irdma/i40iw_hw.c
index 60c1f2b1811d..8301938b4543 100644
--- a/drivers/infiniband/hw/irdma/i40iw_hw.c
+++ b/drivers/infiniband/hw/irdma/i40iw_hw.c
@@ -29,7 +29,9 @@ static u32 i40iw_regs[IRDMA_MAX_REGS] = {
I40E_PFHMC_PDINV,
I40E_GLHMC_VFPDINV(0),
I40E_GLPE_CRITERR,
- 0xffffffff /* PFINT_RATEN not used in FPK */
+ 0xffffffff, /* PFINT_RATEN not used in FPK */
+ 0xffffffff, /* PFHMC_ERRORINFO not used in FPK */
+ 0xffffffff /* PFHMC_ERRORDATA not used in FPK */
};
static u32 i40iw_stat_offsets[] = {
diff --git a/drivers/infiniband/hw/irdma/icrdma_hw.c b/drivers/infiniband/hw/irdma/icrdma_hw.c
index 32f26284a788..b1f1b5485762 100644
--- a/drivers/infiniband/hw/irdma/icrdma_hw.c
+++ b/drivers/infiniband/hw/irdma/icrdma_hw.c
@@ -29,6 +29,8 @@ static u32 icrdma_regs[IRDMA_MAX_REGS] = {
GLHMC_VFPDINV(0),
GLPE_CRITERR,
GLINT_RATE(0),
+ PFHMC_ERRORINFO,
+ PFHMC_ERRORDATA,
};
static u64 icrdma_masks[IRDMA_MAX_MASKS] = {
diff --git a/drivers/infiniband/hw/irdma/icrdma_hw.h b/drivers/infiniband/hw/irdma/icrdma_hw.h
index d97944ab45da..0acdeda1236d 100644
--- a/drivers/infiniband/hw/irdma/icrdma_hw.h
+++ b/drivers/infiniband/hw/irdma/icrdma_hw.h
@@ -40,6 +40,8 @@
#define GLHMC_VFPDINV(_i) (0x00528300 + ((_i) * 4)) /* _i=0...31 */
#define GLPE_CRITERR 0x00534000
#define GLINT_RATE(_INT) (0x0015A000 + ((_INT) * 4)) /* _i=0...2047 */ /* Reset Source: CORER */
+#define PFHMC_ERRORINFO 0x00520400
+#define PFHMC_ERRORDATA 0x00520500
#define ICRDMA_DB_ADDR_OFFSET (8 * 1024 * 1024 - 64 * 1024)
diff --git a/drivers/infiniband/hw/irdma/icrdma_if.c b/drivers/infiniband/hw/irdma/icrdma_if.c
index 2172a2092e3f..4b451d8482a4 100644
--- a/drivers/infiniband/hw/irdma/icrdma_if.c
+++ b/drivers/infiniband/hw/irdma/icrdma_if.c
@@ -91,8 +91,12 @@ static void icrdma_iidc_event_handler(struct iidc_rdma_core_dev_info *cdev_info,
}
}
if (event->reg & IRDMAPFINT_OICR_HMC_ERR_M) {
- ibdev_err(&iwdev->ibdev, "HMC Error\n");
- iwdev->rf->reset = true;
+ u32 hmc_errinfo = readl(iwdev->rf->sc_dev.hw_regs[IRDMA_PFHMC_ERRORINFO]);
+ u32 hmc_errdata = readl(iwdev->rf->sc_dev.hw_regs[IRDMA_PFHMC_ERRORDATA]);
+
+ /* Log diagnostics; do not reset here. */
+ ibdev_warn(&iwdev->ibdev, "HMC Error: errinfo=0x%08x errdata=0x%08x\n",
+ hmc_errinfo, hmc_errdata);
}
if (event->reg & IRDMAPFINT_OICR_PE_PUSH_M) {
ibdev_err(&iwdev->ibdev, "PE Push Error\n");
diff --git a/drivers/infiniband/hw/irdma/irdma.h b/drivers/infiniband/hw/irdma/irdma.h
index b5ce515f4ee8..d4530520e39f 100644
--- a/drivers/infiniband/hw/irdma/irdma.h
+++ b/drivers/infiniband/hw/irdma/irdma.h
@@ -66,6 +66,8 @@ enum irdma_registers {
IRDMA_GLHMC_VFPDINV,
IRDMA_GLPE_CRITERR,
IRDMA_GLINT_RATE,
+ IRDMA_PFHMC_ERRORINFO,
+ IRDMA_PFHMC_ERRORDATA,
IRDMA_MAX_REGS, /* Must be last entry */
};
diff --git a/drivers/infiniband/hw/irdma/utils.c b/drivers/infiniband/hw/irdma/utils.c
index e4037d5ef899..290ad02ed657 100644
--- a/drivers/infiniband/hw/irdma/utils.c
+++ b/drivers/infiniband/hw/irdma/utils.c
@@ -1168,6 +1168,12 @@ void irdma_free_qp_rsrc(struct irdma_qp *iwqp)
iwqp->kqp.dma_mem.va = NULL;
kfree(iwqp->kqp.sq_wrid_mem);
kfree(iwqp->kqp.rq_wrid_mem);
+
+ if (iwqp->user_mode && iwqp->iwpbl) {
+ struct irdma_mr *iwmr = iwqp->iwpbl->iwmr;
+
+ refcount_dec(&iwmr->user_ring_refs);
+ }
}
/**
diff --git a/drivers/infiniband/hw/irdma/verbs.c b/drivers/infiniband/hw/irdma/verbs.c
index be8c5cf12f7f..04d5af78686b 100644
--- a/drivers/infiniband/hw/irdma/verbs.c
+++ b/drivers/infiniband/hw/irdma/verbs.c
@@ -464,6 +464,9 @@ static struct irdma_pbl *irdma_get_pbl(unsigned long va,
list_for_each_entry (iwpbl, pbl_list, list) {
if (iwpbl->user_base == va) {
+ struct irdma_mr *iwmr = iwpbl->iwmr;
+
+ refcount_inc(&iwmr->user_ring_refs);
list_del(&iwpbl->list);
iwpbl->on_list = false;
return iwpbl;
@@ -1880,6 +1883,11 @@ static void irdma_srq_free_rsrc(struct irdma_pci_f *rf, struct irdma_srq *iwsrq)
dma_free_coherent(rf->sc_dev.hw->device, iwsrq->kmem.size,
iwsrq->kmem.va, iwsrq->kmem.pa);
iwsrq->kmem.va = NULL;
+ } else {
+ /* Not called in any failure path, so iwpbl is valid. */
+ struct irdma_mr *iwmr = iwsrq->iwpbl->iwmr;
+
+ refcount_dec(&iwmr->user_ring_refs);
}
irdma_free_rsrc(rf, rf->allocated_srqs, srq->srq_uk.srq_id);
@@ -1902,6 +1910,21 @@ static void irdma_cq_free_rsrc(struct irdma_pci_f *rf, struct irdma_cq *iwcq)
iwcq->kmem_shadow.size,
iwcq->kmem_shadow.va, iwcq->kmem_shadow.pa);
iwcq->kmem_shadow.va = NULL;
+ } else {
+ struct irdma_mr *iwmr;
+
+ /* May be called in a failure path before iwpbl is valid. */
+ if (iwcq->iwpbl) {
+ iwmr = iwcq->iwpbl->iwmr;
+
+ refcount_dec(&iwmr->user_ring_refs);
+ }
+
+ if (iwcq->iwpbl_shadow) {
+ iwmr = iwcq->iwpbl_shadow->iwmr;
+
+ refcount_dec(&iwmr->user_ring_refs);
+ }
}
irdma_free_rsrc(rf, rf->allocated_cqs, cq->cq_uk.cq_id);
@@ -2017,7 +2040,7 @@ static int irdma_resize_cq(struct ib_cq *ibcq, unsigned int entries,
struct irdma_modify_cq_info info = {};
struct irdma_dma_mem kmem_buf;
struct irdma_cq_mr *cqmr_buf;
- struct irdma_pbl *iwpbl_buf;
+ struct irdma_pbl *iwpbl_buf = NULL;
struct irdma_device *iwdev;
struct irdma_pci_f *rf;
struct irdma_cq_buf *cq_buf = NULL;
@@ -2128,6 +2151,19 @@ static int irdma_resize_cq(struct ib_cq *ibcq, unsigned int entries,
goto error;
spin_lock_irqsave(&iwcq->lock, flags);
+ if (udata) {
+ struct irdma_pbl *old_iwpbl = iwcq->iwpbl;
+
+ /* Only update if the resize was successful. Otherwise, HW is
+ * still pointing to the old PBL.
+ */
+ iwcq->iwpbl = iwpbl_buf;
+ if (old_iwpbl) {
+ struct irdma_mr *old_iwmr = old_iwpbl->iwmr;
+
+ refcount_dec(&old_iwmr->user_ring_refs);
+ }
+ }
if (cq_buf) {
cq_buf->kmem_buf = iwcq->kmem;
cq_buf->hw = dev->hw;
@@ -2143,6 +2179,11 @@ static int irdma_resize_cq(struct ib_cq *ibcq, unsigned int entries,
return 0;
error:
+ if (iwpbl_buf) {
+ struct irdma_mr *iwmr = iwpbl_buf->iwmr;
+
+ refcount_dec(&iwmr->user_ring_refs);
+ }
if (!udata) {
dma_free_coherent(dev->hw->device, kmem_buf.size, kmem_buf.va,
kmem_buf.pa);
@@ -2419,6 +2460,11 @@ free_dmem:
dma_free_coherent(rf->hw.device, iwsrq->kmem.size,
iwsrq->kmem.va, iwsrq->kmem.pa);
free_rsrc:
+ if (iwsrq->user_mode && iwsrq->iwpbl) {
+ struct irdma_mr *iwmr = iwsrq->iwpbl->iwmr;
+
+ refcount_dec(&iwmr->user_ring_refs);
+ }
irdma_free_rsrc(rf, rf->allocated_srqs, iwsrq->srq_num);
return err_code;
}
@@ -2498,6 +2544,8 @@ static int irdma_create_cq(struct ib_cq *ibcq,
INIT_LIST_HEAD(&iwcq->resize_list);
INIT_LIST_HEAD(&iwcq->cmpl_generated);
iwcq->cq_num = cq_num;
+ iwcq->iwpbl = NULL;
+ iwcq->iwpbl_shadow = NULL;
info.dev = dev;
ukinfo->cq_size = max(entries, 4);
ukinfo->cq_id = cq_num;
@@ -2517,8 +2565,6 @@ static int irdma_create_cq(struct ib_cq *ibcq,
struct irdma_ucontext *ucontext;
struct irdma_create_cq_req req = {};
struct irdma_cq_mr *cqmr;
- struct irdma_pbl *iwpbl;
- struct irdma_pbl *iwpbl_shadow;
struct irdma_cq_mr *cqmr_shadow;
iwcq->user_mode = true;
@@ -2532,34 +2578,34 @@ static int irdma_create_cq(struct ib_cq *ibcq,
}
spin_lock_irqsave(&ucontext->cq_reg_mem_list_lock, flags);
- iwpbl = irdma_get_pbl((unsigned long)req.user_cq_buf,
- &ucontext->cq_reg_mem_list);
+ iwcq->iwpbl = irdma_get_pbl((unsigned long)req.user_cq_buf,
+ &ucontext->cq_reg_mem_list);
spin_unlock_irqrestore(&ucontext->cq_reg_mem_list_lock, flags);
- if (!iwpbl) {
+ if (!iwcq->iwpbl) {
err_code = -EPROTO;
goto cq_free_rsrc;
}
- cqmr = &iwpbl->cq_mr;
+ cqmr = &iwcq->iwpbl->cq_mr;
if (rf->sc_dev.hw_attrs.uk_attrs.feature_flags &
IRDMA_FEATURE_CQ_RESIZE) {
spin_lock_irqsave(&ucontext->cq_reg_mem_list_lock, flags);
- iwpbl_shadow = irdma_get_pbl(
+ iwcq->iwpbl_shadow = irdma_get_pbl(
(unsigned long)req.user_shadow_area,
&ucontext->cq_reg_mem_list);
spin_unlock_irqrestore(&ucontext->cq_reg_mem_list_lock, flags);
- if (!iwpbl_shadow) {
+ if (!iwcq->iwpbl_shadow) {
err_code = -EPROTO;
goto cq_free_rsrc;
}
- cqmr_shadow = &iwpbl_shadow->cq_mr;
+ cqmr_shadow = &iwcq->iwpbl_shadow->cq_mr;
info.shadow_area_pa = cqmr_shadow->cq_pbl.addr;
} else {
info.shadow_area_pa = cqmr->shadow;
}
- if (iwpbl->pbl_allocated) {
+ if (iwcq->iwpbl->pbl_allocated) {
info.virtual_map = true;
info.pbl_chunk_size = 1;
info.first_pm_pbl_idx = cqmr->cq_pbl.idx;
@@ -2801,7 +2847,7 @@ static bool irdma_check_mem_contiguous(u64 *arr, u32 npages, u32 pg_size)
u32 pg_idx;
for (pg_idx = 0; pg_idx < npages; pg_idx++) {
- if ((*arr + (pg_size * pg_idx)) != arr[pg_idx])
+ if ((*arr + ((u64)pg_size * pg_idx)) != arr[pg_idx])
return false;
}
@@ -2834,7 +2880,7 @@ static bool irdma_check_mr_contiguous(struct irdma_pble_alloc *palloc,
for (i = 0; i < lvl2->leaf_cnt; i++, leaf++) {
arr = leaf->addr;
- if ((*start_addr + (i * pg_size * PBLE_PER_PAGE)) != *arr)
+ if ((*start_addr + ((u64)i * pg_size * PBLE_PER_PAGE)) != *arr)
return false;
ret = irdma_check_mem_contiguous(arr, leaf->cnt, pg_size);
if (!ret)
@@ -3362,6 +3408,7 @@ static struct irdma_mr *irdma_alloc_iwmr(struct ib_umem *region,
if (!iwmr)
return ERR_PTR(-ENOMEM);
+ refcount_set(&iwmr->user_ring_refs, 1);
iwpbl = &iwmr->iwpbl;
iwpbl->iwmr = iwmr;
iwmr->region = region;
@@ -3929,41 +3976,41 @@ static struct ib_mr *irdma_get_dma_mr(struct ib_pd *pd, int acc)
* irdma_del_memlist - Deleting pbl list entries for CQ/QP
* @iwmr: iwmr for IB's user page addresses
* @ucontext: ptr to user context
+ *
+ * Return: True if the MR is currently in-use by a QP/CQ/SRQ ring.
*/
-static void irdma_del_memlist(struct irdma_mr *iwmr,
+static bool irdma_del_memlist(struct irdma_mr *iwmr,
struct irdma_ucontext *ucontext)
{
struct irdma_pbl *iwpbl = &iwmr->iwpbl;
unsigned long flags;
+ spinlock_t *lock;
+ bool in_use = false;
switch (iwmr->type) {
case IRDMA_MEMREG_TYPE_CQ:
- spin_lock_irqsave(&ucontext->cq_reg_mem_list_lock, flags);
- if (iwpbl->on_list) {
- iwpbl->on_list = false;
- list_del(&iwpbl->list);
- }
- spin_unlock_irqrestore(&ucontext->cq_reg_mem_list_lock, flags);
+ lock = &ucontext->cq_reg_mem_list_lock;
break;
case IRDMA_MEMREG_TYPE_QP:
- spin_lock_irqsave(&ucontext->qp_reg_mem_list_lock, flags);
- if (iwpbl->on_list) {
- iwpbl->on_list = false;
- list_del(&iwpbl->list);
- }
- spin_unlock_irqrestore(&ucontext->qp_reg_mem_list_lock, flags);
+ lock = &ucontext->qp_reg_mem_list_lock;
break;
case IRDMA_MEMREG_TYPE_SRQ:
- spin_lock_irqsave(&ucontext->srq_reg_mem_list_lock, flags);
- if (iwpbl->on_list) {
- iwpbl->on_list = false;
- list_del(&iwpbl->list);
- }
- spin_unlock_irqrestore(&ucontext->srq_reg_mem_list_lock, flags);
+ lock = &ucontext->srq_reg_mem_list_lock;
break;
default:
- break;
+ return false;
}
+
+ spin_lock_irqsave(lock, flags);
+ if (!refcount_dec_if_one(&iwmr->user_ring_refs)) {
+ in_use = true;
+ } else if (iwpbl->on_list) {
+ iwpbl->on_list = false;
+ list_del(&iwpbl->list);
+ }
+ spin_unlock_irqrestore(lock, flags);
+
+ return in_use;
}
/**
@@ -3986,7 +4033,12 @@ static int irdma_dereg_mr(struct ib_mr *ib_mr, struct ib_udata *udata)
ucontext = rdma_udata_to_drv_context(udata,
struct irdma_ucontext,
ibucontext);
- irdma_del_memlist(iwmr, ucontext);
+
+ /* Do not allow the MR to be unpinned if it is still
+ * backing a user ring.
+ */
+ if (irdma_del_memlist(iwmr, ucontext))
+ return -EBUSY;
}
goto done;
}
diff --git a/drivers/infiniband/hw/irdma/verbs.h b/drivers/infiniband/hw/irdma/verbs.h
index 289ebc9b23ca..a1651641eb71 100644
--- a/drivers/infiniband/hw/irdma/verbs.h
+++ b/drivers/infiniband/hw/irdma/verbs.h
@@ -120,6 +120,7 @@ struct irdma_mr {
u64 len;
u64 pgaddrmem[IRDMA_MAX_SAVED_PHY_PGADDR];
struct irdma_pbl iwpbl;
+ refcount_t user_ring_refs;
};
struct irdma_srq {
@@ -152,6 +153,8 @@ struct irdma_cq {
struct list_head resize_list;
struct irdma_cq_poll_info cur_cqe;
struct list_head cmpl_generated;
+ struct irdma_pbl *iwpbl;
+ struct irdma_pbl *iwpbl_shadow;
};
struct irdma_cmpl_gen {
diff --git a/drivers/infiniband/sw/rxe/rxe_mw.c b/drivers/infiniband/sw/rxe/rxe_mw.c
index 379e65bfcd49..bddb7a257831 100644
--- a/drivers/infiniband/sw/rxe/rxe_mw.c
+++ b/drivers/infiniband/sw/rxe/rxe_mw.c
@@ -72,13 +72,6 @@ static int rxe_check_bind_mw(struct rxe_qp *qp, struct rxe_send_wqe *wqe,
return -EINVAL;
}
- /* C10-72 */
- if (unlikely(qp->pd != to_rpd(mw->ibmw.pd))) {
- rxe_dbg_mw(mw,
- "attempt to bind type 2 MW with qp with different PD\n");
- return -EINVAL;
- }
-
/* o10-37.2.40 */
if (unlikely(!mr || wqe->wr.wr.mw.length == 0)) {
rxe_dbg_mw(mw,
@@ -87,10 +80,21 @@ static int rxe_check_bind_mw(struct rxe_qp *qp, struct rxe_send_wqe *wqe,
}
}
- /* remaining checks only apply to a nonzero MR */
+ /* C10-72 */
+ if (unlikely(qp->pd != rxe_mw_pd(mw))) {
+ rxe_dbg_mw(mw, "attempt to bind MW with qp with different PD\n");
+ return -EINVAL;
+ }
+
if (!mr)
return 0;
+ /* remaining checks only apply to a nonzero MR */
+ if (unlikely(qp->pd != mr_pd(mr))) {
+ rxe_dbg_mw(mw, "attempt to bind MW/QP to MR with different PD\n");
+ return -EINVAL;
+ }
+
if (unlikely(mr->access & IB_ZERO_BASED)) {
rxe_dbg_mw(mw, "attempt to bind MW to zero based MR\n");
return -EINVAL;
diff --git a/drivers/input/joystick/adc-joystick.c b/drivers/input/joystick/adc-joystick.c
index ff44f9978b71..4fa42f88bcfa 100644
--- a/drivers/input/joystick/adc-joystick.c
+++ b/drivers/input/joystick/adc-joystick.c
@@ -329,3 +329,4 @@ module_platform_driver(adc_joystick_driver);
MODULE_DESCRIPTION("Input driver for joysticks connected over ADC");
MODULE_AUTHOR("Artur Rojek <contact@artur-rojek.eu>");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/input/keyboard/adc-keys.c b/drivers/input/keyboard/adc-keys.c
index f1753207429d..d687459a0c80 100644
--- a/drivers/input/keyboard/adc-keys.c
+++ b/drivers/input/keyboard/adc-keys.c
@@ -202,3 +202,4 @@ module_platform_driver(adc_keys_driver);
MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@free-electrons.com>");
MODULE_DESCRIPTION("Input driver for resistor ladder connected on ADC");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/input/touchscreen/colibri-vf50-ts.c b/drivers/input/touchscreen/colibri-vf50-ts.c
index 98d5b2ba63fb..89c4d7b2b89e 100644
--- a/drivers/input/touchscreen/colibri-vf50-ts.c
+++ b/drivers/input/touchscreen/colibri-vf50-ts.c
@@ -372,3 +372,4 @@ module_platform_driver(vf50_touch_driver);
MODULE_AUTHOR("Sanchayan Maity");
MODULE_DESCRIPTION("Colibri VF50 Touchscreen driver");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/input/touchscreen/resistive-adc-touch.c b/drivers/input/touchscreen/resistive-adc-touch.c
index 68f7e2e28f37..c89edc1280fe 100644
--- a/drivers/input/touchscreen/resistive-adc-touch.c
+++ b/drivers/input/touchscreen/resistive-adc-touch.c
@@ -300,3 +300,4 @@ module_platform_driver(grts_driver);
MODULE_AUTHOR("Eugen Hristev <eugen.hristev@microchip.com>");
MODULE_DESCRIPTION("Generic ADC Resistive Touch Driver");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index e93bcb5eef70..c0748521dff8 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -3085,20 +3085,44 @@ static void __init free_iommu_resources(void)
free_pci_segments();
}
-/* SB IOAPIC is always on this device in AMD systems */
-#define IOAPIC_SB_DEVID ((0x00 << 8) | PCI_DEVFN(0x14, 0))
+static bool __init check_sb_ioapic(int devid)
+{
+ u8 bus = PCI_BUS_NUM(devid);
+ u8 devfn = devid & 0xff;
+ u16 val;
+
+ val = read_pci_config_16(bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
+ PCI_CLASS_DEVICE);
+
+ /*
+ * The SB IOAPIC is integrated into the FCH (Southbridge), which is
+ * exposed as an SMBus or ISA bridge in PCI config space.
+ */
+ return val == PCI_CLASS_SERIAL_SMBUS || val == PCI_CLASS_BRIDGE_ISA;
+}
-/* SB IOAPIC for Hygon family 18h model 4h is on the device 0xb */
-#define IOAPIC_SB_DEVID_FAM18H_M4H ((0x00 << 8) | PCI_DEVFN(0xb, 0))
+/*
+ * The Southbridge IOAPIC is assigned a GSI Base of 0 (handling interrupts
+ * 0 through 23).
+ */
+static int __init get_sb_ioapic_id(void)
+{
+ int idx = mp_find_ioapic(0);
+
+ if (idx < 0)
+ return -ENODEV;
+
+ return mpc_ioapic_id(idx);
+}
static bool __init check_ioapic_information(void)
{
const char *fw_bug = FW_BUG;
bool ret, has_sb_ioapic;
- int idx;
+ int idx, sb_apicid;
has_sb_ioapic = false;
- ret = false;
+ ret = true;
/*
* If we have map overrides on the kernel command line the
@@ -3108,6 +3132,16 @@ static bool __init check_ioapic_information(void)
if (cmdline_maps)
fw_bug = "";
+ sb_apicid = get_sb_ioapic_id();
+ if (sb_apicid < 0) {
+ /*
+ * Lack of SB IOAPIC registration is not a firmware bug,
+ * e.g. kernel booted with noapic or noacpi.
+ */
+ fw_bug = "";
+ goto out;
+ }
+
for (idx = 0; idx < nr_ioapics; idx++) {
int devid, id = mpc_ioapic_id(idx);
@@ -3116,17 +3150,11 @@ static bool __init check_ioapic_information(void)
pr_err("%s: IOAPIC[%d] not in IVRS table\n",
fw_bug, id);
ret = false;
- } else if (devid == IOAPIC_SB_DEVID ||
- (boot_cpu_data.x86_vendor == X86_VENDOR_HYGON &&
- boot_cpu_data.x86 == 0x18 &&
- boot_cpu_data.x86_model >= 0x4 &&
- boot_cpu_data.x86_model <= 0xf &&
- devid == IOAPIC_SB_DEVID_FAM18H_M4H)) {
+ } else if (id == sb_apicid && check_sb_ioapic(devid)) {
has_sb_ioapic = true;
- ret = true;
}
}
-
+out:
if (!has_sb_ioapic) {
/*
* We expect the SB IOAPIC to be listed in the IVRS
@@ -3137,6 +3165,7 @@ static bool __init check_ioapic_information(void)
* device id for the IOAPIC in the system.
*/
pr_err("%s: No southbridge IOAPIC found\n", fw_bug);
+ ret = false;
}
if (!ret)
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index a10affb483a4..57b750ebcd3d 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -2956,8 +2956,13 @@ static void arm_smmu_enable_ats(struct arm_smmu_master *master)
* ATC invalidation of PASID 0 causes the entire ATC to be flushed.
*/
arm_smmu_atc_inv_master(master, IOMMU_NO_PASID);
- if (pci_enable_ats(pdev, stu))
- dev_err(master->dev, "Failed to enable ATS (STU %zu)\n", stu);
+
+ /*
+ * Since pci_prepare_ats() has already verified the HW capability
+ * and programmed the STE, pci_enable_ats() should not fail here.
+ */
+ WARN(pci_enable_ats(pdev, stu),
+ "%s: Failed to enable ATS (STU %zu)\n", dev_name(master->dev), stu);
}
static int arm_smmu_enable_pasid(struct arm_smmu_master *master)
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index 849d06dfe1ae..f39451323553 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -876,8 +876,14 @@ static void iommu_enable_pci_ats(struct device_domain_info *info)
if (!pci_ats_page_aligned(pdev))
return;
- if (!pci_enable_ats(pdev, VTD_PAGE_SHIFT))
- info->ats_enabled = 1;
+ /*
+ * pci_enable_ats() should not fail here because earlier checks
+ * have already verified support and configuration.
+ */
+ if (WARN_ON(pci_enable_ats(pdev, VTD_PAGE_SHIFT)))
+ return;
+
+ info->ats_enabled = 1;
}
static void iommu_disable_pci_ats(struct device_domain_info *info)
@@ -3292,7 +3298,10 @@ static struct iommu_device *intel_iommu_probe_device(struct device *dev)
dev_iommu_priv_set(dev, info);
if (pdev && pci_ats_supported(pdev)) {
- pci_prepare_ats(pdev, VTD_PAGE_SHIFT);
+ ret = pci_prepare_ats(pdev, VTD_PAGE_SHIFT);
+ if (ret)
+ goto free;
+
ret = device_rbtree_insert(iommu, info);
if (ret)
goto free;
diff --git a/drivers/iommu/msm_iommu.c b/drivers/iommu/msm_iommu.c
index 0ad5ff431d5b..708baeb29c03 100644
--- a/drivers/iommu/msm_iommu.c
+++ b/drivers/iommu/msm_iommu.c
@@ -720,7 +720,7 @@ static int msm_iommu_probe(struct platform_device *pdev)
iommu = devm_kzalloc(&pdev->dev, sizeof(*iommu), GFP_KERNEL);
if (!iommu)
- return -ENODEV;
+ return -ENOMEM;
iommu->dev = &pdev->dev;
INIT_LIST_HEAD(&iommu->ctx_list);
diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c
index ac97dd2868d4..e907c9953142 100644
--- a/drivers/iommu/mtk_iommu_v1.c
+++ b/drivers/iommu/mtk_iommu_v1.c
@@ -88,7 +88,7 @@ struct dma_iommu_mapping {
/* MTK generation one iommu HW only support 4K size mapping */
#define MT2701_IOMMU_PAGE_SHIFT 12
#define MT2701_IOMMU_PAGE_SIZE (1UL << MT2701_IOMMU_PAGE_SHIFT)
-#define MT2701_LARB_NR_MAX 3
+#define MT2701_LARB_NR_MAX 4
/*
* MTK m4u support 4GB iova address space, and only support 4K page
diff --git a/drivers/iommu/riscv/iommu-pci.c b/drivers/iommu/riscv/iommu-pci.c
index d82d2b00904c..8abf52dfb4c9 100644
--- a/drivers/iommu/riscv/iommu-pci.c
+++ b/drivers/iommu/riscv/iommu-pci.c
@@ -109,9 +109,9 @@ static void riscv_iommu_pci_shutdown(struct pci_dev *pdev)
}
static const struct pci_device_id riscv_iommu_pci_tbl[] = {
- {PCI_VDEVICE(REDHAT, PCI_DEVICE_ID_REDHAT_RISCV_IOMMU), 0},
- {PCI_VDEVICE(RIVOS, PCI_DEVICE_ID_RIVOS_RISCV_IOMMU_GA), 0},
- {0,}
+ { PCI_VDEVICE(REDHAT, PCI_DEVICE_ID_REDHAT_RISCV_IOMMU) },
+ { PCI_VDEVICE(RIVOS, PCI_DEVICE_ID_RIVOS_RISCV_IOMMU_GA) },
+ { }
};
static struct pci_driver riscv_iommu_pci_driver = {
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 99444a1b2ffa..2673954d4577 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -2588,7 +2588,7 @@ gic_acpi_init(union acpi_subtable_headers *header, const unsigned long end)
if (err)
goto out_fwhandle_free;
- acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, gic_v3_get_gsi_domain_id);
+ acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, gic_v3_get_gsi_domain_id, NULL);
if (static_branch_likely(&supports_deactivate_key))
gic_acpi_setup_kvm_info();
diff --git a/drivers/irqchip/irq-gic-v5-iwb.c b/drivers/irqchip/irq-gic-v5-iwb.c
index 9103feb70ce8..d3433dd3f2b5 100644
--- a/drivers/irqchip/irq-gic-v5-iwb.c
+++ b/drivers/irqchip/irq-gic-v5-iwb.c
@@ -143,7 +143,7 @@ static int gicv5_iwb_irq_domain_translate(struct irq_domain *d, struct irq_fwspe
return -EINVAL;
/*
- * param[0] is be the wire
+ * param[0] is the wire
* param[1] is the interrupt type
*/
*hwirq = fwspec->param[0];
@@ -269,6 +269,8 @@ static int gicv5_iwb_device_probe(struct platform_device *pdev)
if (IS_ERR(iwb_node))
return PTR_ERR(iwb_node);
+ acpi_device_clear_deps(&pdev->dev);
+
return 0;
}
diff --git a/drivers/irqchip/irq-gic-v5.c b/drivers/irqchip/irq-gic-v5.c
index e9d1795235a6..5dcf404ab4c8 100644
--- a/drivers/irqchip/irq-gic-v5.c
+++ b/drivers/irqchip/irq-gic-v5.c
@@ -1226,11 +1226,19 @@ static struct fwnode_handle *gsi_domain_handle;
static struct fwnode_handle *gic_v5_get_gsi_domain_id(u32 gsi)
{
if (FIELD_GET(GICV5_GSI_IC_TYPE, gsi) == GICV5_GSI_IWB_TYPE)
- return iort_iwb_handle(FIELD_GET(GICV5_GSI_IWB_FRAME_ID, gsi));
+ return iort_iwb_handle_fwnode(FIELD_GET(GICV5_GSI_IWB_FRAME_ID, gsi));
return gsi_domain_handle;
}
+static acpi_handle gic_v5_get_gsi_handle(u32 gsi)
+{
+ if (FIELD_GET(GICV5_GSI_IC_TYPE, gsi) == GICV5_GSI_IWB_TYPE)
+ return iort_iwb_handle(FIELD_GET(GICV5_GSI_IWB_FRAME_ID, gsi));
+
+ return NULL;
+}
+
static int __init gic_acpi_init(union acpi_subtable_headers *header, const unsigned long end)
{
struct acpi_madt_gicv5_irs *irs = (struct acpi_madt_gicv5_irs *)header;
@@ -1251,7 +1259,8 @@ static int __init gic_acpi_init(union acpi_subtable_headers *header, const unsig
if (ret)
goto out_irs;
- acpi_set_irq_model(ACPI_IRQ_MODEL_GIC_V5, gic_v5_get_gsi_domain_id);
+ acpi_set_irq_model(ACPI_IRQ_MODEL_GIC_V5, gic_v5_get_gsi_domain_id,
+ gic_v5_get_gsi_handle);
return 0;
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index ec70c84e9f91..f6bc29f515fb 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -1690,7 +1690,7 @@ static int __init gic_v2_acpi_init(union acpi_subtable_headers *header,
return ret;
}
- acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, gic_v2_get_gsi_domain_id);
+ acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, gic_v2_get_gsi_domain_id, NULL);
if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
gicv2m_init(NULL, gic_data[0].domain);
diff --git a/drivers/irqchip/irq-loongarch-cpu.c b/drivers/irqchip/irq-loongarch-cpu.c
index 950bc087e388..84ce24889488 100644
--- a/drivers/irqchip/irq-loongarch-cpu.c
+++ b/drivers/irqchip/irq-loongarch-cpu.c
@@ -168,7 +168,7 @@ static int __init cpuintc_acpi_init(union acpi_subtable_headers *header,
panic("Failed to add irqdomain for LoongArch CPU");
set_handle_irq(&handle_cpu_irq);
- acpi_set_irq_model(ACPI_IRQ_MODEL_LPIC, lpic_get_gsi_domain_id);
+ acpi_set_irq_model(ACPI_IRQ_MODEL_LPIC, lpic_get_gsi_domain_id, NULL);
acpi_set_gsi_to_irq_fallback(lpic_gsi_to_irq);
ret = acpi_cascade_irqdomain_init();
diff --git a/drivers/irqchip/irq-riscv-intc.c b/drivers/irqchip/irq-riscv-intc.c
index 84418dbd5a27..0595144116e2 100644
--- a/drivers/irqchip/irq-riscv-intc.c
+++ b/drivers/irqchip/irq-riscv-intc.c
@@ -384,7 +384,8 @@ static int __init riscv_intc_acpi_init(union acpi_subtable_headers *header,
if (rc)
irq_domain_free_fwnode(fn);
else
- acpi_set_irq_model(ACPI_IRQ_MODEL_RINTC, riscv_acpi_get_gsi_domain_id);
+ acpi_set_irq_model(ACPI_IRQ_MODEL_RINTC, riscv_acpi_get_gsi_domain_id,
+ acpi_get_riscv_gsi_handle);
return rc;
}
diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c
index f38ee74b0397..ce6d80c7f17a 100644
--- a/drivers/irqchip/qcom-pdc.c
+++ b/drivers/irqchip/qcom-pdc.c
@@ -426,7 +426,7 @@ static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type)
}
/**
- * qcom_pdc_gic_set_type: Configure PDC for the interrupt
+ * qcom_pdc_gic_secondary_set_type: Configure PDC for the interrupt in secondary mode
*
* @d: the interrupt data
* @type: the interrupt type
diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c
index f3bf59495b68..2d37e00e459d 100644
--- a/drivers/leds/leds-pca9532.c
+++ b/drivers/leds/leds-pca9532.c
@@ -327,9 +327,9 @@ static int pca9532_gpio_set_value(struct gpio_chip *gc, unsigned int offset,
struct pca9532_led *led = &data->leds[offset];
if (val)
- led->state = PCA9532_ON;
- else
led->state = PCA9532_OFF;
+ else
+ led->state = PCA9532_ON;
pca9532_setled(led);
@@ -349,7 +349,7 @@ static int pca9532_gpio_get_value(struct gpio_chip *gc, unsigned offset)
static int pca9532_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
{
/* To use as input ensure pin is not driven */
- pca9532_gpio_set_value(gc, offset, 0);
+ pca9532_gpio_set_value(gc, offset, 1);
return 0;
}
diff --git a/drivers/leds/leds-st1202.c b/drivers/leds/leds-st1202.c
index 7f68d956f694..168df5ecf27b 100644
--- a/drivers/leds/leds-st1202.c
+++ b/drivers/leds/leds-st1202.c
@@ -31,10 +31,11 @@
#define ST1202_ILED_REG0 0x09
#define ST1202_MAX_LEDS 12
#define ST1202_MAX_PATTERNS 8
-#define ST1202_MILLIS_PATTERN_DUR_MAX 5660
+#define ST1202_MILLIS_PATTERN_DUR_MAX (ST1202_MILLIS_PATTERN_DUR_MIN * U8_MAX)
#define ST1202_MILLIS_PATTERN_DUR_MIN 22
#define ST1202_PATTERN_DUR 0x16
#define ST1202_PATTERN_PWM 0x1E
+#define ST1202_PATTERN_PWM_FULL 0x0FFF
#define ST1202_PATTERN_REP 0x15
struct st1202_led {
@@ -85,7 +86,7 @@ static int st1202_write_reg(struct st1202_chip *chip, int reg, uint8_t val)
static uint8_t st1202_prescalar_to_miliseconds(unsigned int value)
{
- return value / ST1202_MILLIS_PATTERN_DUR_MIN - 1;
+ return value / ST1202_MILLIS_PATTERN_DUR_MIN;
}
static int st1202_pwm_pattern_write(struct st1202_chip *chip, int led_num,
@@ -127,37 +128,11 @@ static int st1202_duration_pattern_write(struct st1202_chip *chip, int pattern,
st1202_prescalar_to_miliseconds(value));
}
-static void st1202_brightness_set(struct led_classdev *led_cdev,
- enum led_brightness value)
-{
- struct st1202_led *led = cdev_to_st1202_led(led_cdev);
- struct st1202_chip *chip = led->chip;
-
- guard(mutex)(&chip->lock);
-
- st1202_write_reg(chip, ST1202_ILED_REG0 + led->led_num, value);
-}
-
-static enum led_brightness st1202_brightness_get(struct led_classdev *led_cdev)
-{
- struct st1202_led *led = cdev_to_st1202_led(led_cdev);
- struct st1202_chip *chip = led->chip;
- u8 value = 0;
-
- guard(mutex)(&chip->lock);
-
- st1202_read_reg(chip, ST1202_ILED_REG0 + led->led_num, &value);
-
- return value;
-}
-
-static int st1202_channel_set(struct st1202_chip *chip, int led_num, bool active)
+static int __st1202_channel_set(struct st1202_chip *chip, int led_num, bool active)
{
u8 chan_low, chan_high;
int ret;
- guard(mutex)(&chip->lock);
-
if (led_num <= 7) {
ret = st1202_read_reg(chip, ST1202_CHAN_ENABLE_LOW, &chan_low);
if (ret < 0)
@@ -185,6 +160,40 @@ static int st1202_channel_set(struct st1202_chip *chip, int led_num, bool active
return 0;
}
+static int st1202_channel_set(struct st1202_chip *chip, int led_num, bool active)
+{
+ guard(mutex)(&chip->lock);
+
+ return __st1202_channel_set(chip, led_num, active);
+}
+
+static void st1202_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ struct st1202_led *led = cdev_to_st1202_led(led_cdev);
+ struct st1202_chip *chip = led->chip;
+
+ guard(mutex)(&chip->lock);
+
+ for (int patt = 0; patt < ST1202_MAX_PATTERNS; patt++)
+ st1202_pwm_pattern_write(chip, led->led_num, patt, ST1202_PATTERN_PWM_FULL);
+ st1202_write_reg(chip, ST1202_ILED_REG0 + led->led_num, value);
+ __st1202_channel_set(chip, led->led_num, !!value);
+}
+
+static enum led_brightness st1202_brightness_get(struct led_classdev *led_cdev)
+{
+ struct st1202_led *led = cdev_to_st1202_led(led_cdev);
+ struct st1202_chip *chip = led->chip;
+ u8 value = 0;
+
+ guard(mutex)(&chip->lock);
+
+ st1202_read_reg(chip, ST1202_ILED_REG0 + led->led_num, &value);
+
+ return value;
+}
+
static int st1202_led_set(struct led_classdev *ldev, enum led_brightness value)
{
struct st1202_led *led = cdev_to_st1202_led(ldev);
@@ -200,12 +209,16 @@ static int st1202_led_pattern_clear(struct led_classdev *ldev)
guard(mutex)(&chip->lock);
+ ret = st1202_write_reg(chip, ST1202_CONFIG_REG, ST1202_CONFIG_REG_SHFT);
+ if (ret != 0)
+ return ret;
+
for (int patt = 0; patt < ST1202_MAX_PATTERNS; patt++) {
- ret = st1202_pwm_pattern_write(chip, led->led_num, patt, LED_OFF);
+ ret = st1202_pwm_pattern_write(chip, led->led_num, patt, ST1202_PATTERN_PWM_FULL);
if (ret != 0)
return ret;
- ret = st1202_duration_pattern_write(chip, patt, ST1202_MILLIS_PATTERN_DUR_MIN);
+ ret = st1202_write_reg(chip, ST1202_PATTERN_DUR + patt, 0);
if (ret != 0)
return ret;
}
@@ -224,13 +237,19 @@ static int st1202_led_pattern_set(struct led_classdev *ldev,
if (len > ST1202_MAX_PATTERNS)
return -EINVAL;
- guard(mutex)(&chip->lock);
-
for (int patt = 0; patt < len; patt++) {
if (pattern[patt].delta_t < ST1202_MILLIS_PATTERN_DUR_MIN ||
pattern[patt].delta_t > ST1202_MILLIS_PATTERN_DUR_MAX)
return -EINVAL;
+ }
+ guard(mutex)(&chip->lock);
+
+ ret = st1202_write_reg(chip, ST1202_CONFIG_REG, ST1202_CONFIG_REG_SHFT);
+ if (ret != 0)
+ return ret;
+
+ for (int patt = 0; patt < len; patt++) {
ret = st1202_pwm_pattern_write(chip, led->led_num, patt, pattern[patt].brightness);
if (ret != 0)
return ret;
@@ -244,6 +263,10 @@ static int st1202_led_pattern_set(struct led_classdev *ldev,
if (ret != 0)
return ret;
+ ret = __st1202_channel_set(chip, led->led_num, true);
+ if (ret != 0)
+ return ret;
+
ret = st1202_write_reg(chip, ST1202_CONFIG_REG, (ST1202_CONFIG_REG_PATSR |
ST1202_CONFIG_REG_PATS | ST1202_CONFIG_REG_SHFT));
if (ret != 0)
@@ -256,13 +279,19 @@ static int st1202_dt_init(struct st1202_chip *chip)
{
struct device *dev = &chip->client->dev;
struct st1202_led *led;
- int err, reg;
+ int err;
+ u32 reg;
for_each_available_child_of_node_scoped(dev_of_node(dev), child) {
err = of_property_read_u32(child, "reg", &reg);
if (err)
return dev_err_probe(dev, err, "Invalid register\n");
+ if (reg >= ST1202_MAX_LEDS)
+ return dev_err_probe(dev, -EINVAL,
+ "LED reg %u out of range [0, %d]\n",
+ reg, ST1202_MAX_LEDS - 1);
+
led = &chip->leds[reg];
led->is_active = true;
led->fwnode = of_fwnode_handle(child);
@@ -322,11 +351,6 @@ static int st1202_setup(struct st1202_chip *chip)
if (ret < 0)
return ret;
- ret = st1202_write_reg(chip, ST1202_CONFIG_REG,
- ST1202_CONFIG_REG_PATS | ST1202_CONFIG_REG_PATSR);
- if (ret < 0)
- return ret;
-
return 0;
}
diff --git a/drivers/leds/rgb/leds-lp5860-core.c b/drivers/leds/rgb/leds-lp5860-core.c
index fd0e2f6e6e0f..e21d5f2302be 100644
--- a/drivers/leds/rgb/leds-lp5860-core.c
+++ b/drivers/leds/rgb/leds-lp5860-core.c
@@ -204,9 +204,9 @@ int lp5860_device_init(struct device *dev)
mutex_lock(&lp->lock);
ret = regmap_update_bits(lp->regmap, LP5860_REG_DEV_INITIAL, LP5860_MODE_MASK,
LP5860_MODE_1 << LP5860_MODE_SHIFT);
+ mutex_unlock(&lp->lock);
if (ret)
goto err_disable;
- mutex_unlock(&lp->lock);
ret = lp5860_init_dt(lp);
if (ret)
@@ -215,7 +215,6 @@ int lp5860_device_init(struct device *dev)
return 0;
err_disable:
- mutex_unlock(&lp->lock);
lp5860_chip_enable(lp, LP5860_CHIP_DISABLE);
return ret;
}
diff --git a/drivers/leds/rgb/leds-lp5860-spi.c b/drivers/leds/rgb/leds-lp5860-spi.c
index 5e0c44854a68..6bf6a625c28a 100644
--- a/drivers/leds/rgb/leds-lp5860-spi.c
+++ b/drivers/leds/rgb/leds-lp5860-spi.c
@@ -38,6 +38,7 @@ static int lp5860_probe(struct spi_device *spi)
struct device *dev = &spi->dev;
struct lp5860 *lp5860;
unsigned int multi_leds;
+ int ret;
multi_leds = device_get_child_node_count(dev);
if (!multi_leds) {
@@ -61,7 +62,10 @@ static int lp5860_probe(struct spi_device *spi)
"Failed to initialise Regmap.\n");
lp5860->dev = dev;
- mutex_init(&lp5860->lock);
+
+ ret = devm_mutex_init(dev, &lp5860->lock);
+ if (ret)
+ return ret;
spi_set_drvdata(spi, lp5860);
@@ -70,10 +74,6 @@ static int lp5860_probe(struct spi_device *spi)
static void lp5860_remove(struct spi_device *spi)
{
- struct lp5860 *lp5860 = spi_get_drvdata(spi);
-
- mutex_destroy(&lp5860->lock);
-
lp5860_device_remove(&spi->dev);
}
diff --git a/drivers/media/cec/core/cec-adap.c b/drivers/media/cec/core/cec-adap.c
index 829ee4861bf7..de0c4fcd8dfe 100644
--- a/drivers/media/cec/core/cec-adap.c
+++ b/drivers/media/cec/core/cec-adap.c
@@ -2219,9 +2219,13 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg,
* Unprocessed messages are aborted if userspace isn't doing
* any processing either.
*/
+ mutex_lock(&adap->lock);
if (!is_broadcast && !is_reply && !adap->follower_cnt &&
- !adap->cec_follower && msg->msg[1] != CEC_MSG_FEATURE_ABORT)
+ !adap->cec_follower && msg->msg[1] != CEC_MSG_FEATURE_ABORT) {
+ mutex_unlock(&adap->lock);
return cec_feature_abort(adap, msg);
+ }
+ mutex_unlock(&adap->lock);
break;
}
@@ -2234,10 +2238,12 @@ skip_processing:
* Send to the exclusive follower if there is one, otherwise send
* to all followers.
*/
+ mutex_lock(&adap->lock);
if (adap->cec_follower)
cec_queue_msg_fh(adap->cec_follower, msg);
else
cec_queue_msg_followers(adap, msg);
+ mutex_unlock(&adap->lock);
return 0;
}
diff --git a/drivers/media/cec/core/cec-core.c b/drivers/media/cec/core/cec-core.c
index 90a98f322f5e..c51e769b4e34 100644
--- a/drivers/media/cec/core/cec-core.c
+++ b/drivers/media/cec/core/cec-core.c
@@ -5,16 +5,33 @@
* Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/bitops.h>
+#include <linux/bug.h>
+#include <linux/cdev.h>
+#include <linux/container_of.h>
#include <linux/debugfs.h>
-#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/fs.h>
#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/kmod.h>
-#include <linux/mm.h>
+#include <linux/kobject.h>
+#include <linux/kthread.h>
+#include <linux/list.h>
+#include <linux/minmax.h>
#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/printk.h>
+#include <linux/seq_file.h>
#include <linux/slab.h>
+#include <linux/sprintf.h>
#include <linux/string.h>
+#include <linux/time.h>
#include <linux/types.h>
+#include <linux/wait.h>
+
+#include <asm/page.h>
#include "cec-priv.h"
@@ -93,7 +110,7 @@ static int __must_check cec_devnode_register(struct cec_devnode *devnode,
minor = find_first_zero_bit(cec_devnode_nums, CEC_NUM_DEVICES);
if (minor == CEC_NUM_DEVICES) {
mutex_unlock(&cec_devnode_lock);
- pr_err("could not get a free minor\n");
+ pr_err("Could not get a free minor\n");
return -ENFILE;
}
@@ -104,19 +121,19 @@ static int __must_check cec_devnode_register(struct cec_devnode *devnode,
devnode->dev.bus = &cec_bus_type;
devnode->dev.devt = MKDEV(MAJOR(cec_dev_t), minor);
devnode->dev.release = cec_devnode_release;
- dev_set_name(&devnode->dev, "cec%d", devnode->minor);
+ dev_set_name(&devnode->dev, "%s%d", CEC_NAME, devnode->minor);
device_initialize(&devnode->dev);
/* Part 2: Initialize and register the character device */
cdev_init(&devnode->cdev, &cec_devnode_fops);
devnode->cdev.owner = owner;
- kobject_set_name(&devnode->cdev.kobj, "cec%d", devnode->minor);
+ kobject_set_name(&devnode->cdev.kobj, "%s%d", CEC_NAME, devnode->minor);
devnode->registered = true;
ret = cdev_device_add(&devnode->cdev, &devnode->dev);
if (ret) {
devnode->registered = false;
- pr_err("%s: cdev_device_add failed\n", __func__);
+ pr_err("cdev_device_add() failed\n");
goto clr_bit;
}
@@ -205,19 +222,7 @@ static int cec_error_inj_show(struct seq_file *sf, void *unused)
return call_op(adap, error_inj_show, sf);
}
-
-static int cec_error_inj_open(struct inode *inode, struct file *file)
-{
- return single_open(file, cec_error_inj_show, inode->i_private);
-}
-
-static const struct file_operations cec_error_inj_fops = {
- .open = cec_error_inj_open,
- .write = cec_error_inj_write,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_STORE_ATTRIBUTE(cec_error_inj);
#endif
struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
@@ -263,12 +268,11 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
mutex_init(&adap->devnode.lock_fhs);
mutex_init(&adap->devnode.lock);
- adap->kthread = kthread_run(cec_thread_func, adap, "cec-%s", name);
+ adap->kthread = kthread_run(cec_thread_func, adap, "%s-%s", CEC_NAME, name);
if (IS_ERR(adap->kthread)) {
- pr_err("cec-%s: kernel_thread() failed\n", name);
+ pr_err("%s: kthread_run() failed\n", name);
res = PTR_ERR(adap->kthread);
- kfree(adap);
- return ERR_PTR(res);
+ goto err_free_adap;
}
#ifdef CONFIG_MEDIA_CEC_RC
@@ -278,11 +282,10 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
/* Prepare the RC input device */
adap->rc = rc_allocate_device(RC_DRIVER_SCANCODE);
if (!adap->rc) {
- pr_err("cec-%s: failed to allocate memory for rc_dev\n",
- name);
+ pr_err("%s: failed to allocate memory for rc_dev\n", name);
kthread_stop(adap->kthread);
- kfree(adap);
- return ERR_PTR(-ENOMEM);
+ res = -ENOMEM;
+ goto err_free_adap;
}
snprintf(adap->input_phys, sizeof(adap->input_phys),
@@ -298,9 +301,18 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
adap->rc->allowed_protocols = RC_PROTO_BIT_CEC;
adap->rc->priv = adap;
adap->rc->map_name = RC_MAP_CEC;
- adap->rc->timeout = MS_TO_US(550);
+ adap->rc->timeout = 550 * USEC_PER_MSEC;
#endif
return adap;
+
+err_free_adap:
+ mutex_destroy(&adap->devnode.lock);
+ mutex_destroy(&adap->devnode.lock_fhs);
+
+ mutex_destroy(&adap->lock);
+
+ kfree(adap);
+ return ERR_PTR(res);
}
EXPORT_SYMBOL_GPL(cec_allocate_adapter);
@@ -326,8 +338,7 @@ int cec_register_adapter(struct cec_adapter *adap,
res = rc_register_device(adap->rc);
if (res) {
- pr_err("cec-%s: failed to prepare input device\n",
- adap->name);
+ pr_err("%s: failed to prepare input device\n", adap->name);
rc_free_device(adap->rc);
adap->rc = NULL;
return res;
@@ -385,14 +396,23 @@ void cec_delete_adapter(struct cec_adapter *adap)
{
if (IS_ERR_OR_NULL(adap))
return;
+
if (adap->kthread_config)
kthread_stop(adap->kthread_config);
kthread_stop(adap->kthread);
+
if (adap->ops->adap_free)
adap->ops->adap_free(adap);
+
#ifdef CONFIG_MEDIA_CEC_RC
rc_free_device(adap->rc);
#endif
+
+ mutex_destroy(&adap->devnode.lock);
+ mutex_destroy(&adap->devnode.lock_fhs);
+
+ mutex_destroy(&adap->lock);
+
kfree(adap);
}
EXPORT_SYMBOL_GPL(cec_delete_adapter);
@@ -405,14 +425,14 @@ static int __init cec_devnode_init(void)
int ret = alloc_chrdev_region(&cec_dev_t, 0, CEC_NUM_DEVICES, CEC_NAME);
if (ret < 0) {
- pr_warn("cec: unable to allocate major\n");
+ pr_warn("Unable to allocate major\n");
return ret;
}
#ifdef CONFIG_DEBUG_FS
- top_cec_dir = debugfs_create_dir("cec", NULL);
+ top_cec_dir = debugfs_create_dir(CEC_NAME, NULL);
if (IS_ERR_OR_NULL(top_cec_dir)) {
- pr_warn("cec: Failed to create debugfs cec dir\n");
+ pr_warn("Failed to create debugfs " CEC_NAME " dir\n");
top_cec_dir = NULL;
}
#endif
@@ -421,7 +441,7 @@ static int __init cec_devnode_init(void)
if (ret < 0) {
debugfs_remove_recursive(top_cec_dir);
unregister_chrdev_region(cec_dev_t, CEC_NUM_DEVICES);
- pr_warn("cec: bus_register failed\n");
+ pr_warn("bus_register() failed\n");
return -EIO;
}
diff --git a/drivers/media/cec/platform/seco/seco-cec.c b/drivers/media/cec/platform/seco/seco-cec.c
index 97ed9654c78a..654c70503dd5 100644
--- a/drivers/media/cec/platform/seco/seco-cec.c
+++ b/drivers/media/cec/platform/seco/seco-cec.c
@@ -7,14 +7,15 @@
* Copyright (C) 2018, Aidilab Srl.
*/
-#include <linux/module.h>
#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
+#include <linux/time.h>
/* CEC Framework */
#include <media/cec-notifier.h>
@@ -356,7 +357,7 @@ static int secocec_ir_probe(void *priv)
cec->ir->allowed_protocols = RC_PROTO_BIT_RC5;
cec->ir->priv = cec;
cec->ir->map_name = RC_MAP_HAUPPAUGE;
- cec->ir->timeout = MS_TO_US(100);
+ cec->ir->timeout = 100 * USEC_PER_MSEC;
/* Clear the status register */
status = smb_rd16(SECOCEC_STATUS_REG_1, &val);
diff --git a/drivers/media/cec/platform/tegra/tegra_cec.c b/drivers/media/cec/platform/tegra/tegra_cec.c
index 3ed50097262f..fe66336e734f 100644
--- a/drivers/media/cec/platform/tegra/tegra_cec.c
+++ b/drivers/media/cec/platform/tegra/tegra_cec.c
@@ -458,6 +458,7 @@ static const struct of_device_id tegra_cec_of_match[] = {
{ .compatible = "nvidia,tegra210-cec", },
{},
};
+MODULE_DEVICE_TABLE(of, tegra_cec_of_match);
static struct platform_driver tegra_cec_driver = {
.driver = {
diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c
index 931e5dc453b9..e1d5c220f738 100644
--- a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c
+++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c
@@ -2346,9 +2346,11 @@ static void tpg_fill_params_extras(const struct tpg_data *tpg,
(params->is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
}
-static void tpg_fill_plane_extras(const struct tpg_data *tpg,
- const struct tpg_draw_params *params,
- unsigned p, unsigned h, u8 *vbuf)
+/* noinline to work around clang KASAN issues */
+static noinline_for_stack void
+tpg_fill_plane_extras(const struct tpg_data *tpg,
+ const struct tpg_draw_params *params,
+ unsigned p, unsigned h, u8 *vbuf)
{
unsigned twopixsize = params->twopixsize;
unsigned img_width = params->img_width;
@@ -2483,9 +2485,9 @@ static void tpg_fill_plane_extras(const struct tpg_data *tpg,
}
}
-static void tpg_fill_plane_pattern(const struct tpg_data *tpg,
- const struct tpg_draw_params *params,
- unsigned p, unsigned h, u8 *vbuf)
+static noinline_for_stack void
+tpg_fill_plane_pattern(const struct tpg_data *tpg, const struct tpg_draw_params *params,
+ unsigned p, unsigned h, u8 *vbuf)
{
unsigned twopixsize = params->twopixsize;
unsigned img_width = params->img_width;
diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c
index c564485e3bbb..0330e7f0881a 100644
--- a/drivers/media/dvb-frontends/rtl2832_sdr.c
+++ b/drivers/media/dvb-frontends/rtl2832_sdr.c
@@ -906,9 +906,12 @@ static int rtl2832_sdr_start_streaming(struct vb2_queue *vq, unsigned int count)
goto err;
mutex_unlock(&dev->v4l2_lock);
+
return 0;
err:
+ rtl2832_sdr_free_urbs(dev);
+ rtl2832_sdr_free_stream_bufs(dev);
rtl2832_sdr_cleanup_queued_bufs(dev, VB2_BUF_STATE_QUEUED);
mutex_unlock(&dev->v4l2_lock);
@@ -1477,14 +1480,22 @@ static void rtl2832_sdr_remove(struct platform_device *pdev)
dev_dbg(&pdev->dev, "\n");
- mutex_lock(&dev->vb_queue_lock);
+ /*
+ * vb2_video_unregister_device() releases the vb2 queue, which
+ * triggers rtl2832_sdr_stop_streaming() if streaming is active.
+ * stop_streaming() uses dev->udev to free URBs and coherent DMA
+ * stream buffers via usb_free_coherent(), so it must run before
+ * dev->udev is cleared. vb2_video_unregister_device() locks
+ * vb_queue_lock internally and stop_streaming() locks v4l2_lock,
+ * so neither may be held by the caller.
+ */
+ v4l2_device_disconnect(&dev->v4l2_dev);
+ vb2_video_unregister_device(&dev->vdev);
+
mutex_lock(&dev->v4l2_lock);
- /* No need to keep the urbs around after disconnection */
dev->udev = NULL;
- v4l2_device_disconnect(&dev->v4l2_dev);
- video_unregister_device(&dev->vdev);
mutex_unlock(&dev->v4l2_lock);
- mutex_unlock(&dev->vb_queue_lock);
+
v4l2_device_put(&dev->v4l2_dev);
module_put(pdev->dev.parent->driver->owner);
}
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 5d173e0ecf42..7ffccba897ae 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -287,6 +287,27 @@ config VIDEO_IMX415
To compile this driver as a module, choose M here: the
module will be called imx415.
+config VIDEO_IMX471
+ tristate "Sony IMX471 sensor support"
+ select V4L2_CCI_I2C
+ help
+ This is a Video4Linux2 sensor driver for the Sony
+ IMX471 camera.
+
+ To compile this driver as a module, choose M here: the
+ module will be called imx471.
+
+config VIDEO_IMX678
+ tristate "Sony IMX678 sensor support"
+ depends on GPIOLIB
+ select V4L2_CCI_I2C
+ help
+ This is a Video4Linux2 sensor driver for the Sony
+ IMX678 camera.
+
+ To compile this driver as a module, choose M here: the
+ module will be called imx678.
+
config VIDEO_MAX9271_LIB
tristate
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index e45359efe0e4..d04bd5724552 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -61,6 +61,8 @@ obj-$(CONFIG_VIDEO_IMX335) += imx335.o
obj-$(CONFIG_VIDEO_IMX355) += imx355.o
obj-$(CONFIG_VIDEO_IMX412) += imx412.o
obj-$(CONFIG_VIDEO_IMX415) += imx415.o
+obj-$(CONFIG_VIDEO_IMX678) += imx678.o
+obj-$(CONFIG_VIDEO_IMX471) += imx471.o
obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
obj-$(CONFIG_VIDEO_ISL7998X) += isl7998x.o
obj-$(CONFIG_VIDEO_KS0127) += ks0127.o
diff --git a/drivers/media/i2c/alvium-csi2.c b/drivers/media/i2c/alvium-csi2.c
index dd991c2ee700..f51f9b987759 100644
--- a/drivers/media/i2c/alvium-csi2.c
+++ b/drivers/media/i2c/alvium-csi2.c
@@ -1290,7 +1290,7 @@ static int alvium_set_ctrl_auto_exposure(struct alvium_dev *alvium, bool on)
struct device *dev = &alvium->i2c_client->dev;
int ret;
- ret = alvium_write_hshake(alvium, REG_BCRM_WHITE_BALANCE_AUTO_RW,
+ ret = alvium_write_hshake(alvium, REG_BCRM_EXPOSURE_AUTO_RW,
on ? 0x02 : 0x00);
if (ret) {
dev_err(dev, "Fail to set autoexposure reg\n");
diff --git a/drivers/media/i2c/cvs/core.c b/drivers/media/i2c/cvs/core.c
index fe9e59ac311c..d4a3b9c3bab1 100644
--- a/drivers/media/i2c/cvs/core.c
+++ b/drivers/media/i2c/cvs/core.c
@@ -31,6 +31,7 @@
#define PCI_DEVICE_ID_INTEL_IPU7 0x645d /* MTL / LNL */
#define PCI_DEVICE_ID_INTEL_IPU7P5 0xb05d /* ARL / PTL */
+#define PCI_DEVICE_ID_INTEL_IPU8 0xd719 /* NVL */
/*
* IPU7 PCI device IDs not covered by ipu6_pci_tbl in ipu6-pci-table.h.
@@ -39,6 +40,7 @@
static const struct pci_device_id icvs_ipu7_tbl[] = {
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IPU7) },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IPU7P5) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IPU8) },
{ }
};
@@ -962,6 +964,7 @@ static const struct acpi_device_id intel_cvs_acpi_match[] = {
{ "INTC10DE" }, /* LNL */
{ "INTC10E0" }, /* ARL */
{ "INTC10E1" }, /* PTL */
+ { "INTC10FA" }, /* NVL */
{ }
};
MODULE_DEVICE_TABLE(acpi, intel_cvs_acpi_match);
diff --git a/drivers/media/i2c/imx471.c b/drivers/media/i2c/imx471.c
new file mode 100644
index 000000000000..6d358b11e96d
--- /dev/null
+++ b/drivers/media/i2c/imx471.c
@@ -0,0 +1,957 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * imx471.c - imx471 sensor driver
+ *
+ * Copyright (C) 2025 Intel Corporation
+ * Copyright (C) 2026 Kate Hsuan <hpa@redhat.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <media/v4l2-cci.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-fwnode.h>
+
+#define IMX471_REG_MODE_SELECT CCI_REG8(0x0100)
+#define IMX471_MODE_STANDBY 0x00
+#define IMX471_MODE_STREAMING 0x01
+
+/* Chip ID */
+#define IMX471_REG_CHIP_ID CCI_REG16(0x0016)
+#define IMX471_CHIP_ID 0x0471
+
+/* V_TIMING internal */
+#define IMX471_REG_FLL CCI_REG16(0x0340)
+#define IMX471_FLL_MAX 0xffff
+
+/* Exposure control */
+#define IMX471_REG_EXPOSURE CCI_REG16(0x0202)
+#define IMX471_EXPOSURE_MIN 1
+#define IMX471_EXPOSURE_STEP 1
+#define IMX471_EXPOSURE_DEFAULT 1270
+
+/* Default exposure margin */
+#define IMX471_EXPOSURE_MARGIN 18
+
+/* Analog gain control */
+#define IMX471_REG_ANALOG_GAIN CCI_REG16(0x0204)
+#define IMX471_ANA_GAIN_MIN 0
+#define IMX471_ANA_GAIN_MAX 800
+#define IMX471_ANA_GAIN_STEP 1
+#define IMX471_ANA_GAIN_DEFAULT 0
+
+/* Digital gain control */
+#define IMX471_REG_DPGA_USE_GLOBAL_GAIN CCI_REG16(0x3ff9)
+#define IMX471_REG_DIG_GAIN_GLOBAL CCI_REG16(0x020e)
+#define IMX471_DGTL_GAIN_MIN 256
+#define IMX471_DGTL_GAIN_MAX 4095
+#define IMX471_DGTL_GAIN_STEP 1
+#define IMX471_DGTL_GAIN_DEFAULT 256
+
+/* HFLIP and VFLIP control */
+#define IMX471_REG_ORIENTATION CCI_REG8(0x0101)
+
+/* Test Pattern Control */
+#define IMX471_REG_TEST_PATTERN CCI_REG8(0x0600)
+
+/* default link frequency and external clock */
+#define IMX471_LINK_FREQ_DEFAULT 200000000LL
+#define IMX471_EXT_CLK 19200000
+
+/* PLL */
+#define IMX471_REG_VTPXCK_DIV CCI_REG8(0x0301)
+#define IMX471_REG_VTSYCK_DIV CCI_REG8(0x0303)
+#define IMX471_REG_PREPLLCK_VT_DIV CCI_REG8(0x0305)
+#define IMX471_REG_PLL_VT_MPY CCI_REG16(0x0306)
+#define IMX471_REG_OPPXCK_DIV CCI_REG8(0x0309)
+#define IMX471_REG_OPSYCK_DIV CCI_REG8(0x030b)
+#define IMX471_REG_PLL_MULT_DRIV CCI_REG8(0x0310)
+#define IMX471_PLL_SINGLE 0
+#define IMX471_PLL_DUAL 1
+
+/* IMX471 native and active pixel array size */
+#define IMX471_NATIVE_WIDTH 4672
+#define IMX471_NATIVE_HEIGHT 3512
+#define IMX471_PIXEL_ARRAY_LEFT 8
+#define IMX471_PIXEL_ARRAY_TOP 8
+#define IMX471_PIXEL_ARRAY_WIDTH 4656
+#define IMX471_PIXEL_ARRAY_HEIGHT 3496
+
+#define IMX471_REG_EXCK_FREQ CCI_REG16(0x0136)
+
+#define IMX471_REG_CSI_DATA_FORMAT CCI_REG16(0x0112)
+#define IMX471_CSI_DATA_FORMAT_RAW10 0x0a0a
+
+#define IMX471_REG_CSI_LANE_MODE CCI_REG8(0x0114)
+#define IMX471_CSI_2_LANE_MODE 1
+#define IMX471_CSI_4_LANE_MODE 3
+
+#define IMX471_REG_X_ADD_STA CCI_REG16(0x0344)
+#define IMX471_REG_Y_ADD_STA CCI_REG16(0x0346)
+#define IMX471_REG_X_ADD_END CCI_REG16(0x0348)
+#define IMX471_REG_Y_ADD_END CCI_REG16(0x034a)
+#define IMX471_REG_X_OUTPUT_SIZE CCI_REG16(0x034c)
+#define IMX471_REG_Y_OUTPUT_SIZE CCI_REG16(0x034e)
+#define IMX471_REG_X_EVEN_INC CCI_REG8(0x0381)
+#define IMX471_REG_X_ODD_INC CCI_REG8(0x0383)
+#define IMX471_REG_Y_EVEN_INC CCI_REG8(0x0385)
+#define IMX471_REG_Y_ODD_INC CCI_REG8(0x0387)
+
+#define IMX471_REG_DIG_CROP_X_OFFSET CCI_REG16(0x0408)
+#define IMX471_REG_DIG_CROP_Y_OFFSET CCI_REG16(0x040a)
+#define IMX471_REG_DIG_CROP_WIDTH CCI_REG16(0x040c)
+#define IMX471_REG_DIG_CROP_HEIGHT CCI_REG16(0x040e)
+
+/* Binning mode */
+#define IMX471_REG_BINNING_MODE CCI_REG8(0x0900)
+#define IMX471_BINNING_NONE 0
+#define IMX471_BINNING_ENABLE 1
+#define IMX471_REG_BINNING_TYPE CCI_REG8(0x0901)
+#define IMX471_REG_BINNING_WEIGHTING CCI_REG8(0x0902)
+
+#define to_imx471(_sd) container_of_const(_sd, struct imx471, sd)
+
+static const char * const imx471_supply_name[] = {
+ "vana",
+};
+
+struct imx471_mode {
+ u32 width;
+ u32 height;
+
+ /* V-timing */
+ u32 fll_def;
+ u32 fll_min;
+
+ /* H-timing */
+ u32 llp;
+
+ const struct cci_reg_sequence *default_mode_regs;
+ unsigned int default_mode_regs_length;
+};
+
+struct imx471 {
+ struct v4l2_subdev sd;
+ struct media_pad pad;
+
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct v4l2_ctrl *vblank;
+ struct v4l2_ctrl *hblank;
+ struct v4l2_ctrl *vflip;
+ struct v4l2_ctrl *hflip;
+ struct v4l2_ctrl *exposure;
+
+ struct gpio_desc *reset_gpio;
+ struct regulator_bulk_data supplies[ARRAY_SIZE(imx471_supply_name)];
+ struct clk *img_clk;
+
+ struct device *dev;
+ struct regmap *regmap;
+};
+
+static const struct cci_reg_sequence imx471_global_regs[] = {
+ { IMX471_REG_EXCK_FREQ, 0x1333 },
+ { CCI_REG8(0x3c7e), 0x08 },
+ { CCI_REG8(0x3c7f), 0x05 },
+ { CCI_REG8(0x3e35), 0x00 },
+ { CCI_REG8(0x3e36), 0x00 },
+ { CCI_REG8(0x3e37), 0x00 },
+ { CCI_REG8(0x3f7f), 0x01 },
+ { CCI_REG8(0x4431), 0x04 },
+ { CCI_REG8(0x531c), 0x01 },
+ { CCI_REG8(0x531d), 0x02 },
+ { CCI_REG8(0x531e), 0x04 },
+ { CCI_REG8(0x5928), 0x00 },
+ { CCI_REG8(0x5929), 0x2f },
+ { CCI_REG8(0x592a), 0x00 },
+ { CCI_REG8(0x592b), 0x85 },
+ { CCI_REG8(0x592c), 0x00 },
+ { CCI_REG8(0x592d), 0x32 },
+ { CCI_REG8(0x592e), 0x00 },
+ { CCI_REG8(0x592f), 0x88 },
+ { CCI_REG8(0x5930), 0x00 },
+ { CCI_REG8(0x5931), 0x3d },
+ { CCI_REG8(0x5932), 0x00 },
+ { CCI_REG8(0x5933), 0x93 },
+ { CCI_REG8(0x5938), 0x00 },
+ { CCI_REG8(0x5939), 0x24 },
+ { CCI_REG8(0x593a), 0x00 },
+ { CCI_REG8(0x593b), 0x7a },
+ { CCI_REG8(0x593c), 0x00 },
+ { CCI_REG8(0x593d), 0x24 },
+ { CCI_REG8(0x593e), 0x00 },
+ { CCI_REG8(0x593f), 0x7a },
+ { CCI_REG8(0x5940), 0x00 },
+ { CCI_REG8(0x5941), 0x2f },
+ { CCI_REG8(0x5942), 0x00 },
+ { CCI_REG8(0x5943), 0x85 },
+ { CCI_REG8(0x5f0e), 0x6e },
+ { CCI_REG8(0x5f11), 0xc6 },
+ { CCI_REG8(0x5f17), 0x5e },
+ { CCI_REG8(0x7990), 0x01 },
+ { CCI_REG8(0x7993), 0x5d },
+ { CCI_REG8(0x7994), 0x5d },
+ { CCI_REG8(0x7995), 0xa1 },
+ { CCI_REG8(0x799a), 0x01 },
+ { CCI_REG8(0x799d), 0x00 },
+ { CCI_REG8(0x8169), 0x01 },
+ { CCI_REG8(0x8359), 0x01 },
+ { CCI_REG8(0x9302), 0x1e },
+ { CCI_REG8(0x9306), 0x1f },
+ { CCI_REG8(0x930a), 0x26 },
+ { CCI_REG8(0x930e), 0x23 },
+ { CCI_REG8(0x9312), 0x23 },
+ { CCI_REG8(0x9316), 0x2c },
+ { CCI_REG8(0x9317), 0x19 },
+ { CCI_REG8(0xb046), 0x01 },
+ { CCI_REG8(0xb048), 0x01 },
+};
+
+static const struct cci_reg_sequence mode_1928x1088_regs[] = {
+ { IMX471_REG_CSI_DATA_FORMAT, IMX471_CSI_DATA_FORMAT_RAW10 },
+ { IMX471_REG_CSI_LANE_MODE, IMX471_CSI_4_LANE_MODE },
+ { IMX471_REG_X_ADD_STA, 8 },
+ { IMX471_REG_Y_ADD_STA, 408 },
+ { IMX471_REG_X_ADD_END, 4647 },
+ { IMX471_REG_Y_ADD_END, 3051 },
+ { IMX471_REG_X_EVEN_INC, 1 },
+ { IMX471_REG_X_ODD_INC, 1 },
+ { IMX471_REG_Y_EVEN_INC, 1 },
+ { IMX471_REG_Y_ODD_INC, 1 },
+ { IMX471_REG_BINNING_MODE, IMX471_BINNING_ENABLE },
+ { IMX471_REG_BINNING_TYPE, 0x22 },
+ { IMX471_REG_BINNING_WEIGHTING, 0x08 },
+ { IMX471_REG_DIG_CROP_X_OFFSET, 208 },
+ { IMX471_REG_DIG_CROP_Y_OFFSET, 108 },
+ { IMX471_REG_DIG_CROP_WIDTH, 1928 },
+ { IMX471_REG_DIG_CROP_HEIGHT, 1088 },
+ { IMX471_REG_X_OUTPUT_SIZE, 1928 },
+ { IMX471_REG_Y_OUTPUT_SIZE, 1088 },
+ { IMX471_REG_VTPXCK_DIV, 0x06 },
+ { IMX471_REG_VTSYCK_DIV, 0x02 },
+ { IMX471_REG_PREPLLCK_VT_DIV, 0x02 },
+ { IMX471_REG_PLL_VT_MPY, 0x0079 },
+ { IMX471_REG_OPSYCK_DIV, 0x01 },
+ { CCI_REG8(0x030d), 0x02 },
+ { CCI_REG8(0x030e), 0x00 },
+ { CCI_REG8(0x030f), 0x53 },
+ { IMX471_REG_PLL_MULT_DRIV, IMX471_PLL_DUAL },
+ { CCI_REG8(0x3f4c), 0x81 },
+ { CCI_REG8(0x3f4d), 0x81 },
+ { CCI_REG8(0x3f78), 0x01 },
+ { CCI_REG8(0x3f79), 0x31 },
+ { CCI_REG8(0x3ffe), 0x00 },
+ { CCI_REG8(0x3fff), 0x8a },
+ { CCI_REG8(0x5f0a), 0xb6 },
+};
+
+static const char * const imx471_test_pattern_menu[] = {
+ "Disabled",
+ "Solid Colour",
+ "Eight Vertical Colour Bars",
+ "Colour Bars With Fade to Grey",
+ "Pseudorandom Sequence (PN9)",
+};
+
+static const s64 link_freq_menu_items[] = {
+ IMX471_LINK_FREQ_DEFAULT,
+};
+
+/*
+ * The Bayer formats for the flipping.
+ * - no flip
+ * - h flip
+ * - v flip
+ * - h and v flips
+ */
+static const u32 imx471_hv_flips_bayer_order[] = {
+ MEDIA_BUS_FMT_SRGGB10_1X10,
+ MEDIA_BUS_FMT_SGRBG10_1X10,
+ MEDIA_BUS_FMT_SGBRG10_1X10,
+ MEDIA_BUS_FMT_SBGGR10_1X10,
+};
+
+static const struct imx471_mode imx471_modes[] = {
+ {
+ .width = 1928,
+ .height = 1088,
+ .fll_def = 1308,
+ .fll_min = 1308,
+ .llp = 2328,
+ .default_mode_regs = mode_1928x1088_regs,
+ .default_mode_regs_length = ARRAY_SIZE(mode_1928x1088_regs),
+ },
+};
+
+static int imx471_get_regulators(struct device *dev, struct imx471 *sensor)
+{
+ for (unsigned int i = 0; i < ARRAY_SIZE(imx471_supply_name); i++)
+ sensor->supplies[i].supply = imx471_supply_name[i];
+
+ return devm_regulator_bulk_get(dev, ARRAY_SIZE(imx471_supply_name),
+ sensor->supplies);
+}
+
+static int imx471_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct imx471 *sensor = container_of_const(ctrl->handler,
+ struct imx471,
+ ctrl_handler);
+ struct v4l2_subdev_state *state =
+ v4l2_subdev_get_locked_active_state(&sensor->sd);
+ const struct v4l2_mbus_framefmt *format =
+ v4l2_subdev_state_get_format(state, 0);
+ int ret;
+
+ if (ctrl->id == V4L2_CID_VBLANK) {
+ s64 exposure_max = format->height + ctrl->val -
+ IMX471_EXPOSURE_MARGIN;
+ ret = __v4l2_ctrl_modify_range(sensor->exposure,
+ sensor->exposure->minimum,
+ exposure_max,
+ sensor->exposure->step,
+ exposure_max);
+ if (ret)
+ return ret;
+ }
+
+ if (!pm_runtime_get_if_in_use(sensor->dev))
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_ANALOGUE_GAIN:
+ ret = cci_write(sensor->regmap, IMX471_REG_ANALOG_GAIN,
+ ctrl->val, NULL);
+ break;
+ case V4L2_CID_DIGITAL_GAIN:
+ ret = cci_write(sensor->regmap, IMX471_REG_DIG_GAIN_GLOBAL,
+ ctrl->val, NULL);
+ break;
+ case V4L2_CID_EXPOSURE:
+ ret = cci_write(sensor->regmap, IMX471_REG_EXPOSURE,
+ ctrl->val, &ret);
+ break;
+ case V4L2_CID_VBLANK:
+ /* Update FLL that meets expected vertical blanking */
+ ret = cci_write(sensor->regmap, IMX471_REG_FLL,
+ format->height + ctrl->val, &ret);
+ break;
+ case V4L2_CID_TEST_PATTERN:
+ ret = cci_write(sensor->regmap, IMX471_REG_TEST_PATTERN,
+ ctrl->val, NULL);
+ break;
+ case V4L2_CID_HFLIP:
+ case V4L2_CID_VFLIP:
+ ret = cci_write(sensor->regmap, IMX471_REG_ORIENTATION,
+ sensor->hflip->val | sensor->vflip->val << 1,
+ NULL);
+ break;
+ default:
+ ret = -EINVAL;
+ dev_err(sensor->dev, "ctrl(id:0x%x,val:0x%x) is not handled\n",
+ ctrl->id, ctrl->val);
+ break;
+ }
+
+ pm_runtime_put(sensor->dev);
+
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops imx471_ctrl_ops = {
+ .s_ctrl = imx471_set_ctrl,
+};
+
+static u32 imx471_get_format_code(struct imx471 *sensor)
+{
+ unsigned int i;
+
+ i = (sensor->vflip->val ? 2 : 0) | (sensor->hflip->val ? 1 : 0);
+
+ return imx471_hv_flips_bayer_order[i];
+}
+
+static int imx471_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ struct imx471 *sensor = to_imx471(sd);
+
+ if (code->index >= (ARRAY_SIZE(imx471_hv_flips_bayer_order) / 4))
+ return -EINVAL;
+
+ code->code = imx471_get_format_code(sensor);
+
+ return 0;
+}
+
+static int imx471_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ if (fse->index >= ARRAY_SIZE(imx471_modes))
+ return -EINVAL;
+
+ fse->min_width = imx471_modes[fse->index].width;
+ fse->max_width = fse->min_width;
+ fse->min_height = imx471_modes[fse->index].height;
+ fse->max_height = fse->min_height;
+
+ return 0;
+}
+
+static void imx471_update_pad_format(struct imx471 *sensor,
+ const struct imx471_mode *mode,
+ struct v4l2_subdev_format *fmt)
+{
+ fmt->format.code = imx471_get_format_code(sensor);
+ fmt->format.width = mode->width;
+ fmt->format.height = mode->height;
+ fmt->format.field = V4L2_FIELD_NONE;
+}
+
+static int imx471_set_pad_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct imx471 *sensor = to_imx471(sd);
+ const struct imx471_mode *mode;
+ int h_blank, ret;
+
+ mode = v4l2_find_nearest_size(imx471_modes, ARRAY_SIZE(imx471_modes),
+ width, height, fmt->format.width,
+ fmt->format.height);
+
+ imx471_update_pad_format(sensor, mode, fmt);
+
+ *v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format;
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
+ return 0;
+
+ if (media_entity_is_streaming(&sensor->sd.entity))
+ return -EBUSY;
+
+ ret = __v4l2_ctrl_modify_range(sensor->vblank,
+ mode->fll_min - mode->height,
+ IMX471_FLL_MAX - mode->height,
+ 1,
+ mode->fll_def - mode->height);
+ if (ret)
+ return ret;
+
+ h_blank = mode->llp - mode->width;
+ /*
+ * Currently hblank is not changeable.
+ * So FPS control is done only by vblank.
+ */
+ return __v4l2_ctrl_modify_range(sensor->hblank, h_blank,
+ h_blank, 1, h_blank);
+}
+
+static int imx471_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_selection *sel)
+{
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP:
+ sel->r = *v4l2_subdev_state_get_crop(sd_state, sel->pad);
+ break;
+
+ case V4L2_SEL_TGT_NATIVE_SIZE:
+ sel->r.top = 0;
+ sel->r.left = 0;
+ sel->r.width = IMX471_NATIVE_WIDTH;
+ sel->r.height = IMX471_NATIVE_HEIGHT;
+ return 0;
+
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ sel->r.top = IMX471_PIXEL_ARRAY_TOP;
+ sel->r.left = IMX471_PIXEL_ARRAY_LEFT;
+ sel->r.width = IMX471_PIXEL_ARRAY_WIDTH;
+ sel->r.height = IMX471_PIXEL_ARRAY_HEIGHT;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int imx471_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
+{
+ struct v4l2_subdev_format fmt = {
+ .which = V4L2_SUBDEV_FORMAT_TRY,
+ .format = {
+ .code = MEDIA_BUS_FMT_SRGGB10_1X10,
+ .width = imx471_modes[0].width,
+ .height = imx471_modes[0].height,
+ },
+ };
+
+ return imx471_set_pad_format(sd, sd_state, &fmt);
+}
+
+static int imx471_identify_module(struct imx471 *sensor)
+{
+ int ret;
+ u64 val;
+
+ ret = cci_read(sensor->regmap, IMX471_REG_CHIP_ID, &val, NULL);
+ if (ret)
+ return dev_err_probe(sensor->dev, ret,
+ "failed to read chip id\n");
+
+ if (val != IMX471_CHIP_ID)
+ return dev_err_probe(sensor->dev, -EIO,
+ "chip id mismatch: %x!=%llx\n",
+ IMX471_CHIP_ID, val);
+
+ return 0;
+}
+
+static int imx471_power_off(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct imx471 *sensor = to_imx471(sd);
+
+ clk_disable_unprepare(sensor->img_clk);
+ gpiod_set_value_cansleep(sensor->reset_gpio, 1);
+
+ regulator_bulk_disable(ARRAY_SIZE(imx471_supply_name),
+ sensor->supplies);
+
+ return 0;
+}
+
+static int imx471_power_on(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct imx471 *sensor = to_imx471(sd);
+ int ret;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(imx471_supply_name),
+ sensor->supplies);
+ if (ret < 0) {
+ dev_err(dev, "failed to enable regulators: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(sensor->img_clk);
+ if (ret < 0) {
+ regulator_bulk_disable(ARRAY_SIZE(imx471_supply_name),
+ sensor->supplies);
+ dev_err(dev, "failed to enable imaging clock: %d\n", ret);
+ return ret;
+ }
+
+ gpiod_set_value_cansleep(sensor->reset_gpio, 0);
+
+ usleep_range(10000, 15000);
+
+ return 0;
+}
+
+static int imx471_enable_stream(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ u32 pad, u64 streams_mask)
+{
+ struct imx471 *sensor = to_imx471(sd);
+ const struct imx471_mode *mode;
+ struct v4l2_mbus_framefmt *fmt;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(sensor->dev);
+ if (ret)
+ return ret;
+
+ ret = imx471_identify_module(sensor);
+ if (ret)
+ goto error_powerdown;
+
+ ret = cci_multi_reg_write(sensor->regmap, imx471_global_regs,
+ ARRAY_SIZE(imx471_global_regs), NULL);
+ if (ret) {
+ dev_err(sensor->dev, "failed to set global settings: %d\n",
+ ret);
+ goto error_powerdown;
+ }
+
+ fmt = v4l2_subdev_state_get_format(state, 0);
+ mode = v4l2_find_nearest_size(imx471_modes, ARRAY_SIZE(imx471_modes),
+ width, height, fmt->width, fmt->height);
+
+ ret = cci_multi_reg_write(sensor->regmap, mode->default_mode_regs,
+ mode->default_mode_regs_length, NULL);
+ if (ret) {
+ dev_err(sensor->dev, "failed to set mode: %d\n", ret);
+ goto error_powerdown;
+ }
+
+ ret = cci_write(sensor->regmap, IMX471_REG_DPGA_USE_GLOBAL_GAIN, 1,
+ NULL);
+ if (ret)
+ goto error_powerdown;
+
+ ret = __v4l2_ctrl_handler_setup(&sensor->ctrl_handler);
+ if (ret)
+ goto error_powerdown;
+
+ ret = cci_write(sensor->regmap, IMX471_REG_MODE_SELECT,
+ IMX471_MODE_STREAMING, NULL);
+ if (ret)
+ goto error_powerdown;
+
+ __v4l2_ctrl_grab(sensor->vflip, true);
+ __v4l2_ctrl_grab(sensor->hflip, true);
+
+ return ret;
+
+error_powerdown:
+ pm_runtime_put(sensor->dev);
+
+ return ret;
+}
+
+static int imx471_disable_stream(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ u32 pad, u64 streams_mask)
+{
+ struct imx471 *sensor = to_imx471(sd);
+ int ret;
+
+ ret = cci_write(sensor->regmap, IMX471_REG_MODE_SELECT,
+ IMX471_MODE_STANDBY, NULL);
+ pm_runtime_put(sensor->dev);
+
+ if (ret)
+ dev_err(sensor->dev,
+ "failed to disable stream with return value: %d\n",
+ ret);
+
+ __v4l2_ctrl_grab(sensor->vflip, false);
+ __v4l2_ctrl_grab(sensor->hflip, false);
+
+ return 0;
+}
+
+static const struct v4l2_subdev_video_ops imx471_video_ops = {
+ .s_stream = v4l2_subdev_s_stream_helper,
+};
+
+static const struct v4l2_subdev_pad_ops imx471_pad_ops = {
+ .enum_mbus_code = imx471_enum_mbus_code,
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = imx471_set_pad_format,
+ .get_selection = imx471_get_selection,
+ .enum_frame_size = imx471_enum_frame_size,
+ .enable_streams = imx471_enable_stream,
+ .disable_streams = imx471_disable_stream,
+};
+
+static const struct v4l2_subdev_ops imx471_subdev_ops = {
+ .video = &imx471_video_ops,
+ .pad = &imx471_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops imx471_internal_ops = {
+ .init_state = imx471_init_state,
+};
+
+static int imx471_init_controls(struct imx471 *sensor)
+{
+ const struct imx471_mode *mode = &imx471_modes[0];
+ struct v4l2_fwnode_device_properties props;
+ struct v4l2_ctrl_handler *ctrl_hdlr;
+ struct v4l2_ctrl *link_freq;
+ s64 exposure_max, hblank;
+ u64 pixel_rate;
+ int ret;
+
+ ret = v4l2_fwnode_device_parse(sensor->dev, &props);
+ if (ret) {
+ dev_err(sensor->dev, "failed to parse fwnode: %d\n", ret);
+ return ret;
+ }
+
+ ctrl_hdlr = &sensor->ctrl_handler;
+ v4l2_ctrl_handler_init(ctrl_hdlr, 12);
+
+ v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx471_ctrl_ops, &props);
+
+ link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr,
+ &imx471_ctrl_ops,
+ V4L2_CID_LINK_FREQ,
+ ARRAY_SIZE(link_freq_menu_items) - 1,
+ 0,
+ link_freq_menu_items);
+
+ /* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */
+ pixel_rate = div_u64(IMX471_LINK_FREQ_DEFAULT * 2 * 4, 10);
+
+ v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops,
+ V4L2_CID_PIXEL_RATE, pixel_rate,
+ pixel_rate, 1, pixel_rate);
+
+ sensor->vblank = v4l2_ctrl_new_std(ctrl_hdlr,
+ &imx471_ctrl_ops,
+ V4L2_CID_VBLANK,
+ mode->fll_min - mode->height,
+ IMX471_FLL_MAX - mode->height,
+ 1,
+ mode->fll_def - mode->height);
+
+ hblank = mode->llp - mode->width;
+ sensor->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops,
+ V4L2_CID_HBLANK, hblank, hblank,
+ 1, hblank);
+
+ /* fll >= exposure time + adjust parameter (default value is 18) */
+ exposure_max = mode->fll_def - IMX471_EXPOSURE_MARGIN;
+ sensor->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops,
+ V4L2_CID_EXPOSURE,
+ IMX471_EXPOSURE_MIN, exposure_max,
+ IMX471_EXPOSURE_STEP,
+ IMX471_EXPOSURE_DEFAULT);
+
+ v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
+ IMX471_ANA_GAIN_MIN, IMX471_ANA_GAIN_MAX,
+ IMX471_ANA_GAIN_STEP, IMX471_ANA_GAIN_DEFAULT);
+
+ v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
+ IMX471_DGTL_GAIN_MIN, IMX471_DGTL_GAIN_MAX,
+ IMX471_DGTL_GAIN_STEP, IMX471_DGTL_GAIN_DEFAULT);
+
+ v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx471_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(imx471_test_pattern_menu) - 1,
+ 0, 0, imx471_test_pattern_menu);
+
+ sensor->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+
+ sensor->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+ if (ctrl_hdlr->error) {
+ dev_err(sensor->dev, "%s control init failed: %d\n",
+ __func__, ctrl_hdlr->error);
+ goto error;
+ }
+
+ link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ sensor->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ sensor->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+ sensor->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+
+ sensor->sd.ctrl_handler = ctrl_hdlr;
+
+ return 0;
+
+error:
+ v4l2_ctrl_handler_free(ctrl_hdlr);
+
+ return ctrl_hdlr->error;
+}
+
+static int imx471_check_hwcfg(struct imx471 *sensor)
+{
+ struct v4l2_fwnode_endpoint bus_cfg = {
+ .bus_type = V4L2_MBUS_CSI2_DPHY,
+ };
+ struct fwnode_handle *ep, *fwnode = dev_fwnode(sensor->dev);
+ unsigned long link_freq_bitmap;
+ struct clk *clk;
+ int ret;
+
+ clk = devm_v4l2_sensor_clk_get(sensor->dev, NULL);
+ if (IS_ERR(clk))
+ return dev_err_probe(sensor->dev, PTR_ERR(clk),
+ "can't get clock frequency\n");
+
+ if (clk_get_rate(clk) != IMX471_EXT_CLK)
+ return dev_err_probe(sensor->dev, -EINVAL,
+ "external clock %lu is not supported\n",
+ clk_get_rate(clk));
+
+ ep = fwnode_graph_get_endpoint_by_id(fwnode, 0, 0, 0);
+ ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
+ fwnode_handle_put(ep);
+ if (ret)
+ return dev_err_probe(sensor->dev, ret,
+ "parsing endpoint failed\n");
+
+ if (bus_cfg.bus.mipi_csi2.num_data_lanes != 4) {
+ ret = dev_err_probe(sensor->dev, -EINVAL,
+ "number of CSI2 data lanes %u is not supported\n",
+ bus_cfg.bus.mipi_csi2.num_data_lanes);
+ goto done_endpoint_free;
+ }
+
+ ret = v4l2_link_freq_to_bitmap(sensor->dev, bus_cfg.link_frequencies,
+ bus_cfg.nr_of_link_frequencies,
+ link_freq_menu_items,
+ ARRAY_SIZE(link_freq_menu_items),
+ &link_freq_bitmap);
+
+done_endpoint_free:
+ v4l2_fwnode_endpoint_free(&bus_cfg);
+
+ return ret;
+}
+
+static int imx471_probe(struct i2c_client *client)
+{
+ struct imx471 *sensor;
+ int ret;
+
+ sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL);
+ if (!sensor)
+ return dev_err_probe(&client->dev, -ENOMEM,
+ "failed to allocate memory\n");
+
+ sensor->dev = &client->dev;
+
+ ret = imx471_check_hwcfg(sensor);
+ if (ret)
+ return dev_err_probe(sensor->dev, ret,
+ "failed to check hwcfg: %d\n", ret);
+
+ ret = imx471_get_regulators(sensor->dev, sensor);
+ if (ret)
+ return dev_err_probe(sensor->dev, ret,
+ "failed to get regulators\n");
+
+ sensor->reset_gpio = devm_gpiod_get_optional(sensor->dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(sensor->reset_gpio))
+ return dev_err_probe(sensor->dev, PTR_ERR(sensor->reset_gpio),
+ "failed to get reset gpio\n");
+
+ sensor->img_clk = devm_v4l2_sensor_clk_get(sensor->dev, NULL);
+ if (IS_ERR(sensor->img_clk))
+ return dev_err_probe(sensor->dev, PTR_ERR(sensor->img_clk),
+ "failed to get imaging clock\n");
+
+ v4l2_i2c_subdev_init(&sensor->sd, client, &imx471_subdev_ops);
+
+ sensor->regmap = devm_cci_regmap_init_i2c(client, 16);
+ if (IS_ERR(sensor->regmap))
+ return dev_err_probe(sensor->dev, PTR_ERR(sensor->regmap),
+ "failed to initialize CCI\n");
+
+ ret = imx471_power_on(sensor->dev);
+ if (ret)
+ return dev_err_probe(sensor->dev, ret,
+ "failed to power on\n");
+
+ ret = imx471_identify_module(sensor);
+ if (ret) {
+ dev_err_probe(sensor->dev, ret, "failed to find sensor: %d\n",
+ ret);
+ goto error_power_off;
+ }
+
+ ret = imx471_init_controls(sensor);
+ if (ret) {
+ dev_err_probe(sensor->dev, ret, "failed to init controls: %d\n",
+ ret);
+ goto error_power_off;
+ }
+
+ sensor->sd.internal_ops = &imx471_internal_ops;
+ sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
+ sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+
+ ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
+ if (ret) {
+ dev_err_probe(sensor->dev, ret,
+ "failed to init entity pads: %d\n", ret);
+ goto error_v4l2_ctrl_handler_free;
+ }
+
+ sensor->sd.state_lock = sensor->ctrl_handler.lock;
+ ret = v4l2_subdev_init_finalize(&sensor->sd);
+ if (ret < 0) {
+ dev_err_probe(sensor->dev, ret, "failed to init subdev: %d\n",
+ ret);
+ goto error_media_entity_pm;
+ }
+
+ pm_runtime_set_active(sensor->dev);
+ pm_runtime_enable(sensor->dev);
+
+ ret = v4l2_async_register_subdev_sensor(&sensor->sd);
+ if (ret < 0)
+ goto error_v4l2_subdev_cleanup;
+
+ pm_runtime_idle(sensor->dev);
+
+ return 0;
+
+error_v4l2_subdev_cleanup:
+ pm_runtime_disable(sensor->dev);
+ pm_runtime_set_suspended(sensor->dev);
+ v4l2_subdev_cleanup(&sensor->sd);
+
+error_media_entity_pm:
+ media_entity_cleanup(&sensor->sd.entity);
+
+error_v4l2_ctrl_handler_free:
+ v4l2_ctrl_handler_free(sensor->sd.ctrl_handler);
+
+error_power_off:
+ imx471_power_off(sensor->dev);
+
+ return ret;
+}
+
+static void imx471_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+ v4l2_async_unregister_subdev(sd);
+ v4l2_subdev_cleanup(sd);
+ media_entity_cleanup(&sd->entity);
+ v4l2_ctrl_handler_free(sd->ctrl_handler);
+
+ pm_runtime_disable(&client->dev);
+
+ if (!pm_runtime_status_suspended(&client->dev)) {
+ imx471_power_off(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+ }
+}
+
+static DEFINE_RUNTIME_DEV_PM_OPS(imx471_pm_ops, imx471_power_off,
+ imx471_power_on, NULL);
+
+static const struct acpi_device_id imx471_acpi_ids[] __maybe_unused = {
+ { "SONY471A" },
+ { "TBE20A0" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(acpi, imx471_acpi_ids);
+
+static struct i2c_driver imx471_i2c_driver = {
+ .driver = {
+ .name = "imx471",
+ .acpi_match_table = ACPI_PTR(imx471_acpi_ids),
+ .pm = pm_sleep_ptr(&imx471_pm_ops),
+ },
+ .probe = imx471_probe,
+ .remove = imx471_remove,
+};
+module_i2c_driver(imx471_i2c_driver);
+
+MODULE_AUTHOR("Jimmy Su <jimmy.su@intel.com>");
+MODULE_AUTHOR("Serin Yeh <serin.yeh@intel.com>");
+MODULE_AUTHOR("Kate Hsuan <hpa@redhat.com>");
+MODULE_DESCRIPTION("Sony imx471 sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/imx678.c b/drivers/media/i2c/imx678.c
new file mode 100644
index 000000000000..0efbf43d2fe6
--- /dev/null
+++ b/drivers/media/i2c/imx678.c
@@ -0,0 +1,1447 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * V4L2 driver for Sony IMX678
+ *
+ * Diagonal 8.86 mm (Type 1/1.8) CMOS image sensor with 8.40 M effective pixels.
+ *
+ * Copyright (C) 2026 Ideas On Board Oy.
+ *
+ * Based on Sony IMX678 driver prepared by Will Whang & Soho Enterprise Ltd.
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/media-bus-format.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <media/v4l2-cci.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-mediabus.h>
+#include <media/v4l2-rect.h>
+#include <media/v4l2-subdev.h>
+
+/* Standby or streaming mode */
+#define IMX678_REG_MODE_SELECT CCI_REG8(0x3000)
+#define IMX678_MODE_STANDBY 0x01
+#define IMX678_MODE_STREAMING 0x00
+#define IMX678_STREAM_DELAY_US 25000
+#define IMX678_STREAM_DELAY_RANGE_US 1000
+
+/* XVS/XHS sync control */
+#define IMX678_REG_XMSTA CCI_REG8(0x3002)
+#define IMX678_REG_XXS_DRV CCI_REG8(0x30a6)
+#define IMX678_REG_XXS_OUTSEL CCI_REG8(0x30a4)
+
+/* Clk selection */
+#define IMX678_REG_INCK_SEL CCI_REG8(0x3014)
+
+/* Link Speed */
+#define IMX678_REG_DATARATE_SEL CCI_REG8(0x3015)
+
+/* Lane Count */
+#define IMX678_REG_LANEMODE CCI_REG8(0x3040)
+
+/*
+ * The internal readout clock runs at 74.25 MHz. In one cycle the AD reads 8
+ * pixels, thus giving us a rate of 74.25 * 8 = 594 MPix/s
+ */
+#define IMX678_PIXEL_RATE 594000000
+#define IMX678_PIX_PER_CLK 8
+
+/* VMAX - Frame Length in Lines */
+#define IMX678_REG_VMAX CCI_REG24_LE(0x3028)
+#define IMX678_VMAX_MAX 0xfffff
+#define IMX678_VMAX_DEFAULT 2250
+
+/* HMAX - Line Length in Cycles (8 Pixels) */
+#define IMX678_REG_HMAX CCI_REG16_LE(0x302c)
+#define IMX678_HMAX_MAX 0xffff
+
+/* SHR internal */
+#define IMX678_REG_SHR CCI_REG24_LE(0x3050)
+#define IMX678_SHR_MIN 8
+
+/* Exposure control */
+#define IMX678_EXPOSURE_MIN 2
+#define IMX678_EXPOSURE_STEP 1
+#define IMX678_EXPOSURE_DEFAULT 1000
+
+/*
+ * Analogue gain control
+ * Range is from 0 to 100 (0dB - 30dB) with 0.3dB step size
+ * Values from 101 to 240 are valid but correspond to additional digital gain
+ * (0.3dB - 42dB) so don't expose it to userspace
+ */
+#define IMX678_REG_GAIN CCI_REG16_LE(0x3070)
+#define IMX678_ANA_GAIN_MIN_NORMAL 0
+#define IMX678_ANA_GAIN_MAX_NORMAL 100
+#define IMX678_ANA_GAIN_STEP 1
+#define IMX678_ANA_GAIN_DEFAULT 0
+
+/* Crop */
+#define IMX678_REG_WINMODE CCI_REG8(0x3018)
+#define IMX678_REG_PIX_HST CCI_REG16_LE(0x303c)
+#define IMX678_REG_PIX_HWIDTH CCI_REG16_LE(0x303e)
+#define IMX678_REG_PIX_VST CCI_REG16_LE(0x3044)
+#define IMX678_REG_PIX_VWIDTH CCI_REG16_LE(0x3046)
+
+/* Flip */
+#define IMX678_REG_WINMODEH CCI_REG8(0x3020)
+#define IMX678_REG_WINMODEV CCI_REG8(0x3021)
+
+/* Sensor Identification */
+#define IMX678_REG_MONOCHROME CCI_REG8(0x4d18)
+#define IMX678_TYPE BIT(0)
+#define IMX678_REG_MODULE_ID CCI_REG16_LE(0x4d1c)
+#define IMX678_ID 0x02a6
+#define IMX678_MODULE_ID_DELAY 80000
+
+/* Common configuration registers */
+#define IMX678_REG_WDMODE CCI_REG8(0x301a)
+#define IMX678_REG_ADDMODE CCI_REG8(0x301b)
+#define IMX678_REG_THIN_V_EN CCI_REG8(0x301c)
+#define IMX678_REG_VCMODE CCI_REG8(0x301e)
+#define IMX678_REG_ADBIT CCI_REG8(0x3022)
+#define IMX678_REG_MDBIT CCI_REG8(0x3023)
+#define IMX678_REG_GAIN_PGC_FIDMD CCI_REG8(0x3400)
+
+/* Test pattern generator */
+#define IMX678_REG_TPG_EN_DUOUT CCI_REG8(0x30e0)
+#define IMX678_REG_TPG_PATSEL_DUOUT CCI_REG8(0x30e2)
+#define IMX678_TPG_ALL_000 0
+#define IMX678_TPG_ALL_FFF 1
+#define IMX678_TPG_ALL_555 2
+#define IMX678_TPG_ALL_AAA 3
+#define IMX678_TPG_TOG_555_AAA 4
+#define IMX678_TPG_TOG_AAA_555 5
+#define IMX678_TPG_TOG_000_555 6
+#define IMX678_TPG_TOG_555_000 7
+#define IMX678_TPG_TOG_000_FFF 8
+#define IMX678_TPG_TOG_FFF_000 9
+#define IMX678_TPG_H_COLOR_BARS 10
+#define IMX678_TPG_V_COLOR_BARS 11
+#define IMX678_REG_TPG_COLORWIDTH CCI_REG8(0x30e4)
+#define IMX678_TPG_COLORWIDTH_80PIX 0
+#define IMX678_TPG_COLORWIDTH_160PIX 1
+#define IMX678_TPG_COLORWIDTH_320PIX 2
+#define IMX678_TPG_COLORWIDTH_640PIX 3
+
+#define IMX678_REG_INTERFACE_SEL CCI_REG8(0x4e3c)
+#define IMX678_INTERFACE_2L_4L 0x07
+#define IMX678_INTERFACE_8L_2x4L 0x7f
+
+/* Minimum output resolution */
+#define IMX678_PIXEL_ARRAY_MIN_WIDTH 1040
+#define IMX678_PIXEL_ARRAY_MIN_HEIGHT 956
+
+/* Sensor windowing register alignment */
+#define IMX678_CROP_HWIDTH_ALIGN 16
+#define IMX678_CROP_VWIDTH_ALIGN 4
+#define IMX678_CROP_HST_ALIGN 4
+#define IMX678_CROP_VST_ALIGN 4
+
+/* Subdev pads */
+#define IMX678_SOURCE_PAD 0
+
+/* IMX678 native and active pixel array size. */
+static const struct v4l2_rect imx678_native_area = {
+ .top = 0,
+ .left = 0,
+ .width = 3857,
+ .height = 2201,
+};
+
+static const struct v4l2_rect imx678_active_area = {
+ .top = 20,
+ .left = 0,
+ .width = 3856,
+ .height = 2180,
+};
+
+enum imx678_type {
+ IMX678_COLOR = 0,
+ IMX678_MONOCHROME = 1,
+};
+
+struct imx678_model_info {
+ enum imx678_type type;
+ const u32 *codes;
+ unsigned int num_codes;
+};
+
+enum imx678_lanemode {
+ IMX678_LANEMODE_2L = 1,
+ IMX678_LANEMODE_4L = 3,
+};
+
+/* Link frequency setup (DDR: lane rate = 2 x link freq) */
+enum {
+ IMX678_LINK_FREQ_297MHZ,
+ IMX678_LINK_FREQ_360MHZ,
+ IMX678_LINK_FREQ_445MHZ,
+ IMX678_LINK_FREQ_594MHZ,
+ IMX678_LINK_FREQ_720MHZ,
+ IMX678_LINK_FREQ_891MHZ,
+ IMX678_LINK_FREQ_1039MHZ,
+ IMX678_LINK_FREQ_1188MHZ,
+};
+
+static const u8 link_freqs_reg_value[] = {
+ [IMX678_LINK_FREQ_297MHZ] = 0x07,
+ [IMX678_LINK_FREQ_360MHZ] = 0x06,
+ [IMX678_LINK_FREQ_445MHZ] = 0x05,
+ [IMX678_LINK_FREQ_594MHZ] = 0x04,
+ [IMX678_LINK_FREQ_720MHZ] = 0x03,
+ [IMX678_LINK_FREQ_891MHZ] = 0x02,
+ [IMX678_LINK_FREQ_1039MHZ] = 0x01,
+ [IMX678_LINK_FREQ_1188MHZ] = 0x00,
+};
+
+static const u64 link_freqs[] = {
+ [IMX678_LINK_FREQ_297MHZ] = 297000000,
+ [IMX678_LINK_FREQ_360MHZ] = 360000000,
+ [IMX678_LINK_FREQ_445MHZ] = 445500000,
+ [IMX678_LINK_FREQ_594MHZ] = 594000000,
+ [IMX678_LINK_FREQ_720MHZ] = 720000000,
+ [IMX678_LINK_FREQ_891MHZ] = 891000000,
+ [IMX678_LINK_FREQ_1039MHZ] = 1039500000,
+ [IMX678_LINK_FREQ_1188MHZ] = 1188000000,
+};
+
+static const u16 min_hmax_4lane[] = {
+ [IMX678_LINK_FREQ_297MHZ] = 1584,
+ [IMX678_LINK_FREQ_360MHZ] = 1320,
+ [IMX678_LINK_FREQ_445MHZ] = 1100,
+ [IMX678_LINK_FREQ_594MHZ] = 792,
+ [IMX678_LINK_FREQ_720MHZ] = 660,
+ [IMX678_LINK_FREQ_891MHZ] = 550,
+ [IMX678_LINK_FREQ_1039MHZ] = 550,
+ [IMX678_LINK_FREQ_1188MHZ] = 550,
+};
+
+struct imx678_inck_cfg {
+ u32 xclk_hz; /* platform clock rate */
+ u8 inck_sel; /* value for reg */
+};
+
+static const struct imx678_inck_cfg imx678_inck_table[] = {
+ { 74250000, 0x00 },
+ { 37125000, 0x01 },
+ { 72000000, 0x02 },
+ { 27000000, 0x03 },
+ { 24000000, 0x04 },
+ { 36000000, 0x05 },
+ { 18000000, 0x06 },
+ { 13500000, 0x07 },
+};
+
+static const char * const imx678_tpg_menu[] = {
+ "Disabled",
+ "All 000h",
+ "All FFFh",
+ "All 555h",
+ "All AAAh",
+ "Toggle 555/AAAh",
+ "Toggle AAA/555h",
+ "Toggle 000/555h",
+ "Toggle 555/000h",
+ "Toggle 000/FFFh",
+ "Toggle FFF/000h",
+ "Horizontal color bars",
+ "Vertical color bars",
+};
+
+static const int imx678_tpg_val[] = {
+ IMX678_TPG_ALL_000,
+ IMX678_TPG_ALL_000,
+ IMX678_TPG_ALL_FFF,
+ IMX678_TPG_ALL_555,
+ IMX678_TPG_ALL_AAA,
+ IMX678_TPG_TOG_555_AAA,
+ IMX678_TPG_TOG_AAA_555,
+ IMX678_TPG_TOG_000_555,
+ IMX678_TPG_TOG_555_000,
+ IMX678_TPG_TOG_000_FFF,
+ IMX678_TPG_TOG_FFF_000,
+ IMX678_TPG_H_COLOR_BARS,
+ IMX678_TPG_V_COLOR_BARS,
+};
+
+/* Common configuration */
+static const struct cci_reg_sequence common_regs[] = {
+ { IMX678_REG_THIN_V_EN, 0x00 },
+ { IMX678_REG_VCMODE, 0x01 },
+ { CCI_REG8(0x306b), 0x00 },
+ { IMX678_REG_GAIN_PGC_FIDMD, 0x01 },
+ { CCI_REG8(0x3460), 0x22 },
+ { CCI_REG8(0x355a), 0x64 },
+ { CCI_REG8(0x3a02), 0x7a },
+ { CCI_REG8(0x3a10), 0xec },
+ { CCI_REG8(0x3a12), 0x71 },
+ { CCI_REG8(0x3a14), 0xde },
+ { CCI_REG8(0x3a20), 0x2b },
+ { CCI_REG8(0x3a24), 0x22 },
+ { CCI_REG8(0x3a25), 0x25 },
+ { CCI_REG8(0x3a26), 0x2a },
+ { CCI_REG8(0x3a27), 0x2c },
+ { CCI_REG8(0x3a28), 0x39 },
+ { CCI_REG8(0x3a29), 0x38 },
+ { CCI_REG8(0x3a30), 0x04 },
+ { CCI_REG8(0x3a31), 0x04 },
+ { CCI_REG8(0x3a32), 0x03 },
+ { CCI_REG8(0x3a33), 0x03 },
+ { CCI_REG8(0x3a34), 0x09 },
+ { CCI_REG8(0x3a35), 0x06 },
+ { CCI_REG8(0x3a38), 0xcd },
+ { CCI_REG8(0x3a3a), 0x4c },
+ { CCI_REG8(0x3a3c), 0xb9 },
+ { CCI_REG8(0x3a3e), 0x30 },
+ { CCI_REG8(0x3a40), 0x2c },
+ { CCI_REG8(0x3a42), 0x39 },
+ { CCI_REG8(0x3a4e), 0x00 },
+ { CCI_REG8(0x3a52), 0x00 },
+ { CCI_REG8(0x3a56), 0x00 },
+ { CCI_REG8(0x3a5a), 0x00 },
+ { CCI_REG8(0x3a5e), 0x00 },
+ { CCI_REG8(0x3a62), 0x00 },
+ { CCI_REG8(0x3a64), 0x00 },
+ { CCI_REG8(0x3a6e), 0xa0 },
+ { CCI_REG8(0x3a70), 0x50 },
+ { CCI_REG8(0x3a8c), 0x04 },
+ { CCI_REG8(0x3a8d), 0x03 },
+ { CCI_REG8(0x3a8e), 0x09 },
+ { CCI_REG8(0x3a90), 0x38 },
+ { CCI_REG8(0x3a91), 0x42 },
+ { CCI_REG8(0x3a92), 0x3c },
+ { CCI_REG8(0x3b0e), 0xf3 },
+ { CCI_REG8(0x3b12), 0xe5 },
+ { CCI_REG8(0x3b27), 0xc0 },
+ { CCI_REG8(0x3b2e), 0xef },
+ { CCI_REG8(0x3b30), 0x6a },
+ { CCI_REG8(0x3b32), 0xf6 },
+ { CCI_REG8(0x3b36), 0xe1 },
+ { CCI_REG8(0x3b3a), 0xe8 },
+ { CCI_REG8(0x3b5a), 0x17 },
+ { CCI_REG8(0x3b5e), 0xef },
+ { CCI_REG8(0x3b60), 0x6a },
+ { CCI_REG8(0x3b62), 0xf6 },
+ { CCI_REG8(0x3b66), 0xe1 },
+ { CCI_REG8(0x3b6a), 0xe8 },
+ { CCI_REG8(0x3b88), 0xec },
+ { CCI_REG8(0x3b8a), 0xed },
+ { CCI_REG8(0x3b94), 0x71 },
+ { CCI_REG8(0x3b96), 0x72 },
+ { CCI_REG8(0x3b98), 0xde },
+ { CCI_REG8(0x3b9a), 0xdf },
+ { CCI_REG8(0x3c0f), 0x06 },
+ { CCI_REG8(0x3c10), 0x06 },
+ { CCI_REG8(0x3c11), 0x06 },
+ { CCI_REG8(0x3c12), 0x06 },
+ { CCI_REG8(0x3c13), 0x06 },
+ { CCI_REG8(0x3c18), 0x20 },
+ { CCI_REG8(0x3c37), 0x10 },
+ { CCI_REG8(0x3c3a), 0x7a },
+ { CCI_REG8(0x3c40), 0xf4 },
+ { CCI_REG8(0x3c48), 0xe6 },
+ { CCI_REG8(0x3c54), 0xce },
+ { CCI_REG8(0x3c56), 0xd0 },
+ { CCI_REG8(0x3c6c), 0x53 },
+ { CCI_REG8(0x3c6e), 0x55 },
+ { CCI_REG8(0x3c70), 0xc0 },
+ { CCI_REG8(0x3c72), 0xc2 },
+ { CCI_REG8(0x3c7e), 0xce },
+ { CCI_REG8(0x3c8c), 0xcf },
+ { CCI_REG8(0x3c8e), 0xeb },
+ { CCI_REG8(0x3c98), 0x54 },
+ { CCI_REG8(0x3c9a), 0x70 },
+ { CCI_REG8(0x3c9c), 0xc1 },
+ { CCI_REG8(0x3c9e), 0xdd },
+ { CCI_REG8(0x3cb0), 0x7a },
+ { CCI_REG8(0x3cb2), 0xba },
+ { CCI_REG8(0x3cc8), 0xbc },
+ { CCI_REG8(0x3cca), 0x7c },
+ { CCI_REG8(0x3cd4), 0xea },
+ { CCI_REG8(0x3cd5), 0x01 },
+ { CCI_REG8(0x3cd6), 0x4a },
+ { CCI_REG8(0x3cd8), 0x00 },
+ { CCI_REG8(0x3cd9), 0x00 },
+ { CCI_REG8(0x3cda), 0xff },
+ { CCI_REG8(0x3cdb), 0x03 },
+ { CCI_REG8(0x3cdc), 0x00 },
+ { CCI_REG8(0x3cdd), 0x00 },
+ { CCI_REG8(0x3cde), 0xff },
+ { CCI_REG8(0x3cdf), 0x03 },
+ { CCI_REG8(0x3ce4), 0x4c },
+ { CCI_REG8(0x3ce6), 0xec },
+ { CCI_REG8(0x3ce7), 0x01 },
+ { CCI_REG8(0x3ce8), 0xff },
+ { CCI_REG8(0x3ce9), 0x03 },
+ { CCI_REG8(0x3cea), 0x00 },
+ { CCI_REG8(0x3ceb), 0x00 },
+ { CCI_REG8(0x3cec), 0xff },
+ { CCI_REG8(0x3ced), 0x03 },
+ { CCI_REG8(0x3cee), 0x00 },
+ { CCI_REG8(0x3cef), 0x00 },
+ { CCI_REG8(0x3cf2), 0xff },
+ { CCI_REG8(0x3cf3), 0x03 },
+ { CCI_REG8(0x3cf4), 0x00 },
+ { CCI_REG8(0x3e28), 0x82 },
+ { CCI_REG8(0x3e2a), 0x80 },
+ { CCI_REG8(0x3e30), 0x85 },
+ { CCI_REG8(0x3e32), 0x7d },
+ { CCI_REG8(0x3e5c), 0xce },
+ { CCI_REG8(0x3e5e), 0xd3 },
+ { CCI_REG8(0x3e70), 0x53 },
+ { CCI_REG8(0x3e72), 0x58 },
+ { CCI_REG8(0x3e74), 0xc0 },
+ { CCI_REG8(0x3e76), 0xc5 },
+ { CCI_REG8(0x3e78), 0xc0 },
+ { CCI_REG8(0x3e79), 0x01 },
+ { CCI_REG8(0x3e7a), 0xd4 },
+ { CCI_REG8(0x3e7b), 0x01 },
+ { CCI_REG8(0x3eb4), 0x0b },
+ { CCI_REG8(0x3eb5), 0x02 },
+ { CCI_REG8(0x3eb6), 0x4d },
+ { CCI_REG8(0x3eb7), 0x42 },
+ { CCI_REG8(0x3eec), 0xf3 },
+ { CCI_REG8(0x3eee), 0xe7 },
+ { CCI_REG8(0x3f01), 0x01 },
+ { CCI_REG8(0x3f24), 0x10 },
+ { CCI_REG8(0x3f28), 0x2d },
+ { CCI_REG8(0x3f2a), 0x2d },
+ { CCI_REG8(0x3f2c), 0x2d },
+ { CCI_REG8(0x3f2e), 0x2d },
+ { CCI_REG8(0x3f30), 0x23 },
+ { CCI_REG8(0x3f38), 0x2d },
+ { CCI_REG8(0x3f3a), 0x2d },
+ { CCI_REG8(0x3f3c), 0x2d },
+ { CCI_REG8(0x3f3e), 0x28 },
+ { CCI_REG8(0x3f40), 0x1e },
+ { CCI_REG8(0x3f48), 0x2d },
+ { CCI_REG8(0x3f4a), 0x2d },
+ { CCI_REG8(0x3f4c), 0x00 },
+ { CCI_REG8(0x4004), 0xe4 },
+ { CCI_REG8(0x4006), 0xff },
+ { CCI_REG8(0x4018), 0x69 },
+ { CCI_REG8(0x401a), 0x84 },
+ { CCI_REG8(0x401c), 0xd6 },
+ { CCI_REG8(0x401e), 0xf1 },
+ { CCI_REG8(0x4038), 0xde },
+ { CCI_REG8(0x403a), 0x00 },
+ { CCI_REG8(0x403b), 0x01 },
+ { CCI_REG8(0x404c), 0x63 },
+ { CCI_REG8(0x404e), 0x85 },
+ { CCI_REG8(0x4050), 0xd0 },
+ { CCI_REG8(0x4052), 0xf2 },
+ { CCI_REG8(0x4108), 0xdd },
+ { CCI_REG8(0x410a), 0xf7 },
+ { CCI_REG8(0x411c), 0x62 },
+ { CCI_REG8(0x411e), 0x7c },
+ { CCI_REG8(0x4120), 0xcf },
+ { CCI_REG8(0x4122), 0xe9 },
+ { CCI_REG8(0x4138), 0xe6 },
+ { CCI_REG8(0x413a), 0xf1 },
+ { CCI_REG8(0x414c), 0x6b },
+ { CCI_REG8(0x414e), 0x76 },
+ { CCI_REG8(0x4150), 0xd8 },
+ { CCI_REG8(0x4152), 0xe3 },
+ { CCI_REG8(0x417e), 0x03 },
+ { CCI_REG8(0x417f), 0x01 },
+ { CCI_REG8(0x4186), 0xe0 },
+ { CCI_REG8(0x4190), 0xf3 },
+ { CCI_REG8(0x4192), 0xf7 },
+ { CCI_REG8(0x419c), 0x78 },
+ { CCI_REG8(0x419e), 0x7c },
+ { CCI_REG8(0x41a0), 0xe5 },
+ { CCI_REG8(0x41a2), 0xe9 },
+ { CCI_REG8(0x41c8), 0xe2 },
+ { CCI_REG8(0x41ca), 0xfd },
+ { CCI_REG8(0x41dc), 0x67 },
+ { CCI_REG8(0x41de), 0x82 },
+ { CCI_REG8(0x41e0), 0xd4 },
+ { CCI_REG8(0x41e2), 0xef },
+ { CCI_REG8(0x4200), 0xde },
+ { CCI_REG8(0x4202), 0xda },
+ { CCI_REG8(0x4218), 0x63 },
+ { CCI_REG8(0x421a), 0x5f },
+ { CCI_REG8(0x421c), 0xd0 },
+ { CCI_REG8(0x421e), 0xcc },
+ { CCI_REG8(0x425a), 0x82 },
+ { CCI_REG8(0x425c), 0xef },
+ { CCI_REG8(0x4348), 0xfe },
+ { CCI_REG8(0x4349), 0x06 },
+ { CCI_REG8(0x4352), 0xce },
+ { CCI_REG8(0x4420), 0x0b },
+ { CCI_REG8(0x4421), 0x02 },
+ { CCI_REG8(0x4422), 0x4d },
+ { CCI_REG8(0x4423), 0x0a },
+ { CCI_REG8(0x4426), 0xf5 },
+ { CCI_REG8(0x442a), 0xe7 },
+ { CCI_REG8(0x4432), 0xf5 },
+ { CCI_REG8(0x4436), 0xe7 },
+ { CCI_REG8(0x4466), 0xb4 },
+ { CCI_REG8(0x446e), 0x32 },
+ { CCI_REG8(0x449f), 0x1c },
+ { CCI_REG8(0x44a4), 0x2c },
+ { CCI_REG8(0x44a6), 0x2c },
+ { CCI_REG8(0x44a8), 0x2c },
+ { CCI_REG8(0x44aa), 0x2c },
+ { CCI_REG8(0x44b4), 0x2c },
+ { CCI_REG8(0x44b6), 0x2c },
+ { CCI_REG8(0x44b8), 0x2c },
+ { CCI_REG8(0x44ba), 0x2c },
+ { CCI_REG8(0x44c4), 0x2c },
+ { CCI_REG8(0x44c6), 0x2c },
+ { CCI_REG8(0x44c8), 0x2c },
+ { CCI_REG8(0x4506), 0xf3 },
+ { CCI_REG8(0x450e), 0xe5 },
+ { CCI_REG8(0x4516), 0xf3 },
+ { CCI_REG8(0x4522), 0xe5 },
+ { CCI_REG8(0x4524), 0xf3 },
+ { CCI_REG8(0x452c), 0xe5 },
+ { CCI_REG8(0x453c), 0x22 },
+ { CCI_REG8(0x453d), 0x1b },
+ { CCI_REG8(0x453e), 0x1b },
+ { CCI_REG8(0x453f), 0x15 },
+ { CCI_REG8(0x4540), 0x15 },
+ { CCI_REG8(0x4541), 0x15 },
+ { CCI_REG8(0x4542), 0x15 },
+ { CCI_REG8(0x4543), 0x15 },
+ { CCI_REG8(0x4544), 0x15 },
+ { CCI_REG8(0x4548), 0x00 },
+ { CCI_REG8(0x4549), 0x01 },
+ { CCI_REG8(0x454a), 0x01 },
+ { CCI_REG8(0x454b), 0x06 },
+ { CCI_REG8(0x454c), 0x06 },
+ { CCI_REG8(0x454d), 0x06 },
+ { CCI_REG8(0x454e), 0x06 },
+ { CCI_REG8(0x454f), 0x06 },
+ { CCI_REG8(0x4550), 0x06 },
+ { CCI_REG8(0x4554), 0x55 },
+ { CCI_REG8(0x4555), 0x02 },
+ { CCI_REG8(0x4556), 0x42 },
+ { CCI_REG8(0x4557), 0x05 },
+ { CCI_REG8(0x4558), 0xfd },
+ { CCI_REG8(0x4559), 0x05 },
+ { CCI_REG8(0x455a), 0x94 },
+ { CCI_REG8(0x455b), 0x06 },
+ { CCI_REG8(0x455d), 0x06 },
+ { CCI_REG8(0x455e), 0x49 },
+ { CCI_REG8(0x455f), 0x07 },
+ { CCI_REG8(0x4560), 0x7f },
+ { CCI_REG8(0x4561), 0x07 },
+ { CCI_REG8(0x4562), 0xa5 },
+ { CCI_REG8(0x4564), 0x55 },
+ { CCI_REG8(0x4565), 0x02 },
+ { CCI_REG8(0x4566), 0x42 },
+ { CCI_REG8(0x4567), 0x05 },
+ { CCI_REG8(0x4568), 0xfd },
+ { CCI_REG8(0x4569), 0x05 },
+ { CCI_REG8(0x456a), 0x94 },
+ { CCI_REG8(0x456b), 0x06 },
+ { CCI_REG8(0x456d), 0x06 },
+ { CCI_REG8(0x456e), 0x49 },
+ { CCI_REG8(0x456f), 0x07 },
+ { CCI_REG8(0x4572), 0xa5 },
+ { CCI_REG8(0x460c), 0x7d },
+ { CCI_REG8(0x460e), 0xb1 },
+ { CCI_REG8(0x4614), 0xa8 },
+ { CCI_REG8(0x4616), 0xb2 },
+ { CCI_REG8(0x461c), 0x7e },
+ { CCI_REG8(0x461e), 0xa7 },
+ { CCI_REG8(0x4624), 0xa8 },
+ { CCI_REG8(0x4626), 0xb2 },
+ { CCI_REG8(0x462c), 0x7e },
+ { CCI_REG8(0x462e), 0x8a },
+ { CCI_REG8(0x4630), 0x94 },
+ { CCI_REG8(0x4632), 0xa7 },
+ { CCI_REG8(0x4634), 0xfb },
+ { CCI_REG8(0x4636), 0x2f },
+ { CCI_REG8(0x4638), 0x81 },
+ { CCI_REG8(0x4639), 0x01 },
+ { CCI_REG8(0x463a), 0xb5 },
+ { CCI_REG8(0x463b), 0x01 },
+ { CCI_REG8(0x463c), 0x26 },
+ { CCI_REG8(0x463e), 0x30 },
+ { CCI_REG8(0x4640), 0xac },
+ { CCI_REG8(0x4641), 0x01 },
+ { CCI_REG8(0x4642), 0xb6 },
+ { CCI_REG8(0x4643), 0x01 },
+ { CCI_REG8(0x4644), 0xfc },
+ { CCI_REG8(0x4646), 0x25 },
+ { CCI_REG8(0x4648), 0x82 },
+ { CCI_REG8(0x4649), 0x01 },
+ { CCI_REG8(0x464a), 0xab },
+ { CCI_REG8(0x464b), 0x01 },
+ { CCI_REG8(0x464c), 0x26 },
+ { CCI_REG8(0x464e), 0x30 },
+ { CCI_REG8(0x4654), 0xfc },
+ { CCI_REG8(0x4656), 0x08 },
+ { CCI_REG8(0x4658), 0x12 },
+ { CCI_REG8(0x465a), 0x25 },
+ { CCI_REG8(0x4662), 0xfc },
+ { CCI_REG8(0x46a2), 0xfb },
+ { CCI_REG8(0x46d6), 0xf3 },
+ { CCI_REG8(0x46e6), 0x00 },
+ { CCI_REG8(0x46e8), 0xff },
+ { CCI_REG8(0x46e9), 0x03 },
+ { CCI_REG8(0x46ec), 0x7a },
+ { CCI_REG8(0x46ee), 0xe5 },
+ { CCI_REG8(0x46f4), 0xee },
+ { CCI_REG8(0x46f6), 0xf2 },
+ { CCI_REG8(0x470c), 0xff },
+ { CCI_REG8(0x470d), 0x03 },
+ { CCI_REG8(0x470e), 0x00 },
+ { CCI_REG8(0x4714), 0xe0 },
+ { CCI_REG8(0x4716), 0xe4 },
+ { CCI_REG8(0x471e), 0xed },
+ { CCI_REG8(0x472e), 0x00 },
+ { CCI_REG8(0x4730), 0xff },
+ { CCI_REG8(0x4731), 0x03 },
+ { CCI_REG8(0x4734), 0x7b },
+ { CCI_REG8(0x4736), 0xdf },
+ { CCI_REG8(0x4754), 0x7d },
+ { CCI_REG8(0x4756), 0x8b },
+ { CCI_REG8(0x4758), 0x93 },
+ { CCI_REG8(0x475a), 0xb1 },
+ { CCI_REG8(0x475c), 0xfb },
+ { CCI_REG8(0x475e), 0x09 },
+ { CCI_REG8(0x4760), 0x11 },
+ { CCI_REG8(0x4762), 0x2f },
+ { CCI_REG8(0x4766), 0xcc },
+ { CCI_REG8(0x4776), 0xcb },
+ { CCI_REG8(0x477e), 0x4a },
+ { CCI_REG8(0x478e), 0x49 },
+ { CCI_REG8(0x4794), 0x7c },
+ { CCI_REG8(0x4796), 0x8f },
+ { CCI_REG8(0x4798), 0xb3 },
+ { CCI_REG8(0x4799), 0x00 },
+ { CCI_REG8(0x479a), 0xcc },
+ { CCI_REG8(0x479c), 0xc1 },
+ { CCI_REG8(0x479e), 0xcb },
+ { CCI_REG8(0x47a4), 0x7d },
+ { CCI_REG8(0x47a6), 0x8e },
+ { CCI_REG8(0x47a8), 0xb4 },
+ { CCI_REG8(0x47a9), 0x00 },
+ { CCI_REG8(0x47aa), 0xc0 },
+ { CCI_REG8(0x47ac), 0xfa },
+ { CCI_REG8(0x47ae), 0x0d },
+ { CCI_REG8(0x47b0), 0x31 },
+ { CCI_REG8(0x47b1), 0x01 },
+ { CCI_REG8(0x47b2), 0x4a },
+ { CCI_REG8(0x47b3), 0x01 },
+ { CCI_REG8(0x47b4), 0x3f },
+ { CCI_REG8(0x47b6), 0x49 },
+ { CCI_REG8(0x47bc), 0xfb },
+ { CCI_REG8(0x47be), 0x0c },
+ { CCI_REG8(0x47c0), 0x32 },
+ { CCI_REG8(0x47c1), 0x01 },
+ { CCI_REG8(0x47c2), 0x3e },
+ { CCI_REG8(0x47c3), 0x01 },
+ { IMX678_REG_WDMODE, 0x00 },
+ { IMX678_REG_MDBIT, 0x01 },
+ { IMX678_REG_XXS_DRV, 0x00 },
+};
+
+static const u32 codes_bayer[] = {
+ MEDIA_BUS_FMT_SRGGB12_1X12,
+};
+
+static const u32 codes_monochrome[] = {
+ MEDIA_BUS_FMT_Y12_1X12,
+};
+
+static const struct imx678_model_info imx678_aaqr_info = {
+ .type = IMX678_COLOR,
+ .codes = codes_bayer,
+ .num_codes = ARRAY_SIZE(codes_bayer),
+};
+
+static const struct imx678_model_info imx678_aamr_info = {
+ .type = IMX678_MONOCHROME,
+ .codes = codes_monochrome,
+ .num_codes = ARRAY_SIZE(codes_monochrome),
+};
+
+static const char * const imx678_supply_name[] = {
+ "avdd", /* Analog (3.3V) supply */
+ "dvdd", /* Digital Core (1.1V) supply */
+ "ovdd", /* IF (1.8V) supply */
+};
+
+struct imx678 {
+ struct v4l2_subdev sd;
+ struct media_pad pad;
+ struct regmap *cci;
+
+ const struct imx678_model_info *info;
+
+ struct clk *xclk;
+ u32 xclk_freq;
+
+ /* chosen INCK_SEL register value */
+ u8 inck_sel_val;
+
+ /* Link configurations */
+ enum imx678_lanemode lane_mode;
+ unsigned long link_freq_bitmap;
+
+ struct gpio_desc *reset_gpio;
+ struct regulator_bulk_data supplies[ARRAY_SIZE(imx678_supply_name)];
+
+ struct v4l2_ctrl_handler ctrl_handler;
+
+ /* V4L2 Controls */
+ struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *vblank;
+ struct v4l2_ctrl *hblank;
+
+ /* Track VMAX for exposure updates */
+ u32 vmax;
+};
+
+static inline struct imx678 *to_imx678(struct v4l2_subdev *_sd)
+{
+ return container_of_const(_sd, struct imx678, sd);
+}
+
+static u32 imx678_default_mbus_code(struct imx678 *imx678)
+{
+ return imx678->info->codes[0];
+}
+
+static bool imx678_mbus_code_supported(struct imx678 *imx678, u32 code)
+{
+ for (unsigned int i = 0; i < imx678->info->num_codes; i++) {
+ if (imx678->info->codes[i] == code)
+ return true;
+ }
+
+ return false;
+}
+
+static int imx678_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct imx678 *imx678 = container_of_const(ctrl->handler, struct
+ imx678, ctrl_handler);
+ struct i2c_client *client = v4l2_get_subdevdata(&imx678->sd);
+ const struct v4l2_mbus_framefmt *format;
+ struct v4l2_subdev_state *state;
+ int ret = 0;
+
+ state = v4l2_subdev_get_locked_active_state(&imx678->sd);
+ format = v4l2_subdev_state_get_format(state, IMX678_SOURCE_PAD);
+
+ if (ctrl->id == V4L2_CID_VBLANK) {
+ u32 current_exposure = imx678->exposure->cur.val;
+
+ imx678->vmax = format->height + ctrl->val;
+
+ current_exposure = clamp_t(u32, current_exposure,
+ IMX678_EXPOSURE_MIN,
+ imx678->vmax - IMX678_SHR_MIN);
+ ret = __v4l2_ctrl_modify_range(imx678->exposure,
+ IMX678_EXPOSURE_MIN,
+ imx678->vmax - IMX678_SHR_MIN,
+ 1, current_exposure);
+ if (ret)
+ return ret;
+ }
+
+ /*
+ * Only apply control values when device is powered on (RPM ACTIVE)
+ * and streaming (usage count != 0)
+ */
+ if (!pm_runtime_get_if_in_use(&client->dev))
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_VBLANK:
+ cci_write(imx678->cci, IMX678_REG_VMAX, imx678->vmax, &ret);
+ fallthrough; /* SHR = VMAX - exposure, so update it */
+ case V4L2_CID_EXPOSURE: {
+ u32 shr = imx678->vmax - imx678->exposure->val;
+
+ cci_write(imx678->cci, IMX678_REG_SHR, shr, &ret);
+ break;
+ }
+ case V4L2_CID_ANALOGUE_GAIN:
+ cci_write(imx678->cci, IMX678_REG_GAIN, ctrl->val, &ret);
+ break;
+ case V4L2_CID_HBLANK: {
+ u32 hmax = (format->width + ctrl->val) / IMX678_PIX_PER_CLK;
+
+ cci_write(imx678->cci, IMX678_REG_HMAX, hmax, &ret);
+ break;
+ }
+ case V4L2_CID_TEST_PATTERN: {
+ cci_write(imx678->cci, IMX678_REG_TPG_COLORWIDTH,
+ IMX678_TPG_COLORWIDTH_160PIX, &ret);
+ cci_write(imx678->cci, IMX678_REG_TPG_PATSEL_DUOUT,
+ imx678_tpg_val[ctrl->val], &ret);
+ cci_write(imx678->cci, IMX678_REG_TPG_EN_DUOUT,
+ (ctrl->val) ? 1 : 0,
+ &ret);
+ break;
+ }
+ case V4L2_CID_HFLIP:
+ cci_write(imx678->cci, IMX678_REG_WINMODEH, ctrl->val, &ret);
+ break;
+ case V4L2_CID_VFLIP:
+ cci_write(imx678->cci, IMX678_REG_WINMODEV, ctrl->val, &ret);
+ break;
+ default:
+ dev_warn(&client->dev,
+ "ctrl(id:0x%x,val:0x%x) is not handled\n",
+ ctrl->id, ctrl->val);
+ break;
+ }
+
+ pm_runtime_put(&client->dev);
+
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops imx678_ctrl_ops = {
+ .s_ctrl = imx678_set_ctrl,
+};
+
+static int imx678_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ struct imx678 *imx678 = to_imx678(sd);
+
+ if (code->index >= imx678->info->num_codes)
+ return -EINVAL;
+
+ code->code = imx678->info->codes[code->index];
+
+ return 0;
+}
+
+static int imx678_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ struct imx678 *imx678 = to_imx678(sd);
+ const struct v4l2_rect *crop;
+
+ if (fse->index)
+ return -EINVAL;
+
+ if (!imx678_mbus_code_supported(imx678, fse->code))
+ return -EINVAL;
+
+ crop = v4l2_subdev_state_get_crop(sd_state, fse->pad);
+
+ fse->min_width = crop->width;
+ fse->max_width = fse->min_width;
+ fse->min_height = crop->height;
+ fse->max_height = fse->min_height;
+
+ return 0;
+}
+
+static int imx678_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_selection *sel)
+{
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP:
+ sel->r = *v4l2_subdev_state_get_crop(sd_state, sel->pad);
+ return 0;
+
+ case V4L2_SEL_TGT_NATIVE_SIZE:
+ sel->r = imx678_native_area;
+ return 0;
+
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ sel->r = imx678_active_area;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int imx678_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ struct imx678 *imx678 = to_imx678(sd);
+ struct v4l2_mbus_framefmt *format;
+ struct v4l2_rect *crop;
+
+ crop = v4l2_subdev_state_get_crop(state, IMX678_SOURCE_PAD);
+ *crop = imx678_active_area;
+
+ format = v4l2_subdev_state_get_format(state, IMX678_SOURCE_PAD);
+ format->code = imx678_default_mbus_code(imx678);
+ format->width = imx678_active_area.width;
+ format->height = imx678_active_area.height;
+ format->field = V4L2_FIELD_NONE;
+ format->colorspace = V4L2_COLORSPACE_RAW;
+ format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ format->quantization = V4L2_QUANTIZATION_FULL_RANGE;
+ format->xfer_func = V4L2_XFER_FUNC_NONE;
+
+ return 0;
+}
+
+static int imx678_write_common(struct imx678 *imx678)
+{
+ int ret = 0;
+
+ cci_multi_reg_write(imx678->cci, common_regs, ARRAY_SIZE(common_regs),
+ &ret);
+
+ cci_write(imx678->cci, IMX678_REG_INCK_SEL, imx678->inck_sel_val, &ret);
+ cci_write(imx678->cci, IMX678_REG_DATARATE_SEL,
+ link_freqs_reg_value[__ffs(imx678->link_freq_bitmap)], &ret);
+ cci_write(imx678->cci, IMX678_REG_LANEMODE, imx678->lane_mode, &ret);
+
+ cci_write(imx678->cci, IMX678_REG_INTERFACE_SEL, IMX678_INTERFACE_2L_4L,
+ &ret);
+
+ return ret;
+}
+
+static int imx678_program_window(struct imx678 *imx678,
+ const struct v4l2_rect *crop)
+{
+ int ret = 0;
+
+ cci_write(imx678->cci, IMX678_REG_ADDMODE, 0x00, &ret);
+ cci_write(imx678->cci, IMX678_REG_WINMODE,
+ v4l2_rect_equal(crop, &imx678_active_area) ? 0x00 : 0x04,
+ &ret);
+ cci_write(imx678->cci, IMX678_REG_PIX_HST,
+ crop->left - imx678_active_area.left, &ret);
+ cci_write(imx678->cci, IMX678_REG_PIX_HWIDTH, crop->width, &ret);
+ cci_write(imx678->cci, IMX678_REG_PIX_VST,
+ crop->top - imx678_active_area.top, &ret);
+ cci_write(imx678->cci, IMX678_REG_PIX_VWIDTH, crop->height, &ret);
+ cci_write(imx678->cci, IMX678_REG_ADBIT, 0x01, &ret);
+
+ return ret;
+}
+
+static int imx678_enable_streams(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state, u32 pad,
+ u64 mask)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct imx678 *imx678 = to_imx678(sd);
+ const struct v4l2_rect *crop;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(&client->dev);
+ if (ret < 0)
+ return ret;
+
+ crop = v4l2_subdev_state_get_crop(state, pad);
+ ret = imx678_program_window(imx678, crop);
+ if (ret) {
+ dev_err(&client->dev, "%s failed to set mode\n", __func__);
+ goto err_rpm_put;
+ }
+
+ ret = __v4l2_ctrl_handler_setup(imx678->sd.ctrl_handler);
+ if (ret) {
+ dev_err(&client->dev, "%s failed to apply user values\n",
+ __func__);
+ goto err_rpm_put;
+ }
+
+ cci_write(imx678->cci, IMX678_REG_MODE_SELECT, IMX678_MODE_STREAMING,
+ &ret);
+ usleep_range(IMX678_STREAM_DELAY_US, IMX678_STREAM_DELAY_US +
+ IMX678_STREAM_DELAY_RANGE_US);
+ cci_write(imx678->cci, IMX678_REG_XMSTA, 0x00, &ret);
+
+ if (ret) {
+ dev_err(&client->dev, "%s failed to start streaming\n",
+ __func__);
+ goto err_rpm_put;
+ }
+
+ return 0;
+
+err_rpm_put:
+ pm_runtime_put(&client->dev);
+
+ return ret;
+}
+
+static int imx678_disable_streams(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ u32 pad, u64 mask)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct imx678 *imx678 = to_imx678(sd);
+ int ret = 0;
+
+ /* Master mode disable */
+ cci_write(imx678->cci, IMX678_REG_XMSTA, 0x01, &ret);
+ /* Standby */
+ cci_write(imx678->cci, IMX678_REG_MODE_SELECT, IMX678_MODE_STANDBY,
+ &ret);
+ if (ret)
+ dev_err(&client->dev, "%s failed to stop stream\n", __func__);
+
+ pm_runtime_put(&client->dev);
+
+ return ret;
+}
+
+static int imx678_power_on(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct imx678 *imx678 = to_imx678(sd);
+ int ret;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(imx678_supply_name),
+ imx678->supplies);
+ if (ret) {
+ dev_err(&client->dev, "%s: failed to enable regulators\n",
+ __func__);
+ return ret;
+ }
+
+ fsleep(1); /* Tlow > 500ns */
+
+ gpiod_set_value_cansleep(imx678->reset_gpio, 0);
+
+ fsleep(1); /* T3 > 1us */
+
+ ret = clk_prepare_enable(imx678->xclk);
+ if (ret) {
+ dev_err(&client->dev, "%s: failed to enable clock\n",
+ __func__);
+ goto reg_off;
+ }
+
+ fsleep(20); /* T4 > 20us */
+
+ ret = imx678_write_common(imx678);
+ if (ret) {
+ dev_err(&client->dev, "%s failed to write registers\n",
+ __func__);
+ goto clk_off;
+ }
+
+ return 0;
+
+clk_off:
+ clk_disable_unprepare(imx678->xclk);
+
+reg_off:
+ gpiod_set_value_cansleep(imx678->reset_gpio, 1);
+ regulator_bulk_disable(ARRAY_SIZE(imx678_supply_name),
+ imx678->supplies);
+
+ return ret;
+}
+
+static int imx678_power_off(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct imx678 *imx678 = to_imx678(sd);
+
+ clk_disable_unprepare(imx678->xclk);
+ gpiod_set_value_cansleep(imx678->reset_gpio, 1);
+ regulator_bulk_disable(ARRAY_SIZE(imx678_supply_name),
+ imx678->supplies);
+
+ return 0;
+}
+
+static int imx678_identify_model(struct imx678 *imx678)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx678->sd);
+ const struct imx678_model_info *info;
+ enum imx678_type detected;
+ int ret = 0;
+ u64 val = 0;
+
+ info = device_get_match_data(&client->dev);
+
+ /*
+ * This sensor's ID registers become accessible 80ms after coming out
+ * of STANDBY mode.
+ */
+ cci_write(imx678->cci, IMX678_REG_MODE_SELECT, 0, &ret);
+ fsleep(IMX678_MODULE_ID_DELAY);
+
+ cci_read(imx678->cci, IMX678_REG_MODULE_ID, &val, &ret);
+
+ if (ret) {
+ dev_err(&client->dev,
+ "I2C transaction failed ret = %d\n", ret);
+ return ret;
+ }
+
+ if (val != IMX678_ID) {
+ dev_err(&client->dev,
+ "Chip ID mismatch: %x!=%llx\n", IMX678_ID, val);
+ return -ENXIO;
+ }
+
+ cci_read(imx678->cci, IMX678_REG_MONOCHROME, &val, &ret);
+
+ if (ret) {
+ dev_err(&client->dev,
+ "I2C transaction failed ret = %d\n", ret);
+ return ret;
+ }
+
+ detected = val & IMX678_TYPE;
+
+ /* Prefer to use sensor type specified in device tree */
+ if (info) {
+ imx678->info = info;
+ if (detected != info->type)
+ dev_err(&client->dev,
+ "detected %s sensor, DT specifies %s; using DT value\n",
+ detected == IMX678_COLOR ? "color" : "mono",
+ info->type == IMX678_COLOR ? "color" : "mono");
+ } else {
+ imx678->info = detected == IMX678_MONOCHROME ?
+ &imx678_aamr_info : &imx678_aaqr_info;
+ dev_info(&client->dev,
+ "sensor type missing in DT; detected %s sensor\n",
+ detected == IMX678_MONOCHROME ? "mono" : "color");
+ }
+
+ return 0;
+}
+
+static const struct v4l2_subdev_video_ops imx678_video_ops = {
+ .s_stream = v4l2_subdev_s_stream_helper,
+};
+
+static const struct v4l2_subdev_pad_ops imx678_pad_ops = {
+ .enum_mbus_code = imx678_enum_mbus_code,
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = v4l2_subdev_get_fmt,
+ .get_selection = imx678_get_selection,
+ .enum_frame_size = imx678_enum_frame_size,
+ .enable_streams = imx678_enable_streams,
+ .disable_streams = imx678_disable_streams,
+};
+
+static const struct v4l2_subdev_ops imx678_subdev_ops = {
+ .video = &imx678_video_ops,
+ .pad = &imx678_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops imx678_internal_ops = {
+ .init_state = imx678_init_state,
+};
+
+static int imx678_init_controls(struct imx678 *imx678)
+{
+ struct v4l2_ctrl_handler *ctrl_hdlr;
+ const u32 hmax_4lane = min_hmax_4lane[__ffs(imx678->link_freq_bitmap)];
+ const u32 lane_scale = imx678->lane_mode == IMX678_LANEMODE_2L ? 2 : 1;
+ struct i2c_client *client = v4l2_get_subdevdata(&imx678->sd);
+ struct v4l2_fwnode_device_properties props;
+ struct v4l2_ctrl *link_freq;
+ s32 hblank, max_hblank, vblank, max_vblank;
+ u32 hmax;
+ int ret;
+
+ ret = v4l2_fwnode_device_parse(&client->dev, &props);
+ if (ret < 0)
+ return ret;
+
+ ctrl_hdlr = &imx678->ctrl_handler;
+ ret = v4l2_ctrl_handler_init(ctrl_hdlr, 11);
+ if (ret)
+ return ret;
+
+ imx678->vmax = IMX678_VMAX_DEFAULT;
+ hmax = hmax_4lane * lane_scale;
+
+ /* PIXEL_RATE is fixed and read-only */
+ v4l2_ctrl_new_std(ctrl_hdlr, &imx678_ctrl_ops, V4L2_CID_PIXEL_RATE,
+ IMX678_PIXEL_RATE, IMX678_PIXEL_RATE, 1,
+ IMX678_PIXEL_RATE);
+
+ /* LINK_FREQ is also read only */
+ link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx678_ctrl_ops,
+ V4L2_CID_LINK_FREQ,
+ ARRAY_SIZE(link_freqs) - 1,
+ __ffs(imx678->link_freq_bitmap),
+ link_freqs);
+
+ if (link_freq)
+ link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ vblank = imx678->vmax - imx678_active_area.height;
+ max_vblank = IMX678_VMAX_MAX - imx678_active_area.height;
+ imx678->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx678_ctrl_ops,
+ V4L2_CID_VBLANK, vblank, max_vblank,
+ 2, vblank);
+
+ hblank = hmax * IMX678_PIX_PER_CLK - imx678_active_area.width;
+ max_hblank = IMX678_HMAX_MAX * IMX678_PIX_PER_CLK -
+ imx678_active_area.width;
+ imx678->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx678_ctrl_ops,
+ V4L2_CID_HBLANK, hblank, max_hblank,
+ IMX678_PIX_PER_CLK, hblank);
+
+ imx678->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx678_ctrl_ops,
+ V4L2_CID_EXPOSURE,
+ IMX678_EXPOSURE_MIN,
+ IMX678_VMAX_DEFAULT -
+ IMX678_SHR_MIN,
+ IMX678_EXPOSURE_STEP,
+ IMX678_EXPOSURE_DEFAULT);
+
+ v4l2_ctrl_new_std(ctrl_hdlr, &imx678_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
+ IMX678_ANA_GAIN_MIN_NORMAL,
+ IMX678_ANA_GAIN_MAX_NORMAL, IMX678_ANA_GAIN_STEP,
+ IMX678_ANA_GAIN_DEFAULT);
+
+ v4l2_ctrl_new_std(ctrl_hdlr, &imx678_ctrl_ops, V4L2_CID_HFLIP,
+ 0, 1, 1, 0);
+ v4l2_ctrl_new_std(ctrl_hdlr, &imx678_ctrl_ops, V4L2_CID_VFLIP,
+ 0, 1, 1, 0);
+
+ v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx678_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(imx678_tpg_menu) - 1, 0, 0,
+ imx678_tpg_menu);
+
+ v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx678_ctrl_ops, &props);
+
+ if (ctrl_hdlr->error) {
+ ret = ctrl_hdlr->error;
+ dev_err(&client->dev, "%s control init failed (%d)\n",
+ __func__, ret);
+ v4l2_ctrl_handler_free(ctrl_hdlr);
+ return ret;
+ }
+
+ imx678->sd.ctrl_handler = ctrl_hdlr;
+
+ return 0;
+}
+
+static int imx678_check_hwcfg(struct device *dev, struct imx678 *imx678)
+{
+ struct fwnode_handle *endpoint;
+ struct v4l2_fwnode_endpoint ep_cfg = {
+ .bus_type = V4L2_MBUS_CSI2_DPHY
+ };
+ int ret = -EINVAL;
+
+ endpoint = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, 0);
+ if (!endpoint) {
+ dev_err(dev, "endpoint node not found\n");
+ return -EINVAL;
+ }
+
+ if (v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep_cfg)) {
+ dev_err(dev, "could not parse endpoint\n");
+ goto error_out;
+ }
+
+ switch (ep_cfg.bus.mipi_csi2.num_data_lanes) {
+ case 2:
+ imx678->lane_mode = IMX678_LANEMODE_2L;
+ break;
+ case 4:
+ imx678->lane_mode = IMX678_LANEMODE_4L;
+ break;
+ default:
+ dev_err(dev,
+ "only 2 or 4 CSI2 data lanes are currently supported\n");
+ goto error_out;
+ }
+
+ ret = v4l2_link_freq_to_bitmap(dev, ep_cfg.link_frequencies,
+ ep_cfg.nr_of_link_frequencies,
+ link_freqs, ARRAY_SIZE(link_freqs),
+ &imx678->link_freq_bitmap);
+
+error_out:
+ v4l2_fwnode_endpoint_free(&ep_cfg);
+ fwnode_handle_put(endpoint);
+
+ return ret;
+}
+
+static int imx678_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct imx678 *imx678;
+ int ret, i;
+
+ imx678 = devm_kzalloc(&client->dev, sizeof(*imx678), GFP_KERNEL);
+ if (!imx678)
+ return -ENOMEM;
+
+ v4l2_i2c_subdev_init(&imx678->sd, client, &imx678_subdev_ops);
+
+ imx678->cci = devm_cci_regmap_init_i2c(client, 16);
+ if (IS_ERR(imx678->cci))
+ return dev_err_probe(dev, PTR_ERR(imx678->cci),
+ "failed to init CCI\n");
+
+ if (imx678_check_hwcfg(dev, imx678))
+ return -EINVAL;
+
+ imx678->xclk = devm_v4l2_sensor_clk_get(dev, NULL);
+ if (IS_ERR(imx678->xclk))
+ return dev_err_probe(dev, PTR_ERR(imx678->xclk),
+ "failed to get xclk\n");
+
+ imx678->xclk_freq = clk_get_rate(imx678->xclk);
+
+ for (i = 0; i < ARRAY_SIZE(imx678_inck_table); ++i) {
+ if (imx678_inck_table[i].xclk_hz == imx678->xclk_freq) {
+ imx678->inck_sel_val = imx678_inck_table[i].inck_sel;
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(imx678_inck_table))
+ return dev_err_probe(dev, -EINVAL,
+ "unsupported XCLK rate %u Hz\n",
+ imx678->xclk_freq);
+
+ for (i = 0; i < ARRAY_SIZE(imx678_supply_name); i++)
+ imx678->supplies[i].supply = imx678_supply_name[i];
+
+ ret = devm_regulator_bulk_get(&client->dev,
+ ARRAY_SIZE(imx678_supply_name),
+ imx678->supplies);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to get regulators\n");
+
+ imx678->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(imx678->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(imx678->reset_gpio),
+ "failed to get reset GPIO\n");
+
+ ret = imx678_power_on(dev);
+ if (ret)
+ return ret;
+
+ ret = imx678_identify_model(imx678);
+ if (ret)
+ goto error_power_off;
+
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ ret = imx678_init_controls(imx678);
+ if (ret)
+ goto error_pm_runtime;
+
+ imx678->sd.internal_ops = &imx678_internal_ops;
+ imx678->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ imx678->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+
+ imx678->pad.flags = MEDIA_PAD_FL_SOURCE;
+
+ ret = media_entity_pads_init(&imx678->sd.entity, 1, &imx678->pad);
+ if (ret) {
+ dev_err_probe(dev, ret, "failed to init entity pads\n");
+ goto error_handler_free;
+ }
+
+ imx678->sd.state_lock = imx678->ctrl_handler.lock;
+ ret = v4l2_subdev_init_finalize(&imx678->sd);
+ if (ret < 0) {
+ dev_err_probe(dev, ret, "subdev init error\n");
+ goto error_media_entity;
+ }
+
+ ret = v4l2_async_register_subdev_sensor(&imx678->sd);
+ if (ret < 0) {
+ dev_err_probe(dev, ret,
+ "failed to register sensor sub-device\n");
+ goto error_subdev_cleanup;
+ }
+
+ pm_runtime_idle(dev);
+
+ return 0;
+
+error_subdev_cleanup:
+ v4l2_subdev_cleanup(&imx678->sd);
+
+error_media_entity:
+ media_entity_cleanup(&imx678->sd.entity);
+
+error_handler_free:
+ v4l2_ctrl_handler_free(imx678->sd.ctrl_handler);
+
+error_pm_runtime:
+ pm_runtime_disable(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+
+error_power_off:
+ imx678_power_off(&client->dev);
+
+ return ret;
+}
+
+static void imx678_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct imx678 *imx678 = to_imx678(sd);
+
+ v4l2_async_unregister_subdev(sd);
+ v4l2_subdev_cleanup(sd);
+ media_entity_cleanup(&sd->entity);
+ v4l2_ctrl_handler_free(imx678->sd.ctrl_handler);
+
+ pm_runtime_disable(&client->dev);
+ if (!pm_runtime_status_suspended(&client->dev))
+ imx678_power_off(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+}
+
+static const struct dev_pm_ops imx678_pm_ops = {
+ SET_RUNTIME_PM_OPS(imx678_power_off, imx678_power_on, NULL)
+};
+
+static const struct of_device_id imx678_of_match[] = {
+ { .compatible = "sony,imx678-aamr", .data = &imx678_aamr_info },
+ { .compatible = "sony,imx678-aaqr", .data = &imx678_aaqr_info },
+ /* for non-conforming DTs that rely on runtime check */
+ { .compatible = "sony,imx678" },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, imx678_of_match);
+
+static struct i2c_driver imx678_i2c_driver = {
+ .driver = {
+ .name = "imx678",
+ .of_match_table = imx678_of_match,
+ .pm = pm_ptr(&imx678_pm_ops),
+ },
+ .probe = imx678_probe,
+ .remove = imx678_remove,
+};
+
+module_i2c_driver(imx678_i2c_driver);
+
+MODULE_AUTHOR("Will Whang <will@willwhang.com>");
+MODULE_AUTHOR("Tetsuya NOMURA <tetsuya.nomura@soho-enterprise.com>");
+MODULE_AUTHOR("Jai Luthra <jai.luthra@ideasonboard.com>");
+MODULE_DESCRIPTION("Sony imx678 sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/ov02a10.c b/drivers/media/i2c/ov02a10.c
index 143dcfe10445..0150e4d296af 100644
--- a/drivers/media/i2c/ov02a10.c
+++ b/drivers/media/i2c/ov02a10.c
@@ -820,18 +820,16 @@ static int ov02a10_check_hwcfg(struct device *dev, struct ov02a10 *ov02a10)
if (!ep)
return -ENXIO;
+ /* Optional indication of MIPI clock voltage unit */
+ if (!fwnode_property_read_u32(ep, "ovti,mipi-clock-voltage",
+ &clk_volt))
+ ov02a10->mipi_clock_voltage = clk_volt;
+
ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
fwnode_handle_put(ep);
if (ret)
return ret;
- /* Optional indication of MIPI clock voltage unit */
- ret = fwnode_property_read_u32(ep, "ovti,mipi-clock-voltage",
- &clk_volt);
-
- if (!ret)
- ov02a10->mipi_clock_voltage = clk_volt;
-
for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); i++) {
for (j = 0; j < bus_cfg.nr_of_link_frequencies; j++) {
if (link_freq_menu_items[i] ==
diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c
index c2e02f191816..b4e14171556f 100644
--- a/drivers/media/i2c/ov7740.c
+++ b/drivers/media/i2c/ov7740.c
@@ -1116,18 +1116,14 @@ static void ov7740_remove(struct i2c_client *client)
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
- mutex_destroy(&ov7740->mutex);
- v4l2_ctrl_handler_free(ov7740->subdev.ctrl_handler);
- media_entity_cleanup(&ov7740->subdev.entity);
v4l2_async_unregister_subdev(sd);
+ media_entity_cleanup(&ov7740->subdev.entity);
ov7740_free_controls(ov7740);
- pm_runtime_get_sync(&client->dev);
pm_runtime_disable(&client->dev);
+ if (!pm_runtime_status_suspended(&client->dev))
+ ov7740_set_power(ov7740, 0);
pm_runtime_set_suspended(&client->dev);
- pm_runtime_put_noidle(&client->dev);
-
- ov7740_set_power(ov7740, 0);
}
static int __maybe_unused ov7740_runtime_suspend(struct device *dev)
diff --git a/drivers/media/pci/ddbridge/ddbridge.h b/drivers/media/pci/ddbridge/ddbridge.h
index f01ecdb0b627..cf50898f9a92 100644
--- a/drivers/media/pci/ddbridge/ddbridge.h
+++ b/drivers/media/pci/ddbridge/ddbridge.h
@@ -14,7 +14,7 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dvb/ca.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/interrupt.h>
diff --git a/drivers/media/pci/hws/hws_v4l2_ioctl.h b/drivers/media/pci/hws/hws_v4l2_ioctl.h
index 53044f78d6fa..9a81e940e33e 100644
--- a/drivers/media/pci/hws/hws_v4l2_ioctl.h
+++ b/drivers/media/pci/hws/hws_v4l2_ioctl.h
@@ -17,14 +17,10 @@ int hws_vidioc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *setfp
int hws_vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *i);
int hws_vidioc_g_input(struct file *file, void *priv, unsigned int *i);
int hws_vidioc_s_input(struct file *file, void *priv, unsigned int i);
-int hws_vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *a);
-int hws_vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a);
int hws_vidioc_dv_timings_cap(struct file *file, void *fh,
struct v4l2_dv_timings_cap *cap);
int hws_vidioc_s_dv_timings(struct file *file, void *fh,
struct v4l2_dv_timings *timings);
-
-int hws_vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *a);
int hws_vidioc_g_dv_timings(struct file *file, void *fh,
struct v4l2_dv_timings *timings);
int hws_vidioc_enum_dv_timings(struct file *file, void *fh,
diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c
index 88581a4c081d..50818a10168e 100644
--- a/drivers/media/pci/intel/ipu-bridge.c
+++ b/drivers/media/pci/intel/ipu-bridge.c
@@ -97,6 +97,8 @@ static const struct ipu_sensor_config ipu_supported_sensors[] = {
IPU_SENSOR_CONFIG("OVTI8856", 3, 180000000, 360000000, 720000000),
/* Sony IMX471 */
IPU_SENSOR_CONFIG("SONY471A", 1, 200000000),
+ /* Sony IMX471 (found on Lenovo X1 Carbon G14) */
+ IPU_SENSOR_CONFIG("TBE20A0", 1, 200000000),
/* Toshiba T4KA3 */
IPU_SENSOR_CONFIG("XMCC0003", 1, 321468000),
};
@@ -134,6 +136,45 @@ static const struct dmi_system_id upside_down_sensor_dmi_ids[] = {
},
.driver_data = "OVTI02C1",
},
+ /*
+ * The first four characters of DMI_BOARD_NAME identify the Lenovo
+ * machine type/model. For example, a DMI_BOARD_NAME starting with
+ * "21Q6" indicates a ThinkPad X9-15.
+ *
+ * Reference: https://psref.lenovo.com/
+ */
+ {
+ /* Lenovo X9-14 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_BOARD_NAME, "21QA"),
+ },
+ .driver_data = "SONY471A",
+ },
+ {
+ /* Lenovo X9-14 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_BOARD_NAME, "21QB"),
+ },
+ .driver_data = "SONY471A",
+ },
+ {
+ /* Lenovo X9-15 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_BOARD_NAME, "21Q6"),
+ },
+ .driver_data = "SONY471A",
+ },
+ {
+ /* Lenovo X9-15 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_BOARD_NAME, "21Q7"),
+ },
+ .driver_data = "SONY471A",
+ },
{} /* Terminating entry */
};
@@ -171,6 +212,7 @@ static const struct acpi_device_id ivsc_acpi_ids[] = {
{ "INTC10DE" }, /* LNL */
{ "INTC10E0" }, /* ARL */
{ "INTC10E1" }, /* PTL */
+ { "INTC10FA" }, /* NVL */
};
static struct acpi_device *ipu_bridge_get_ivsc_acpi_dev(struct acpi_device *adev)
diff --git a/drivers/media/platform/samsung/s3c-camif/camif-core.c b/drivers/media/platform/samsung/s3c-camif/camif-core.c
index 221e3c447f36..14eedd1ceb27 100644
--- a/drivers/media/platform/samsung/s3c-camif/camif-core.c
+++ b/drivers/media/platform/samsung/s3c-camif/camif-core.c
@@ -12,7 +12,6 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/errno.h>
-#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -412,7 +411,7 @@ static int s3c_camif_probe(struct platform_device *pdev)
camif->dev = dev;
- if (!pdata || !pdata->gpio_get || !pdata->gpio_put) {
+ if (!pdata) {
dev_err(dev, "wrong platform data\n");
return -EINVAL;
}
@@ -429,9 +428,7 @@ static int s3c_camif_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
- ret = pdata->gpio_get();
- if (ret < 0)
- return ret;
+ /* FIXME: get GPIOs here */
ret = s3c_camif_create_subdev(camif);
if (ret < 0)
@@ -504,14 +501,12 @@ err_disable:
err_clk:
s3c_camif_unregister_subdev(camif);
err_sd:
- pdata->gpio_put();
return ret;
}
static void s3c_camif_remove(struct platform_device *pdev)
{
struct camif_dev *camif = platform_get_drvdata(pdev);
- struct s3c_camif_plat_data *pdata = &camif->pdata;
media_device_unregister(&camif->media_dev);
media_device_cleanup(&camif->media_dev);
@@ -521,7 +516,6 @@ static void s3c_camif_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
camif_clk_put(camif);
s3c_camif_unregister_subdev(camif);
- pdata->gpio_put();
}
static int s3c_camif_runtime_resume(struct device *dev)
diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c
index 57edb42463e8..358a66ab8e48 100644
--- a/drivers/media/usb/airspy/airspy.c
+++ b/drivers/media/usb/airspy/airspy.c
@@ -464,14 +464,21 @@ static void airspy_disconnect(struct usb_interface *intf)
dev_dbg(s->dev, "\n");
- mutex_lock(&s->vb_queue_lock);
+ /*
+ * vb2_video_unregister_device() releases the vb2 queue, which
+ * triggers airspy_stop_streaming() if streaming is active.
+ * stop_streaming() dereferences s->udev via airspy_ctrl_msg() and
+ * airspy_free_stream_bufs(), so it must run before s->udev is
+ * cleared. vb2_video_unregister_device() locks vb_queue_lock
+ * internally and stop_streaming() locks v4l2_lock, so neither may
+ * be held by the caller.
+ */
+ v4l2_device_disconnect(&s->v4l2_dev);
+ vb2_video_unregister_device(&s->vdev);
+
mutex_lock(&s->v4l2_lock);
- /* No need to keep the urbs around after disconnection */
s->udev = NULL;
- v4l2_device_disconnect(&s->v4l2_dev);
- video_unregister_device(&s->vdev);
mutex_unlock(&s->v4l2_lock);
- mutex_unlock(&s->vb_queue_lock);
v4l2_device_put(&s->v4l2_dev);
}
diff --git a/drivers/media/usb/cx231xx/cx231xx-audio.c b/drivers/media/usb/cx231xx/cx231xx-audio.c
index 9c71b32552df..b24ceef497e4 100644
--- a/drivers/media/usb/cx231xx/cx231xx-audio.c
+++ b/drivers/media/usb/cx231xx/cx231xx-audio.c
@@ -443,6 +443,11 @@ static int snd_cx231xx_pcm_close(struct snd_pcm_substream *substream)
int ret;
struct cx231xx *dev = snd_pcm_substream_chip(substream);
+ if (!dev) {
+ pr_err("cx231xx: called with null device\n");
+ return -ENODEV;
+ }
+
dev_dbg(dev->dev, "closing device\n");
/* inform hardware to stop streaming */
diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c
index 2cd4e333bc4b..70aa99fead27 100644
--- a/drivers/media/usb/cx231xx/cx231xx-video.c
+++ b/drivers/media/usb/cx231xx/cx231xx-video.c
@@ -898,7 +898,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
if (rc)
return rc;
- if (vb2_is_busy(&dev->vidq)) {
+ if (vb2_is_busy(&dev->vidq) || vb2_is_busy(&dev->vbiq)) {
dev_err(dev->dev, "%s: queue busy\n", __func__);
return -EBUSY;
}
@@ -933,7 +933,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
if (dev->norm == norm)
return 0;
- if (vb2_is_busy(&dev->vidq))
+ if (vb2_is_busy(&dev->vidq) || vb2_is_busy(&dev->vbiq))
return -EBUSY;
dev->norm = norm;
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index fbfb74eab475..e3c0f5e491e3 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -2677,6 +2677,28 @@ const struct em28xx_board em28xx_boards[] = {
.gpio = mygica_utv3_tuner_audio_gpio,
} },
},
+ /* eb1a:8286 StarTech SVID2USB232
+ * Empia EM28281 with integrated TVP5150-compatible video decoder.
+ * Composite and S-Video inputs, stereo line-in audio.
+ */
+ [EM28281_BOARD_STARTECH_SVID2USB232] = {
+ .name = "StarTech SVID2USB232",
+ .vchannels = 2,
+ .tuner_type = TUNER_ABSENT,
+ .has_dvb = 0,
+ .decoder = EM28XX_BUILTIN,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ,
+ .xclk = EM28XX_XCLK_FREQUENCY_12MHZ,
+ .input = { {
+ .type = EM28XX_VMUX_COMPOSITE,
+ .vmux = EM2828X_COMPOSITE,
+ .amux = EM28XX_AMUX_LINE_IN,
+ }, {
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = EM2828X_SVIDEO,
+ .amux = EM28XX_AMUX_LINE_IN,
+ } },
+ },
[EM2828X_BOARD_HAUPPAUGE_USB_LIVE2] = {
.name = "Hauppauge USB Live2",
.vchannels = 2,
@@ -2946,6 +2968,8 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM2874_BOARD_HAUPPAUGE_USB_QUADHD },
{ USB_DEVICE(0x2040, 0xc220),
.driver_info = EM2828X_BOARD_HAUPPAUGE_USB_LIVE2 },
+ { USB_DEVICE(0xeb1a, 0x8286),
+ .driver_info = EM28281_BOARD_STARTECH_SVID2USB232 },
{ USB_DEVICE(0x2040, 0x0360),
.driver_info = EM2828X_BOARD_HAUPPAUGE_935_V2 },
{ USB_DEVICE(0x2040, 0x8360),
@@ -3859,6 +3883,11 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
dev->wait_after_write = 0;
dev->eeprom_addrwidth_16bit = 1;
break;
+ case CHIP_ID_EM28281:
+ chip_name = "em28281";
+ dev->wait_after_write = 0;
+ dev->eeprom_addrwidth_16bit = 1;
+ break;
case CHIP_ID_EM2883:
chip_name = "em2882/3";
dev->wait_after_write = 0;
diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
index 938f1980d448..8482fc4045ea 100644
--- a/drivers/media/usb/em28xx/em28xx-dvb.c
+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
@@ -29,7 +29,7 @@
#include <media/dmxdev.h>
#include <media/tuner.h>
#include "tuner-simple.h"
-#include <linux/gpio.h>
+#include <linux/gpio/legacy.h>
#include "lgdt330x.h"
#include "lgdt3305.h"
diff --git a/drivers/media/usb/em28xx/em28xx-reg.h b/drivers/media/usb/em28xx/em28xx-reg.h
index 68a0fcc2fa72..8931733a8e24 100644
--- a/drivers/media/usb/em28xx/em28xx-reg.h
+++ b/drivers/media/usb/em28xx/em28xx-reg.h
@@ -283,6 +283,7 @@ enum em28xx_chip_id {
CHIP_ID_EM2884 = 68,
CHIP_ID_EM28174 = 113,
CHIP_ID_EM28178 = 114,
+ CHIP_ID_EM28281 = 145,
CHIP_ID_EM2828X = 148,
};
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index 711f281613f5..b26f2d4a228d 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -150,6 +150,7 @@
#define EM2828X_BOARD_HAUPPAUGE_955_V2 110
#define EM2828X_BOARD_HAUPPAUGE_975_V2 111
#define EM28178_BOARD_PCTV_461E_V3 112
+#define EM28281_BOARD_STARTECH_SVID2USB232 113
/* Limits minimum and default number of buffers */
#define EM28XX_MIN_BUF 4
diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c
index ec80ea9cc173..458ce99916ad 100644
--- a/drivers/memory/tegra/mc.c
+++ b/drivers/memory/tegra/mc.c
@@ -3,6 +3,7 @@
* Copyright (C) 2014-2026 NVIDIA CORPORATION. All rights reserved.
*/
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
@@ -10,6 +11,7 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
@@ -22,6 +24,9 @@
#include "mc.h"
+static DEFINE_MUTEX(tegra_mc_debugfs_root_lock);
+static struct dentry *tegra_mc_debugfs_root;
+
static const struct of_device_id tegra_mc_of_match[] = {
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
{ .compatible = "nvidia,tegra20-mc-gart", .data = &tegra20_mc_soc },
@@ -598,6 +603,13 @@ irqreturn_t tegra30_mc_handle_irq(int irq, void *data)
if (!status)
return IRQ_NONE;
+ if (!mc->soc->regs) {
+ dev_err_ratelimited(mc->dev,
+ "MC error interrupt 0x%08lx with no error register map, Clearing.\n",
+ status);
+ goto clear;
+ }
+
for_each_set_bit(bit, &status, 32) {
const char *error = tegra_mc_status_names[bit] ?: "unknown";
const char *client = "unknown", *desc;
@@ -736,6 +748,7 @@ irqreturn_t tegra30_mc_handle_irq(int irq, void *data)
desc, perm);
}
+clear:
/* clear interrupts */
if (mc->soc->num_channels) {
mc_ch_writel(mc, channel, status, MC_INTSTATUS);
@@ -778,7 +791,7 @@ struct icc_node *tegra_mc_icc_xlate(const struct of_phandle_args *spec, void *da
struct icc_node *node;
list_for_each_entry(node, &mc->provider.nodes, node_list) {
- if (node->id == spec->args[0])
+ if (tegra_mc_client_id_from_node(node) == spec->args[0])
return node;
}
@@ -834,6 +847,7 @@ const struct tegra_mc_icc_ops tegra_mc_icc_ops = {
*/
static int tegra_mc_interconnect_setup(struct tegra_mc *mc)
{
+ int node_id = dev_to_node(mc->dev);
struct icc_node *node;
unsigned int i;
int err;
@@ -854,31 +868,40 @@ static int tegra_mc_interconnect_setup(struct tegra_mc *mc)
icc_provider_init(&mc->provider);
/* create Memory Controller node */
- node = icc_node_create(TEGRA_ICC_MC);
+ node = tegra_mc_icc_node_create(node_id, TEGRA_ICC_MC);
if (IS_ERR(node))
return PTR_ERR(node);
- node->name = "Memory Controller";
+ if (node_id == NUMA_NO_NODE)
+ node->name = "Memory Controller";
+ else
+ node->name = dev_name(mc->dev);
+
icc_node_add(node, &mc->provider);
/* link Memory Controller to External Memory Controller */
- err = icc_link_create(node, TEGRA_ICC_EMC);
+ err = tegra_mc_icc_link_create(node, node_id, TEGRA_ICC_EMC);
if (err)
goto remove_nodes;
for (i = 0; i < mc->soc->num_clients; i++) {
/* create MC client node */
- node = icc_node_create(mc->soc->clients[i].id);
+ node = tegra_mc_icc_node_create(node_id, mc->soc->clients[i].id);
if (IS_ERR(node)) {
err = PTR_ERR(node);
goto remove_nodes;
}
- node->name = mc->soc->clients[i].name;
+ if (node_id == NUMA_NO_NODE)
+ node->name = mc->soc->clients[i].name;
+ else
+ node->name = devm_kasprintf(mc->dev, GFP_KERNEL, "%d-%s",
+ node_id, mc->soc->clients[i].name);
+
icc_node_add(node, &mc->provider);
/* link Memory Client to Memory Controller */
- err = icc_link_create(node, TEGRA_ICC_MC);
+ err = tegra_mc_icc_link_create(node, node_id, TEGRA_ICC_MC);
if (err)
goto remove_nodes;
@@ -957,7 +980,16 @@ static int tegra_mc_probe(struct platform_device *pdev)
if (IS_ERR(mc->regs))
return PTR_ERR(mc->regs);
- mc->debugfs.root = debugfs_create_dir("mc", NULL);
+ scoped_guard(mutex, &tegra_mc_debugfs_root_lock) {
+ if (!tegra_mc_debugfs_root)
+ tegra_mc_debugfs_root = debugfs_create_dir("mc", NULL);
+
+ if (dev_to_node(mc->dev) == NUMA_NO_NODE)
+ mc->debugfs.root = tegra_mc_debugfs_root;
+ else
+ mc->debugfs.root = debugfs_create_dir(dev_name(mc->dev),
+ tegra_mc_debugfs_root);
+ }
if (mc->soc->ops && mc->soc->ops->probe) {
err = mc->soc->ops->probe(mc);
diff --git a/drivers/memory/tegra/mc.h b/drivers/memory/tegra/mc.h
index e94d265d7b67..01499292dd5f 100644
--- a/drivers/memory/tegra/mc.h
+++ b/drivers/memory/tegra/mc.h
@@ -8,6 +8,7 @@
#include <linux/bits.h>
#include <linux/io.h>
+#include <linux/numa.h>
#include <linux/types.h>
#include <soc/tegra/mc.h>
@@ -167,6 +168,42 @@ icc_provider_to_tegra_mc(struct icc_provider *provider)
return container_of(provider, struct tegra_mc, provider);
}
+/*
+ * Compose a globally-unique ICC node ID. On single-socket
+ * systems (NUMA_NO_NODE), the SoC client ID is returned unchanged.
+ * On multi-socket systems, the NUMA node ID is encoded in the
+ * upper bits of the returned ID.
+ *
+ * The client ID field is sized to keep composed IDs below
+ * ICC_DYN_ID_START (the start of the ICC core's dynamic-ID range).
+ */
+#define TEGRA_MC_CLIENT_ID_BITS 12
+#define TEGRA_MC_CLIENT_ID_MASK ((1U << TEGRA_MC_CLIENT_ID_BITS) - 1)
+
+static inline u32 tegra_mc_get_client_id(int node_id, int id)
+{
+ if (node_id == NUMA_NO_NODE)
+ return id;
+
+ return ((node_id + 1) << TEGRA_MC_CLIENT_ID_BITS) | id;
+}
+
+static inline struct icc_node *tegra_mc_icc_node_create(int node_id, int id)
+{
+ return icc_node_create(tegra_mc_get_client_id(node_id, id));
+}
+
+static inline int tegra_mc_icc_link_create(struct icc_node *node, int node_id, int id)
+{
+ return icc_link_create(node, tegra_mc_get_client_id(node_id, id));
+}
+
+/* Return the SoC client ID encoded in an ICC node ID. */
+static inline u32 tegra_mc_client_id_from_node(const struct icc_node *node)
+{
+ return node->id & TEGRA_MC_CLIENT_ID_MASK;
+}
+
static inline u32 mc_ch_readl(const struct tegra_mc *mc, int ch,
unsigned long offset)
{
diff --git a/drivers/memory/tegra/tegra186-emc.c b/drivers/memory/tegra/tegra186-emc.c
index 2a4cb64c4c4c..c9583b66f18d 100644
--- a/drivers/memory/tegra/tegra186-emc.c
+++ b/drivers/memory/tegra/tegra186-emc.c
@@ -3,15 +3,21 @@
* Copyright (C) 2019-2025 NVIDIA CORPORATION. All rights reserved.
*/
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/debugfs.h>
+#include <linux/fs.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <soc/tegra/bpmp.h>
#include "mc.h"
+static DEFINE_MUTEX(tegra_emc_debugfs_root_lock);
+static struct dentry *tegra_emc_debugfs_root;
+
struct tegra186_emc_dvfs {
unsigned long latency;
unsigned long rate;
@@ -206,7 +212,17 @@ static int tegra186_emc_get_emc_dvfs_latency(struct tegra186_emc *emc)
return err;
}
- emc->debugfs.root = debugfs_create_dir("emc", NULL);
+ scoped_guard(mutex, &tegra_emc_debugfs_root_lock) {
+ if (!tegra_emc_debugfs_root)
+ tegra_emc_debugfs_root = debugfs_create_dir("emc", NULL);
+
+ if (dev_to_node(emc->dev) == NUMA_NO_NODE)
+ emc->debugfs.root = tegra_emc_debugfs_root;
+ else
+ emc->debugfs.root = debugfs_create_dir(dev_name(emc->dev),
+ tegra_emc_debugfs_root);
+ }
+
debugfs_create_file("available_rates", 0444, emc->debugfs.root, emc,
&tegra186_emc_debug_available_rates_fops);
debugfs_create_file("min_rate", 0644, emc->debugfs.root, emc,
@@ -238,7 +254,7 @@ tegra186_emc_of_icc_xlate(const struct of_phandle_args *spec, void *data)
/* External Memory is the only possible ICC route */
list_for_each_entry(node, &provider->nodes, node_list) {
- if (node->id != TEGRA_ICC_EMEM)
+ if (tegra_mc_client_id_from_node(node) != TEGRA_ICC_EMEM)
continue;
return node;
@@ -257,6 +273,7 @@ static int tegra186_emc_icc_get_init_bw(struct icc_node *node, u32 *avg, u32 *pe
static int tegra186_emc_interconnect_init(struct tegra186_emc *emc)
{
+ int node_id = dev_to_node(emc->dev->parent);
struct icc_node *node;
int err;
@@ -270,26 +287,36 @@ static int tegra186_emc_interconnect_init(struct tegra186_emc *emc)
icc_provider_init(&emc->provider);
/* create External Memory Controller node */
- node = icc_node_create(TEGRA_ICC_EMC);
- if (IS_ERR(node))
- return PTR_ERR(node);
+ node = tegra_mc_icc_node_create(node_id, TEGRA_ICC_EMC);
+ if (IS_ERR(node)) {
+ err = PTR_ERR(node);
+ goto remove_nodes;
+ }
+
+ if (node_id == NUMA_NO_NODE)
+ node->name = "External Memory Controller";
+ else
+ node->name = dev_name(emc->dev);
- node->name = "External Memory Controller";
icc_node_add(node, &emc->provider);
/* link External Memory Controller to External Memory (DRAM) */
- err = icc_link_create(node, TEGRA_ICC_EMEM);
+ err = tegra_mc_icc_link_create(node, node_id, TEGRA_ICC_EMEM);
if (err)
goto remove_nodes;
/* create External Memory node */
- node = icc_node_create(TEGRA_ICC_EMEM);
+ node = tegra_mc_icc_node_create(node_id, TEGRA_ICC_EMEM);
if (IS_ERR(node)) {
err = PTR_ERR(node);
goto remove_nodes;
}
- node->name = "External Memory (DRAM)";
+ if (node_id == NUMA_NO_NODE)
+ node->name = "External Memory (DRAM)";
+ else
+ node->name = devm_kasprintf(emc->dev, GFP_KERNEL, "%d-dram", node_id);
+
icc_node_add(node, &emc->provider);
err = icc_provider_register(&emc->provider);
@@ -382,6 +409,16 @@ static void tegra186_emc_remove(struct platform_device *pdev)
debugfs_remove_recursive(emc->debugfs.root);
+ scoped_guard(mutex, &tegra_emc_debugfs_root_lock) {
+ if (emc->debugfs.root == tegra_emc_debugfs_root) {
+ tegra_emc_debugfs_root = NULL;
+ } else if (tegra_emc_debugfs_root &&
+ simple_empty(tegra_emc_debugfs_root)) {
+ debugfs_remove(tegra_emc_debugfs_root);
+ tegra_emc_debugfs_root = NULL;
+ }
+ }
+
mc->bpmp = NULL;
tegra_bpmp_put(emc->bpmp);
}
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index f0bc0b5a6f4a..86fa99022cb3 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -19,7 +19,7 @@
#include <linux/mfd/core.h>
#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500/ab8500.h>
-#include <linux/mfd/dbx500-prcmu.h>
+#include <linux/mfd/db8500-prcmu.h>
#include <linux/of.h>
/*
diff --git a/drivers/mfd/altera-a10sr.c b/drivers/mfd/altera-a10sr.c
index d53e433ab5c1..9c0262228655 100644
--- a/drivers/mfd/altera-a10sr.c
+++ b/drivers/mfd/altera-a10sr.c
@@ -155,7 +155,7 @@ MODULE_DEVICE_TABLE(of, altr_a10sr_spi_of_match);
static const struct spi_device_id altr_a10sr_spi_ids[] = {
{ .name = "a10sr" },
- { },
+ { }
};
MODULE_DEVICE_TABLE(spi, altr_a10sr_spi_ids);
diff --git a/drivers/mfd/arizona-spi.c b/drivers/mfd/arizona-spi.c
index eaa2b2bc5dd0..04baf5a1c652 100644
--- a/drivers/mfd/arizona-spi.c
+++ b/drivers/mfd/arizona-spi.c
@@ -255,12 +255,12 @@ static void arizona_spi_remove(struct spi_device *spi)
}
static const struct spi_device_id arizona_spi_ids[] = {
- { "wm5102", WM5102 },
- { "wm5110", WM5110 },
- { "wm8280", WM8280 },
- { "wm1831", WM1831 },
- { "cs47l24", CS47L24 },
- { },
+ { .name = "wm5102", .driver_data = WM5102 },
+ { .name = "wm5110", .driver_data = WM5110 },
+ { .name = "wm8280", .driver_data = WM8280 },
+ { .name = "wm1831", .driver_data = WM1831 },
+ { .name = "cs47l24", .driver_data = CS47L24 },
+ { }
};
MODULE_DEVICE_TABLE(spi, arizona_spi_ids);
diff --git a/drivers/mfd/cs40l50-spi.c b/drivers/mfd/cs40l50-spi.c
index 53526b595a0d..a635951ca6b7 100644
--- a/drivers/mfd/cs40l50-spi.c
+++ b/drivers/mfd/cs40l50-spi.c
@@ -40,8 +40,8 @@ static void cs40l50_spi_remove(struct spi_device *spi)
}
static const struct spi_device_id cs40l50_id_spi[] = {
- { "cs40l50" },
- {}
+ { .name = "cs40l50" },
+ { }
};
MODULE_DEVICE_TABLE(spi, cs40l50_id_spi);
diff --git a/drivers/mfd/da9052-spi.c b/drivers/mfd/da9052-spi.c
index be5f2b34e18a..29cf2c17fde1 100644
--- a/drivers/mfd/da9052-spi.c
+++ b/drivers/mfd/da9052-spi.c
@@ -63,12 +63,12 @@ static void da9052_spi_remove(struct spi_device *spi)
}
static const struct spi_device_id da9052_spi_id[] = {
- {"da9052", DA9052},
- {"da9053-aa", DA9053_AA},
- {"da9053-ba", DA9053_BA},
- {"da9053-bb", DA9053_BB},
- {"da9053-bc", DA9053_BC},
- {}
+ { .name = "da9052", .driver_data = DA9052 },
+ { .name = "da9053-aa", .driver_data = DA9053_AA },
+ { .name = "da9053-ba", .driver_data = DA9053_BA },
+ { .name = "da9053-bb", .driver_data = DA9053_BB },
+ { .name = "da9053-bc", .driver_data = DA9053_BC },
+ { }
};
static struct spi_driver da9052_spi_driver = {
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c
index 21e68a382b11..6672c55f2ebc 100644
--- a/drivers/mfd/db8500-prcmu.c
+++ b/drivers/mfd/db8500-prcmu.c
@@ -32,7 +32,7 @@
#include <linux/platform_device.h>
#include <linux/uaccess.h>
#include <linux/mfd/core.h>
-#include <linux/mfd/dbx500-prcmu.h>
+#include <linux/mfd/db8500-prcmu.h>
#include <linux/mfd/abx500/ab8500.h>
#include <linux/regulator/db8500-prcmu.h>
#include <linux/regulator/machine.h>
@@ -2285,7 +2285,7 @@ void db8500_prcmu_system_reset(u16 reset_code)
/**
* db8500_prcmu_get_reset_code - Retrieve SW reset reason code
*
- * Retrieves the reset reason code stored by prcmu_system_reset() before
+ * Retrieves the reset reason code stored by db8500_prcmu_system_reset() before
* last restart.
*/
u16 db8500_prcmu_get_reset_code(void)
@@ -3041,7 +3041,7 @@ static int db8500_prcmu_probe(struct platform_device *pdev)
db8500_irq_init(np);
- prcmu_config_esram0_deep_sleep(ESRAM0_DEEP_SLEEP_STATE_RET);
+ db8500_prcmu_config_esram0_deep_sleep(ESRAM0_DEEP_SLEEP_STATE_RET);
err = mfd_add_devices(&pdev->dev, 0, common_prcmu_devs,
ARRAY_SIZE(common_prcmu_devs), NULL, 0, db8500_irq_domain);
diff --git a/drivers/mfd/intel-m10-bmc-spi.c b/drivers/mfd/intel-m10-bmc-spi.c
index cfa620f0c70e..94b9c99bb4f8 100644
--- a/drivers/mfd/intel-m10-bmc-spi.c
+++ b/drivers/mfd/intel-m10-bmc-spi.c
@@ -160,9 +160,9 @@ static const struct intel_m10bmc_platform_info m10bmc_spi_n5010 = {
};
static const struct spi_device_id m10bmc_spi_id[] = {
- { "m10-n3000", (kernel_ulong_t)&m10bmc_spi_n3000 },
- { "m10-d5005", (kernel_ulong_t)&m10bmc_spi_d5005 },
- { "m10-n5010", (kernel_ulong_t)&m10bmc_spi_n5010 },
+ { .name = "m10-n3000", .driver_data = (kernel_ulong_t)&m10bmc_spi_n3000 },
+ { .name = "m10-d5005", .driver_data = (kernel_ulong_t)&m10bmc_spi_d5005 },
+ { .name = "m10-n5010", .driver_data = (kernel_ulong_t)&m10bmc_spi_n5010 },
{ }
};
MODULE_DEVICE_TABLE(spi, m10bmc_spi_id);
diff --git a/drivers/mfd/madera-spi.c b/drivers/mfd/madera-spi.c
index ce9e90322c9c..3fffa21ceadc 100644
--- a/drivers/mfd/madera-spi.c
+++ b/drivers/mfd/madera-spi.c
@@ -112,15 +112,15 @@ static void madera_spi_remove(struct spi_device *spi)
}
static const struct spi_device_id madera_spi_ids[] = {
- { "cs47l15", CS47L15 },
- { "cs47l35", CS47L35 },
- { "cs47l85", CS47L85 },
- { "cs47l90", CS47L90 },
- { "cs47l91", CS47L91 },
- { "cs42l92", CS42L92 },
- { "cs47l92", CS47L92 },
- { "cs47l93", CS47L93 },
- { "wm1840", WM1840 },
+ { .name = "cs47l15", .driver_data = CS47L15 },
+ { .name = "cs47l35", .driver_data = CS47L35 },
+ { .name = "cs47l85", .driver_data = CS47L85 },
+ { .name = "cs47l90", .driver_data = CS47L90 },
+ { .name = "cs47l91", .driver_data = CS47L91 },
+ { .name = "cs42l92", .driver_data = CS42L92 },
+ { .name = "cs47l92", .driver_data = CS47L92 },
+ { .name = "cs47l93", .driver_data = CS47L93 },
+ { .name = "wm1840", .driver_data = WM1840 },
{ }
};
MODULE_DEVICE_TABLE(spi, madera_spi_ids);
diff --git a/drivers/mfd/motorola-cpcap.c b/drivers/mfd/motorola-cpcap.c
index feeccb2c6655..4ed8704c985a 100644
--- a/drivers/mfd/motorola-cpcap.c
+++ b/drivers/mfd/motorola-cpcap.c
@@ -202,9 +202,9 @@ static const struct of_device_id cpcap_of_match[] = {
MODULE_DEVICE_TABLE(of, cpcap_of_match);
static const struct spi_device_id cpcap_spi_ids[] = {
- { .name = "cpcap", },
- { .name = "6556002", },
- {},
+ { .name = "cpcap" },
+ { .name = "6556002" },
+ { }
};
MODULE_DEVICE_TABLE(spi, cpcap_spi_ids);
diff --git a/drivers/mfd/ocelot-spi.c b/drivers/mfd/ocelot-spi.c
index fc30663824bb..d3ab4868a523 100644
--- a/drivers/mfd/ocelot-spi.c
+++ b/drivers/mfd/ocelot-spi.c
@@ -270,7 +270,7 @@ static int ocelot_spi_probe(struct spi_device *spi)
}
static const struct spi_device_id ocelot_spi_ids[] = {
- { "vsc7512", 0 },
+ { .name = "vsc7512" },
{ }
};
MODULE_DEVICE_TABLE(spi, ocelot_spi_ids);
diff --git a/drivers/mfd/rk8xx-spi.c b/drivers/mfd/rk8xx-spi.c
index 3405fb82ff9f..bb85fe60518f 100644
--- a/drivers/mfd/rk8xx-spi.c
+++ b/drivers/mfd/rk8xx-spi.c
@@ -104,7 +104,7 @@ static const struct of_device_id rk8xx_spi_of_match[] = {
MODULE_DEVICE_TABLE(of, rk8xx_spi_of_match);
static const struct spi_device_id rk8xx_spi_id_table[] = {
- { "rk806", 0 },
+ { .name = "rk806" },
{ }
};
MODULE_DEVICE_TABLE(spi, rk8xx_spi_id_table);
diff --git a/drivers/mfd/rsmu_spi.c b/drivers/mfd/rsmu_spi.c
index e07f21482439..cdb0f9797ec6 100644
--- a/drivers/mfd/rsmu_spi.c
+++ b/drivers/mfd/rsmu_spi.c
@@ -239,12 +239,12 @@ static void rsmu_spi_remove(struct spi_device *client)
}
static const struct spi_device_id rsmu_spi_id[] = {
- { "8a34000", RSMU_CM },
- { "8a34001", RSMU_CM },
- { "8a34002", RSMU_CM },
- { "82p33810", RSMU_SABRE },
- { "82p33811", RSMU_SABRE },
- {}
+ { .name = "8a34000", .driver_data = RSMU_CM },
+ { .name = "8a34001", .driver_data = RSMU_CM },
+ { .name = "8a34002", .driver_data = RSMU_CM },
+ { .name = "82p33810", .driver_data = RSMU_SABRE },
+ { .name = "82p33811", .driver_data = RSMU_SABRE },
+ { }
};
MODULE_DEVICE_TABLE(spi, rsmu_spi_id);
diff --git a/drivers/mfd/sprd-sc27xx-spi.c b/drivers/mfd/sprd-sc27xx-spi.c
index aa052f646623..9a8e6add8fca 100644
--- a/drivers/mfd/sprd-sc27xx-spi.c
+++ b/drivers/mfd/sprd-sc27xx-spi.c
@@ -61,6 +61,7 @@ static const struct mfd_cell sc2730_devices[] = {
MFD_CELL_OF("sc2730-efuse", NULL, NULL, 0, 0, "sprd,sc2730-efuse"),
MFD_CELL_OF("sc2730-eic", NULL, NULL, 0, 0, "sprd,sc2730-eic"),
MFD_CELL_OF("sc2730-fgu", NULL, NULL, 0, 0, "sprd,sc2730-fgu"),
+ MFD_CELL_NAME("sc2730-regulator"),
MFD_CELL_OF("sc2730-rtc", NULL, NULL, 0, 0, "sprd,sc2730-rtc"),
MFD_CELL_OF("sc2730-vibrator", NULL, NULL, 0, 0, "sprd,sc2730-vibrator"),
};
@@ -294,7 +295,7 @@ MODULE_DEVICE_TABLE(of, sprd_pmic_match);
static const struct spi_device_id sprd_pmic_spi_ids[] = {
{ .name = "sc2730", .driver_data = PMIC_TYPE_SC2730 },
{ .name = "sc2731", .driver_data = PMIC_TYPE_SC2731 },
- {},
+ { }
};
MODULE_DEVICE_TABLE(spi, sprd_pmic_spi_ids);
diff --git a/drivers/mfd/stmpe-spi.c b/drivers/mfd/stmpe-spi.c
index dea31efface6..22a3da062dee 100644
--- a/drivers/mfd/stmpe-spi.c
+++ b/drivers/mfd/stmpe-spi.c
@@ -121,12 +121,12 @@ static const struct of_device_id stmpe_spi_of_match[] = {
MODULE_DEVICE_TABLE(of, stmpe_spi_of_match);
static const struct spi_device_id stmpe_spi_id[] = {
- { "stmpe610", STMPE610 },
- { "stmpe801", STMPE801 },
- { "stmpe811", STMPE811 },
- { "stmpe1601", STMPE1601 },
- { "stmpe2401", STMPE2401 },
- { "stmpe2403", STMPE2403 },
+ { .name = "stmpe610", .driver_data = STMPE610 },
+ { .name = "stmpe801", .driver_data = STMPE801 },
+ { .name = "stmpe811", .driver_data = STMPE811 },
+ { .name = "stmpe1601", .driver_data = STMPE1601 },
+ { .name = "stmpe2401", .driver_data = STMPE2401 },
+ { .name = "stmpe2403", .driver_data = STMPE2403 },
{ }
};
MODULE_DEVICE_TABLE(spi, stmpe_spi_id);
diff --git a/drivers/mfd/tps65912-spi.c b/drivers/mfd/tps65912-spi.c
index 2a77dccd6059..2442a2e67d67 100644
--- a/drivers/mfd/tps65912-spi.c
+++ b/drivers/mfd/tps65912-spi.c
@@ -43,7 +43,7 @@ static int tps65912_spi_probe(struct spi_device *spi)
}
static const struct spi_device_id tps65912_spi_id_table[] = {
- { "tps65912", 0 },
+ { .name = "tps65912" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(spi, tps65912_spi_id_table);
diff --git a/drivers/mfd/viperboard.c b/drivers/mfd/viperboard.c
index 888737b8e7be..36be8e69f45c 100644
--- a/drivers/mfd/viperboard.c
+++ b/drivers/mfd/viperboard.c
@@ -96,8 +96,7 @@ static int vprbrd_probe(struct usb_interface *interface,
return 0;
error:
- if (vb)
- kfree(vb);
+ kfree(vb);
return ret;
}
diff --git a/drivers/mfd/wm831x-spi.c b/drivers/mfd/wm831x-spi.c
index 54c87267917b..1e519fd9a9e1 100644
--- a/drivers/mfd/wm831x-spi.c
+++ b/drivers/mfd/wm831x-spi.c
@@ -77,14 +77,14 @@ static const struct dev_pm_ops wm831x_spi_pm = {
};
static const struct spi_device_id wm831x_spi_ids[] = {
- { "wm8310", WM8310 },
- { "wm8311", WM8311 },
- { "wm8312", WM8312 },
- { "wm8320", WM8320 },
- { "wm8321", WM8321 },
- { "wm8325", WM8325 },
- { "wm8326", WM8326 },
- { },
+ { .name = "wm8310", .driver_data = WM8310 },
+ { .name = "wm8311", .driver_data = WM8311 },
+ { .name = "wm8312", .driver_data = WM8312 },
+ { .name = "wm8320", .driver_data = WM8320 },
+ { .name = "wm8321", .driver_data = WM8321 },
+ { .name = "wm8325", .driver_data = WM8325 },
+ { .name = "wm8326", .driver_data = WM8326 },
+ { }
};
static struct spi_driver wm831x_spi_driver = {
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index e044fc733b8c..e1bec8164221 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -4857,12 +4857,6 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr)
__func__, slave);
res = dev_set_mac_address(slave->dev, addr, NULL);
if (res) {
- /* TODO: consider downing the slave
- * and retry ?
- * User should expect communications
- * breakage anyway until ARP finish
- * updating, so...
- */
slave_dbg(bond_dev, slave->dev, "%s: err %d\n",
__func__, res);
goto unwind;
diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
index fd282a1700fb..d394f1f43b68 100644
--- a/drivers/net/ethernet/cadence/macb_main.c
+++ b/drivers/net/ethernet/cadence/macb_main.c
@@ -2668,8 +2668,25 @@ static void macb_free_consistent(struct macb *bp)
dma_free_coherent(dev, size, bp->queues[0].rx_ring, bp->queues[0].rx_ring_dma);
for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
- kfree(queue->tx_skb);
- queue->tx_skb = NULL;
+ if (queue->tx_skb) {
+ unsigned int dropped = 0, tail;
+
+ for (tail = queue->tx_tail; tail != queue->tx_head;
+ tail++) {
+ if (macb_tx_skb(queue, tail)->skb)
+ dropped++;
+ macb_tx_unmap(bp, macb_tx_skb(queue, tail), 0);
+ }
+
+ queue->stats.tx_dropped += dropped;
+ bp->dev->stats.tx_dropped += dropped;
+
+ kfree(queue->tx_skb);
+ queue->tx_skb = NULL;
+ }
+
+ queue->tx_head = 0;
+ queue->tx_tail = 0;
queue->tx_ring = NULL;
queue->rx_ring = NULL;
}
diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.h b/drivers/net/ethernet/intel/igb/e1000_82575.h
index 63ec253ac788..9e696d55e512 100644
--- a/drivers/net/ethernet/intel/igb/e1000_82575.h
+++ b/drivers/net/ethernet/intel/igb/e1000_82575.h
@@ -87,6 +87,27 @@ union e1000_adv_rx_desc {
} wb; /* writeback */
};
+#define E1000_RSS_TYPE_NO_HASH 0
+#define E1000_RSS_TYPE_HASH_TCP_IPV4 1
+#define E1000_RSS_TYPE_HASH_IPV4 2
+#define E1000_RSS_TYPE_HASH_TCP_IPV6 3
+#define E1000_RSS_TYPE_HASH_IPV6_EX 4
+#define E1000_RSS_TYPE_HASH_IPV6 5
+#define E1000_RSS_TYPE_HASH_TCP_IPV6_EX 6
+#define E1000_RSS_TYPE_HASH_UDP_IPV4 7
+#define E1000_RSS_TYPE_HASH_UDP_IPV6 8
+#define E1000_RSS_TYPE_HASH_UDP_IPV6_EX 9
+
+#define E1000_RSS_TYPE_MASK GENMASK(3, 0)
+
+#define E1000_RSS_L4_TYPES_MASK \
+ (BIT(E1000_RSS_TYPE_HASH_TCP_IPV4) | \
+ BIT(E1000_RSS_TYPE_HASH_TCP_IPV6) | \
+ BIT(E1000_RSS_TYPE_HASH_TCP_IPV6_EX) | \
+ BIT(E1000_RSS_TYPE_HASH_UDP_IPV4) | \
+ BIT(E1000_RSS_TYPE_HASH_UDP_IPV6) | \
+ BIT(E1000_RSS_TYPE_HASH_UDP_IPV6_EX))
+
#define E1000_RXDADV_HDRBUFLEN_MASK 0x7FE0
#define E1000_RXDADV_HDRBUFLEN_SHIFT 5
#define E1000_RXDADV_STAT_TS 0x10000 /* Pkt was time stamped */
diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h
index 0fff1df81b7b..8c9b02058cec 100644
--- a/drivers/net/ethernet/intel/igb/igb.h
+++ b/drivers/net/ethernet/intel/igb/igb.h
@@ -495,6 +495,7 @@ struct hwmon_buff {
#define IGB_N_PEROUT 2
#define IGB_N_SDP 4
#define IGB_RETA_SIZE 128
+#define IGB_RSS_KEY_SIZE 40
enum igb_filter_match_flags {
IGB_FILTER_FLAG_ETHER_TYPE = 0x1,
@@ -655,6 +656,7 @@ struct igb_adapter {
struct i2c_client *i2c_client;
u32 rss_indir_tbl_init;
u8 rss_indir_tbl[IGB_RETA_SIZE];
+ u8 rss_key[IGB_RSS_KEY_SIZE];
unsigned long link_check_timeout;
int copper_tries;
@@ -735,6 +737,7 @@ void igb_down(struct igb_adapter *);
void igb_reinit_locked(struct igb_adapter *);
void igb_reset(struct igb_adapter *);
int igb_reinit_queues(struct igb_adapter *);
+void igb_write_rss_key(struct igb_adapter *adapter);
void igb_write_rss_indir_tbl(struct igb_adapter *);
int igb_set_spd_dplx(struct igb_adapter *, u32, u8);
int igb_setup_tx_resources(struct igb_ring *);
diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c
index f7938c1da835..65014a54a6d1 100644
--- a/drivers/net/ethernet/intel/igb/igb_ethtool.c
+++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c
@@ -3019,6 +3019,27 @@ static int igb_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
return ret;
}
+/**
+ * igb_write_rss_key - Program the RSS key into device registers
+ * @adapter: board private structure
+ *
+ * Write the RSS key stored in adapter->rss_key to the E1000 hardware registers.
+ * Each 32-bit chunk of the key is read using get_unaligned_le32() and written
+ * to the appropriate register.
+ */
+void igb_write_rss_key(struct igb_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+
+ ASSERT_RTNL();
+
+ for (int i = 0; i < IGB_RSS_KEY_SIZE / 4; i++) {
+ u32 val = get_unaligned_le32(&adapter->rss_key[i * 4]);
+
+ wr32(E1000_RSSRK(i), val);
+ }
+}
+
static int igb_get_eee(struct net_device *netdev, struct ethtool_keee *edata)
{
struct igb_adapter *adapter = netdev_priv(netdev);
@@ -3276,10 +3297,12 @@ static int igb_get_rxfh(struct net_device *netdev,
int i;
rxfh->hfunc = ETH_RSS_HASH_TOP;
- if (!rxfh->indir)
- return 0;
- for (i = 0; i < IGB_RETA_SIZE; i++)
- rxfh->indir[i] = adapter->rss_indir_tbl[i];
+ if (rxfh->indir)
+ for (i = 0; i < IGB_RETA_SIZE; i++)
+ rxfh->indir[i] = adapter->rss_indir_tbl[i];
+
+ if (rxfh->key)
+ memcpy(rxfh->key, adapter->rss_key, sizeof(adapter->rss_key));
return 0;
}
@@ -3319,6 +3342,11 @@ void igb_write_rss_indir_tbl(struct igb_adapter *adapter)
}
}
+static u32 igb_get_rxfh_key_size(struct net_device *netdev)
+{
+ return IGB_RSS_KEY_SIZE;
+}
+
static int igb_set_rxfh(struct net_device *netdev,
struct ethtool_rxfh_param *rxfh,
struct netlink_ext_ack *extack)
@@ -3329,35 +3357,39 @@ static int igb_set_rxfh(struct net_device *netdev,
u32 num_queues;
/* We do not allow change in unsupported parameters */
- if (rxfh->key ||
- (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
- rxfh->hfunc != ETH_RSS_HASH_TOP))
+ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP)
return -EOPNOTSUPP;
- if (!rxfh->indir)
- return 0;
- num_queues = adapter->rss_queues;
+ if (rxfh->indir) {
+ num_queues = adapter->rss_queues;
- switch (hw->mac.type) {
- case e1000_82576:
- /* 82576 supports 2 RSS queues for SR-IOV */
- if (adapter->vfs_allocated_count)
- num_queues = 2;
- break;
- default:
- break;
- }
+ switch (hw->mac.type) {
+ case e1000_82576:
+ /* 82576 supports 2 RSS queues for SR-IOV */
+ if (adapter->vfs_allocated_count)
+ num_queues = 2;
+ break;
+ default:
+ break;
+ }
+
+ /* Verify user input. */
+ for (i = 0; i < IGB_RETA_SIZE; i++)
+ if (rxfh->indir[i] >= num_queues)
+ return -EINVAL;
- /* Verify user input. */
- for (i = 0; i < IGB_RETA_SIZE; i++)
- if (rxfh->indir[i] >= num_queues)
- return -EINVAL;
+ for (i = 0; i < IGB_RETA_SIZE; i++)
+ adapter->rss_indir_tbl[i] = rxfh->indir[i];
- for (i = 0; i < IGB_RETA_SIZE; i++)
- adapter->rss_indir_tbl[i] = rxfh->indir[i];
+ igb_write_rss_indir_tbl(adapter);
+ }
- igb_write_rss_indir_tbl(adapter);
+ if (rxfh->key) {
+ memcpy(adapter->rss_key, rxfh->key, sizeof(adapter->rss_key));
+ igb_write_rss_key(adapter);
+ }
return 0;
}
@@ -3483,6 +3515,7 @@ static const struct ethtool_ops igb_ethtool_ops = {
.get_module_eeprom = igb_get_module_eeprom,
.get_rxfh_indir_size = igb_get_rxfh_indir_size,
.get_rxfh = igb_get_rxfh,
+ .get_rxfh_key_size = igb_get_rxfh_key_size,
.set_rxfh = igb_set_rxfh,
.get_rxfh_fields = igb_get_rxfh_fields,
.set_rxfh_fields = igb_set_rxfh_fields,
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index a1e89a375744..d4a897a8c82c 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -4048,6 +4048,9 @@ static int igb_sw_init(struct igb_adapter *adapter)
pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word);
+ /* init RSS key */
+ netdev_rss_key_fill(adapter->rss_key, sizeof(adapter->rss_key));
+
/* set default ring sizes */
adapter->tx_ring_count = IGB_DEFAULT_TXD;
adapter->rx_ring_count = IGB_DEFAULT_RXD;
@@ -4522,11 +4525,8 @@ static void igb_setup_mrqc(struct igb_adapter *adapter)
struct e1000_hw *hw = &adapter->hw;
u32 mrqc, rxcsum;
u32 j, num_rx_queues;
- u32 rss_key[10];
- netdev_rss_key_fill(rss_key, sizeof(rss_key));
- for (j = 0; j < 10; j++)
- wr32(E1000_RSSRK(j), rss_key[j]);
+ igb_write_rss_key(adapter);
num_rx_queues = adapter->rss_queues;
@@ -8820,10 +8820,19 @@ static inline void igb_rx_hash(struct igb_ring *ring,
union e1000_adv_rx_desc *rx_desc,
struct sk_buff *skb)
{
- if (ring->netdev->features & NETIF_F_RXHASH)
- skb_set_hash(skb,
- le32_to_cpu(rx_desc->wb.lower.hi_dword.rss),
- PKT_HASH_TYPE_L3);
+ u16 rss_type;
+
+ if (!(ring->netdev->features & NETIF_F_RXHASH))
+ return;
+
+ rss_type = le16_to_cpu(rx_desc->wb.lower.lo_dword.pkt_info) &
+ E1000_RSS_TYPE_MASK;
+ if (!rss_type)
+ return;
+
+ skb_set_hash(skb, le32_to_cpu(rx_desc->wb.lower.hi_dword.rss),
+ (E1000_RSS_L4_TYPES_MASK & BIT(rss_type)) ?
+ PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3);
}
/**
diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h
index 46d625b15f44..17f213cc93e4 100644
--- a/drivers/net/ethernet/intel/igc/igc.h
+++ b/drivers/net/ethernet/intel/igc/igc.h
@@ -30,6 +30,7 @@ void igc_ethtool_set_ops(struct net_device *);
#define MAX_ETYPE_FILTER 8
#define IGC_RETA_SIZE 128
+#define IGC_RSS_KEY_SIZE 40
/* SDP support */
#define IGC_N_EXTTS 2
@@ -302,6 +303,7 @@ struct igc_adapter {
unsigned int nfc_rule_count;
u8 rss_indir_tbl[IGC_RETA_SIZE];
+ u8 rss_key[IGC_RSS_KEY_SIZE];
unsigned long link_check_timeout;
struct igc_info ei;
@@ -361,6 +363,7 @@ unsigned int igc_get_max_rss_queues(struct igc_adapter *adapter);
void igc_set_flag_queue_pairs(struct igc_adapter *adapter,
const u32 max_rss_queues);
int igc_reinit_queues(struct igc_adapter *adapter);
+void igc_write_rss_key(struct igc_adapter *adapter);
void igc_write_rss_indir_tbl(struct igc_adapter *adapter);
bool igc_has_link(struct igc_adapter *adapter);
void igc_reset(struct igc_adapter *adapter);
diff --git a/drivers/net/ethernet/intel/igc/igc_base.c b/drivers/net/ethernet/intel/igc/igc_base.c
index 1613b562d17c..ab9120a3127f 100644
--- a/drivers/net/ethernet/intel/igc/igc_base.c
+++ b/drivers/net/ethernet/intel/igc/igc_base.c
@@ -114,11 +114,35 @@ static s32 igc_setup_copper_link_base(struct igc_hw *hw)
u32 ctrl;
ctrl = rd32(IGC_CTRL);
- ctrl |= IGC_CTRL_SLU;
- ctrl &= ~(IGC_CTRL_FRCSPD | IGC_CTRL_FRCDPX);
- wr32(IGC_CTRL, ctrl);
-
- ret_val = igc_setup_copper_link(hw);
+ ctrl &= ~(IGC_CTRL_FRCSPD | IGC_CTRL_FRCDPX |
+ IGC_CTRL_SPEED_MASK | IGC_CTRL_FD);
+
+ if (hw->mac.autoneg_enabled) {
+ ctrl |= IGC_CTRL_SLU;
+ wr32(IGC_CTRL, ctrl);
+ ret_val = igc_setup_copper_link(hw);
+ } else {
+ ctrl |= IGC_CTRL_SLU | IGC_CTRL_FRCSPD | IGC_CTRL_FRCDPX;
+
+ switch (hw->mac.forced_speed_duplex) {
+ case IGC_FORCED_10H:
+ ctrl |= IGC_CTRL_SPEED_10;
+ break;
+ case IGC_FORCED_10F:
+ ctrl |= IGC_CTRL_SPEED_10 | IGC_CTRL_FD;
+ break;
+ case IGC_FORCED_100H:
+ ctrl |= IGC_CTRL_SPEED_100;
+ break;
+ case IGC_FORCED_100F:
+ ctrl |= IGC_CTRL_SPEED_100 | IGC_CTRL_FD;
+ break;
+ default:
+ return -IGC_ERR_CONFIG;
+ }
+ wr32(IGC_CTRL, ctrl);
+ ret_val = igc_setup_copper_link(hw);
+ }
return ret_val;
}
@@ -443,6 +467,7 @@ static const struct igc_phy_operations igc_phy_ops_base = {
.reset = igc_phy_hw_reset,
.read_reg = igc_read_phy_reg_gpy,
.write_reg = igc_write_phy_reg_gpy,
+ .force_speed_duplex = igc_force_speed_duplex,
};
const struct igc_info igc_base_info = {
diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h
index 9482ab11f050..3f504751c2d9 100644
--- a/drivers/net/ethernet/intel/igc/igc_defines.h
+++ b/drivers/net/ethernet/intel/igc/igc_defines.h
@@ -129,10 +129,13 @@
#define IGC_ERR_SWFW_SYNC 13
/* Device Control */
+#define IGC_CTRL_FD BIT(0) /* Full Duplex */
#define IGC_CTRL_RST 0x04000000 /* Global reset */
-
#define IGC_CTRL_PHY_RST 0x80000000 /* PHY Reset */
#define IGC_CTRL_SLU 0x00000040 /* Set link up (Force Link) */
+#define IGC_CTRL_SPEED_MASK GENMASK(10, 8)
+#define IGC_CTRL_SPEED_10 FIELD_PREP(IGC_CTRL_SPEED_MASK, 0)
+#define IGC_CTRL_SPEED_100 FIELD_PREP(IGC_CTRL_SPEED_MASK, 1)
#define IGC_CTRL_FRCSPD 0x00000800 /* Force Speed */
#define IGC_CTRL_FRCDPX 0x00001000 /* Force Duplex */
#define IGC_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */
@@ -673,6 +676,10 @@
#define IGC_GEN_POLL_TIMEOUT 1920
/* PHY Control Register */
+#define MII_CR_SPEED_MASK (BIT(6) | BIT(13))
+#define MII_CR_SPEED_10 0x0000 /* SSM=0, SSL=0: 10 Mb/s */
+#define MII_CR_SPEED_100 BIT(13) /* SSM=0, SSL=1: 100 Mb/s */
+#define MII_CR_DUPLEX_EN BIT(8) /* 0 = Half Duplex, 1 = Full Duplex */
#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */
#define MII_CR_POWER_DOWN 0x0800 /* Power down */
#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */
diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c
index 0122009bedd0..89fe2788a565 100644
--- a/drivers/net/ethernet/intel/igc/igc_ethtool.c
+++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c
@@ -1460,6 +1460,26 @@ static int igc_ethtool_set_rxnfc(struct net_device *dev,
}
}
+/**
+ * igc_write_rss_key - Program the RSS key into device registers
+ * @adapter: board private structure
+ *
+ * Write the RSS key stored in adapter->rss_key to the IGC_RSSRK registers.
+ * Each 32-bit chunk of the key is read using get_unaligned_le32() and written
+ * to the appropriate register.
+ */
+void igc_write_rss_key(struct igc_adapter *adapter)
+{
+ struct igc_hw *hw = &adapter->hw;
+ u32 val;
+ int i;
+
+ for (i = 0; i < IGC_RSS_KEY_SIZE / 4; i++) {
+ val = get_unaligned_le32(&adapter->rss_key[i * 4]);
+ wr32(IGC_RSSRK(i), val);
+ }
+}
+
void igc_write_rss_indir_tbl(struct igc_adapter *adapter)
{
struct igc_hw *hw = &adapter->hw;
@@ -1482,6 +1502,11 @@ void igc_write_rss_indir_tbl(struct igc_adapter *adapter)
}
}
+static u32 igc_ethtool_get_rxfh_key_size(struct net_device *netdev)
+{
+ return IGC_RSS_KEY_SIZE;
+}
+
static u32 igc_ethtool_get_rxfh_indir_size(struct net_device *netdev)
{
return IGC_RETA_SIZE;
@@ -1494,10 +1519,13 @@ static int igc_ethtool_get_rxfh(struct net_device *netdev,
int i;
rxfh->hfunc = ETH_RSS_HASH_TOP;
- if (!rxfh->indir)
- return 0;
- for (i = 0; i < IGC_RETA_SIZE; i++)
- rxfh->indir[i] = adapter->rss_indir_tbl[i];
+
+ if (rxfh->indir)
+ for (i = 0; i < IGC_RETA_SIZE; i++)
+ rxfh->indir[i] = adapter->rss_indir_tbl[i];
+
+ if (rxfh->key)
+ memcpy(rxfh->key, adapter->rss_key, sizeof(adapter->rss_key));
return 0;
}
@@ -1511,24 +1539,28 @@ static int igc_ethtool_set_rxfh(struct net_device *netdev,
int i;
/* We do not allow change in unsupported parameters */
- if (rxfh->key ||
- (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
- rxfh->hfunc != ETH_RSS_HASH_TOP))
+ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP)
return -EOPNOTSUPP;
- if (!rxfh->indir)
- return 0;
- num_queues = adapter->rss_queues;
+ if (rxfh->indir) {
+ num_queues = adapter->rss_queues;
- /* Verify user input. */
- for (i = 0; i < IGC_RETA_SIZE; i++)
- if (rxfh->indir[i] >= num_queues)
- return -EINVAL;
+ /* Verify user input. */
+ for (i = 0; i < IGC_RETA_SIZE; i++)
+ if (rxfh->indir[i] >= num_queues)
+ return -EINVAL;
- for (i = 0; i < IGC_RETA_SIZE; i++)
- adapter->rss_indir_tbl[i] = rxfh->indir[i];
+ for (i = 0; i < IGC_RETA_SIZE; i++)
+ adapter->rss_indir_tbl[i] = rxfh->indir[i];
+
+ igc_write_rss_indir_tbl(adapter);
+ }
- igc_write_rss_indir_tbl(adapter);
+ if (rxfh->key) {
+ memcpy(adapter->rss_key, rxfh->key, sizeof(adapter->rss_key));
+ igc_write_rss_key(adapter);
+ }
return 0;
}
@@ -1914,44 +1946,58 @@ static int igc_ethtool_get_link_ksettings(struct net_device *netdev,
ethtool_link_ksettings_add_link_mode(cmd, supported, TP);
ethtool_link_ksettings_add_link_mode(cmd, advertising, TP);
- /* advertising link modes */
- if (hw->phy.autoneg_advertised & ADVERTISE_10_HALF)
- ethtool_link_ksettings_add_link_mode(cmd, advertising, 10baseT_Half);
- if (hw->phy.autoneg_advertised & ADVERTISE_10_FULL)
- ethtool_link_ksettings_add_link_mode(cmd, advertising, 10baseT_Full);
- if (hw->phy.autoneg_advertised & ADVERTISE_100_HALF)
- ethtool_link_ksettings_add_link_mode(cmd, advertising, 100baseT_Half);
- if (hw->phy.autoneg_advertised & ADVERTISE_100_FULL)
- ethtool_link_ksettings_add_link_mode(cmd, advertising, 100baseT_Full);
- if (hw->phy.autoneg_advertised & ADVERTISE_1000_FULL)
- ethtool_link_ksettings_add_link_mode(cmd, advertising, 1000baseT_Full);
- if (hw->phy.autoneg_advertised & ADVERTISE_2500_FULL)
- ethtool_link_ksettings_add_link_mode(cmd, advertising, 2500baseT_Full);
-
/* set autoneg settings */
ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg);
- ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg);
+ if (hw->mac.autoneg_enabled) {
+ ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg);
+ cmd->base.autoneg = AUTONEG_ENABLE;
+
+ /* advertising link modes only apply when autoneg is on */
+ if (hw->phy.autoneg_advertised & ADVERTISE_10_HALF)
+ ethtool_link_ksettings_add_link_mode(cmd, advertising,
+ 10baseT_Half);
+ if (hw->phy.autoneg_advertised & ADVERTISE_10_FULL)
+ ethtool_link_ksettings_add_link_mode(cmd, advertising,
+ 10baseT_Full);
+ if (hw->phy.autoneg_advertised & ADVERTISE_100_HALF)
+ ethtool_link_ksettings_add_link_mode(cmd, advertising,
+ 100baseT_Half);
+ if (hw->phy.autoneg_advertised & ADVERTISE_100_FULL)
+ ethtool_link_ksettings_add_link_mode(cmd, advertising,
+ 100baseT_Full);
+ if (hw->phy.autoneg_advertised & ADVERTISE_1000_FULL)
+ ethtool_link_ksettings_add_link_mode(cmd, advertising,
+ 1000baseT_Full);
+ if (hw->phy.autoneg_advertised & ADVERTISE_2500_FULL)
+ ethtool_link_ksettings_add_link_mode(cmd, advertising,
+ 2500baseT_Full);
+
+ /* Set pause flow control advertising */
+ switch (hw->fc.requested_mode) {
+ case igc_fc_full:
+ ethtool_link_ksettings_add_link_mode(cmd, advertising,
+ Pause);
+ break;
+ case igc_fc_rx_pause:
+ ethtool_link_ksettings_add_link_mode(cmd, advertising,
+ Pause);
+ ethtool_link_ksettings_add_link_mode(cmd, advertising,
+ Asym_Pause);
+ break;
+ case igc_fc_tx_pause:
+ ethtool_link_ksettings_add_link_mode(cmd, advertising,
+ Asym_Pause);
+ break;
+ default:
+ break;
+ }
+ } else {
+ cmd->base.autoneg = AUTONEG_DISABLE;
+ }
- /* Set pause flow control settings */
+ /* Pause is always supported */
ethtool_link_ksettings_add_link_mode(cmd, supported, Pause);
- switch (hw->fc.requested_mode) {
- case igc_fc_full:
- ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause);
- break;
- case igc_fc_rx_pause:
- ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause);
- ethtool_link_ksettings_add_link_mode(cmd, advertising,
- Asym_Pause);
- break;
- case igc_fc_tx_pause:
- ethtool_link_ksettings_add_link_mode(cmd, advertising,
- Asym_Pause);
- break;
- default:
- break;
- }
-
status = pm_runtime_suspended(&adapter->pdev->dev) ?
0 : rd32(IGC_STATUS);
@@ -1983,7 +2029,6 @@ static int igc_ethtool_get_link_ksettings(struct net_device *netdev,
cmd->base.duplex = DUPLEX_UNKNOWN;
}
cmd->base.speed = speed;
- cmd->base.autoneg = AUTONEG_ENABLE;
/* MDI-X => 2; MDI =>1; Invalid =>0 */
if (hw->phy.media_type == igc_media_type_copper)
@@ -2000,37 +2045,50 @@ static int igc_ethtool_get_link_ksettings(struct net_device *netdev,
return 0;
}
-static int
-igc_ethtool_set_link_ksettings(struct net_device *netdev,
- const struct ethtool_link_ksettings *cmd)
+/**
+ * igc_handle_autoneg_disabled - Configure forced speed/duplex settings
+ * @adapter: private driver structure
+ * @speed: requested speed (must be SPEED_10 or SPEED_100)
+ * @duplex: requested duplex
+ *
+ * Records forced speed/duplex when autoneg is disabled.
+ * Caller must validate speed before calling this function.
+ */
+static void igc_handle_autoneg_disabled(struct igc_adapter *adapter, u32 speed,
+ u8 duplex)
{
- struct igc_adapter *adapter = netdev_priv(netdev);
- struct net_device *dev = adapter->netdev;
- struct igc_hw *hw = &adapter->hw;
- u16 advertised = 0;
+ struct igc_mac_info *mac = &adapter->hw.mac;
- /* When adapter in resetting mode, autoneg/speed/duplex
- * cannot be changed
- */
- if (igc_check_reset_block(hw)) {
- netdev_err(dev, "Cannot change link characteristics when reset is active\n");
- return -EINVAL;
+ switch (speed) {
+ case SPEED_10:
+ mac->forced_speed_duplex = (duplex == DUPLEX_FULL) ?
+ IGC_FORCED_10F : IGC_FORCED_10H;
+ break;
+ case SPEED_100:
+ mac->forced_speed_duplex = (duplex == DUPLEX_FULL) ?
+ IGC_FORCED_100F : IGC_FORCED_100H;
+ break;
+ default:
+ WARN_ONCE(1, "Unsupported speed %u\n", speed);
+ return;
}
- /* MDI setting is only allowed when autoneg enabled because
- * some hardware doesn't allow MDI setting when speed or
- * duplex is forced.
- */
- if (cmd->base.eth_tp_mdix_ctrl) {
- if (cmd->base.eth_tp_mdix_ctrl != ETH_TP_MDI_AUTO &&
- cmd->base.autoneg != AUTONEG_ENABLE) {
- netdev_err(dev, "Forcing MDI/MDI-X state is not supported when link speed and/or duplex are forced\n");
- return -EINVAL;
- }
- }
+ mac->autoneg_enabled = false;
+}
- while (test_and_set_bit(__IGC_RESETTING, &adapter->state))
- usleep_range(1000, 2000);
+/**
+ * igc_handle_autoneg_enabled - Configure autonegotiation advertisement
+ * @adapter: private driver structure
+ * @cmd: ethtool link ksettings from user
+ *
+ * Records advertised speeds and flow control settings when autoneg
+ * is enabled.
+ */
+static void igc_handle_autoneg_enabled(struct igc_adapter *adapter,
+ const struct ethtool_link_ksettings *cmd)
+{
+ struct igc_hw *hw = &adapter->hw;
+ u16 advertised = 0;
if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
2500baseT_Full))
@@ -2056,14 +2114,66 @@ igc_ethtool_set_link_ksettings(struct net_device *netdev,
10baseT_Half))
advertised |= ADVERTISE_10_HALF;
- if (cmd->base.autoneg == AUTONEG_ENABLE) {
- hw->phy.autoneg_advertised = advertised;
- if (adapter->fc_autoneg)
- hw->fc.requested_mode = igc_fc_default;
- } else {
- netdev_info(dev, "Force mode currently not supported\n");
+ hw->mac.autoneg_enabled = true;
+ hw->phy.autoneg_advertised = advertised;
+ if (adapter->fc_autoneg)
+ hw->fc.requested_mode = igc_fc_default;
+}
+
+static int
+igc_ethtool_set_link_ksettings(struct net_device *netdev,
+ const struct ethtool_link_ksettings *cmd)
+{
+ struct igc_adapter *adapter = netdev_priv(netdev);
+ struct net_device *dev = adapter->netdev;
+ struct igc_hw *hw = &adapter->hw;
+
+ /* When adapter in resetting mode, autoneg/speed/duplex
+ * cannot be changed
+ */
+ if (igc_check_reset_block(hw)) {
+ netdev_err(dev, "Cannot change link characteristics when reset is active\n");
+ return -EINVAL;
+ }
+
+ if (cmd->base.autoneg != AUTONEG_ENABLE &&
+ cmd->base.autoneg != AUTONEG_DISABLE) {
+ netdev_info(dev, "Unsupported autoneg setting\n");
+ return -EINVAL;
+ }
+
+ /* MDI setting is only allowed when autoneg enabled because
+ * some hardware doesn't allow MDI setting when speed or
+ * duplex is forced.
+ */
+ if (cmd->base.eth_tp_mdix_ctrl) {
+ if (cmd->base.eth_tp_mdix_ctrl != ETH_TP_MDI_AUTO &&
+ cmd->base.autoneg != AUTONEG_ENABLE) {
+ netdev_err(dev, "Forcing MDI/MDI-X state is not supported when link speed and/or duplex are forced\n");
+ return -EINVAL;
+ }
}
+ if (cmd->base.autoneg == AUTONEG_DISABLE) {
+ if (cmd->base.speed != SPEED_10 && cmd->base.speed != SPEED_100) {
+ netdev_info(dev, "Unsupported speed for forced link\n");
+ return -EINVAL;
+ }
+ if (cmd->base.duplex != DUPLEX_HALF && cmd->base.duplex != DUPLEX_FULL) {
+ netdev_info(dev, "Duplex must be half or full for forced link\n");
+ return -EINVAL;
+ }
+ }
+
+ while (test_and_set_bit(__IGC_RESETTING, &adapter->state))
+ usleep_range(1000, 2000);
+
+ if (cmd->base.autoneg == AUTONEG_ENABLE)
+ igc_handle_autoneg_enabled(adapter, cmd);
+ else
+ igc_handle_autoneg_disabled(adapter, cmd->base.speed,
+ cmd->base.duplex);
+
/* MDI-X => 2; MDI => 1; Auto => 3 */
if (cmd->base.eth_tp_mdix_ctrl) {
/* fix up the value for auto (3 => 0) as zero is mapped
@@ -2175,6 +2285,7 @@ static const struct ethtool_ops igc_ethtool_ops = {
.get_rxnfc = igc_ethtool_get_rxnfc,
.set_rxnfc = igc_ethtool_set_rxnfc,
.get_rx_ring_count = igc_ethtool_get_rx_ring_count,
+ .get_rxfh_key_size = igc_ethtool_get_rxfh_key_size,
.get_rxfh_indir_size = igc_ethtool_get_rxfh_indir_size,
.get_rxfh = igc_ethtool_get_rxfh,
.set_rxfh = igc_ethtool_set_rxfh,
diff --git a/drivers/net/ethernet/intel/igc/igc_hw.h b/drivers/net/ethernet/intel/igc/igc_hw.h
index be8a49a86d09..62aaee55668a 100644
--- a/drivers/net/ethernet/intel/igc/igc_hw.h
+++ b/drivers/net/ethernet/intel/igc/igc_hw.h
@@ -73,6 +73,13 @@ struct igc_info {
extern const struct igc_info igc_base_info;
+enum igc_forced_speed_duplex {
+ IGC_FORCED_10H,
+ IGC_FORCED_10F,
+ IGC_FORCED_100H,
+ IGC_FORCED_100F,
+};
+
struct igc_mac_info {
struct igc_mac_operations ops;
@@ -92,8 +99,9 @@ struct igc_mac_info {
bool asf_firmware_present;
bool arc_subsystem_valid;
- bool autoneg_failed;
bool get_link_status;
+ bool autoneg_enabled;
+ enum igc_forced_speed_duplex forced_speed_duplex;
};
struct igc_nvm_operations {
diff --git a/drivers/net/ethernet/intel/igc/igc_mac.c b/drivers/net/ethernet/intel/igc/igc_mac.c
index 7ac6637f8db7..d6f3f6618469 100644
--- a/drivers/net/ethernet/intel/igc/igc_mac.c
+++ b/drivers/net/ethernet/intel/igc/igc_mac.c
@@ -438,26 +438,23 @@ void igc_config_collision_dist(struct igc_hw *hw)
* Checks the status of auto-negotiation after link up to ensure that the
* speed and duplex were not forced. If the link needed to be forced, then
* flow control needs to be forced also. If auto-negotiation is enabled
- * and did not fail, then we configure flow control based on our link
- * partner.
+ * then we configure flow control based on our link partner.
*/
s32 igc_config_fc_after_link_up(struct igc_hw *hw)
{
u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg;
- struct igc_mac_info *mac = &hw->mac;
u16 speed, duplex;
s32 ret_val = 0;
- /* Check for the case where we have fiber media and auto-neg failed
- * so we had to force link. In this case, we need to force the
- * configuration of the MAC to match the "fc" parameter.
+ /* Without autoneg, flow control capability is not exchanged with the
+ * link partner. IEEE 802.3 prohibits flow control in half-duplex mode.
*/
- if (mac->autoneg_failed)
- ret_val = igc_force_mac_fc(hw);
+ if (!hw->mac.autoneg_enabled) {
+ if (hw->mac.forced_speed_duplex == IGC_FORCED_10H ||
+ hw->mac.forced_speed_duplex == IGC_FORCED_100H)
+ hw->fc.current_mode = igc_fc_none;
- if (ret_val) {
- hw_dbg("Error forcing flow control settings\n");
- goto out;
+ goto force_fc;
}
/* In auto-neg, we need to check and see if Auto-Neg has completed,
@@ -472,15 +469,15 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw)
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS,
&mii_status_reg);
if (ret_val)
- goto out;
+ return ret_val;
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS,
&mii_status_reg);
if (ret_val)
- goto out;
+ return ret_val;
if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) {
hw_dbg("Copper PHY and Auto Neg has not completed.\n");
- goto out;
+ return ret_val;
}
/* The AutoNeg process has completed, so we now need to
@@ -492,11 +489,11 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw)
ret_val = hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV,
&mii_nway_adv_reg);
if (ret_val)
- goto out;
+ return ret_val;
ret_val = hw->phy.ops.read_reg(hw, PHY_LP_ABILITY,
&mii_nway_lp_ability_reg);
if (ret_val)
- goto out;
+ return ret_val;
/* Two bits in the Auto Negotiation Advertisement Register
* (Address 4) and two bits in the Auto Negotiation Base
* Page Ability Register (Address 5) determine flow control
@@ -612,7 +609,7 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw)
ret_val = hw->mac.ops.get_speed_and_duplex(hw, &speed, &duplex);
if (ret_val) {
hw_dbg("Error getting link speed and duplex\n");
- goto out;
+ return ret_val;
}
if (duplex == HALF_DUPLEX)
@@ -621,13 +618,13 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw)
/* Now we call a subroutine to actually force the MAC
* controller to use the correct flow control settings.
*/
+force_fc:
ret_val = igc_force_mac_fc(hw);
if (ret_val) {
hw_dbg("Error forcing flow control settings\n");
- goto out;
+ return ret_val;
}
-out:
return ret_val;
}
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index 2c9e2dfd8499..e6e9441fc3d4 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -785,11 +785,8 @@ static void igc_setup_mrqc(struct igc_adapter *adapter)
struct igc_hw *hw = &adapter->hw;
u32 j, num_rx_queues;
u32 mrqc, rxcsum;
- u32 rss_key[10];
- netdev_rss_key_fill(rss_key, sizeof(rss_key));
- for (j = 0; j < 10; j++)
- wr32(IGC_RSSRK(j), rss_key[j]);
+ igc_write_rss_key(adapter);
num_rx_queues = adapter->rss_queues;
@@ -5048,6 +5045,9 @@ static int igc_sw_init(struct igc_adapter *adapter)
pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word);
+ /* init RSS key */
+ netdev_rss_key_fill(adapter->rss_key, sizeof(adapter->rss_key));
+
/* set default ring sizes */
adapter->tx_ring_count = IGC_DEFAULT_TXD;
adapter->rx_ring_count = IGC_DEFAULT_RXD;
@@ -7298,7 +7298,7 @@ static int igc_probe(struct pci_dev *pdev,
/* Initialize link properties that are user-changeable */
adapter->fc_autoneg = true;
hw->phy.autoneg_advertised = 0xaf;
-
+ hw->mac.autoneg_enabled = true;
hw->fc.requested_mode = igc_fc_default;
hw->fc.current_mode = igc_fc_default;
diff --git a/drivers/net/ethernet/intel/igc/igc_phy.c b/drivers/net/ethernet/intel/igc/igc_phy.c
index 6c4d204aecfa..4cf737fb3b21 100644
--- a/drivers/net/ethernet/intel/igc/igc_phy.c
+++ b/drivers/net/ethernet/intel/igc/igc_phy.c
@@ -494,12 +494,20 @@ s32 igc_setup_copper_link(struct igc_hw *hw)
s32 ret_val = 0;
bool link;
- /* Setup autoneg and flow control advertisement and perform
- * autonegotiation.
- */
- ret_val = igc_copper_link_autoneg(hw);
- if (ret_val)
- goto out;
+ if (hw->mac.autoneg_enabled) {
+ /* Setup autoneg and flow control advertisement and perform
+ * autonegotiation.
+ */
+ ret_val = igc_copper_link_autoneg(hw);
+ if (ret_val)
+ goto out;
+ } else {
+ ret_val = hw->phy.ops.force_speed_duplex(hw);
+ if (ret_val) {
+ hw_dbg("Error Forcing Speed/Duplex\n");
+ goto out;
+ }
+ }
/* Check link status. Wait up to 100 microseconds for link to become
* valid.
@@ -778,3 +786,48 @@ u16 igc_read_phy_fw_version(struct igc_hw *hw)
return gphy_version;
}
+
+/**
+ * igc_force_speed_duplex - Force PHY speed and duplex settings
+ * @hw: pointer to the HW structure
+ *
+ * Programs the GPY PHY control register to disable autonegotiation
+ * and force the speed/duplex indicated by hw->mac.forced_speed_duplex.
+ */
+s32 igc_force_speed_duplex(struct igc_hw *hw)
+{
+ struct igc_phy_info *phy = &hw->phy;
+ u16 phy_ctrl;
+ s32 ret_val;
+
+ ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
+ if (ret_val)
+ return ret_val;
+
+ phy_ctrl &= ~(MII_CR_SPEED_MASK | MII_CR_DUPLEX_EN |
+ MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
+
+ switch (hw->mac.forced_speed_duplex) {
+ case IGC_FORCED_10H:
+ phy_ctrl |= MII_CR_SPEED_10;
+ break;
+ case IGC_FORCED_10F:
+ phy_ctrl |= MII_CR_SPEED_10 | MII_CR_DUPLEX_EN;
+ break;
+ case IGC_FORCED_100H:
+ phy_ctrl |= MII_CR_SPEED_100;
+ break;
+ case IGC_FORCED_100F:
+ phy_ctrl |= MII_CR_SPEED_100 | MII_CR_DUPLEX_EN;
+ break;
+ default:
+ return -IGC_ERR_CONFIG;
+ }
+
+ ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
+ if (ret_val)
+ return ret_val;
+
+ hw->mac.get_link_status = true;
+ return 0;
+}
diff --git a/drivers/net/ethernet/intel/igc/igc_phy.h b/drivers/net/ethernet/intel/igc/igc_phy.h
index 832a7e359f18..d37a89174826 100644
--- a/drivers/net/ethernet/intel/igc/igc_phy.h
+++ b/drivers/net/ethernet/intel/igc/igc_phy.h
@@ -18,5 +18,6 @@ void igc_power_down_phy_copper(struct igc_hw *hw);
s32 igc_write_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 data);
s32 igc_read_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 *data);
u16 igc_read_phy_fw_version(struct igc_hw *hw);
+s32 igc_force_speed_duplex(struct igc_hw *hw);
#endif
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
index 8e3bb47eb3ba..78667a0977c0 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
@@ -4587,7 +4587,7 @@ int rvu_mbox_handler_nix_set_rx_mode(struct rvu *rvu, struct nix_rx_mode *req,
rvu_npc_install_allmulti_entry(rvu, pcifunc, nixlf,
pfvf->rx_chan_base);
} else {
- if (!nix_rx_multicast)
+ if (!nix_rx_multicast && !is_vf(pcifunc))
rvu_npc_enable_allmulti_entry(rvu, pcifunc, nixlf, false);
}
@@ -4597,7 +4597,7 @@ int rvu_mbox_handler_nix_set_rx_mode(struct rvu *rvu, struct nix_rx_mode *req,
pfvf->rx_chan_base,
pfvf->rx_chan_cnt);
else
- if (!nix_rx_multicast)
+ if (!nix_rx_multicast && !is_vf(pcifunc))
rvu_npc_enable_promisc_entry(rvu, pcifunc, nixlf, false);
return 0;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/port_tun.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/port_tun.c
index 4571c56ec3c9..97f6097d4c70 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/port_tun.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/port_tun.c
@@ -176,7 +176,8 @@ void mlx5_tun_entropy_refcount_dec(struct mlx5_tun_entropy *tun_entropy,
int reformat_type)
{
mutex_lock(&tun_entropy->lock);
- if (reformat_type == MLX5_REFORMAT_TYPE_L2_TO_VXLAN)
+ if (reformat_type == MLX5_REFORMAT_TYPE_L2_TO_VXLAN ||
+ reformat_type == MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL)
tun_entropy->num_enabling_entries--;
else if (reformat_type == MLX5_REFORMAT_TYPE_L2_TO_NVGRE &&
--tun_entropy->num_disabling_entries == 0)
diff --git a/drivers/net/ethernet/microsoft/Kconfig b/drivers/net/ethernet/microsoft/Kconfig
index 3f36ee6a8ece..e9be18c92ca5 100644
--- a/drivers/net/ethernet/microsoft/Kconfig
+++ b/drivers/net/ethernet/microsoft/Kconfig
@@ -21,6 +21,7 @@ config MICROSOFT_MANA
depends on X86_64 || (ARM64 && !CPU_BIG_ENDIAN)
depends on PCI_HYPERV
select AUXILIARY_BUS
+ select DIMLIB
select PAGE_POOL
select NET_SHAPER
help
diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c
index e8b7ffb47eb9..aef3b77229c1 100644
--- a/drivers/net/ethernet/microsoft/mana/gdma_main.c
+++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright (c) 2021, Microsoft Corporation. */
+#include <linux/bitfield.h>
#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/pci.h>
@@ -466,6 +467,7 @@ static int mana_gd_disable_queue(struct gdma_queue *queue)
#define DOORBELL_OFFSET_RQ 0x400
#define DOORBELL_OFFSET_CQ 0x800
#define DOORBELL_OFFSET_EQ 0xFF8
+#define DOORBELL_OFFSET_DIM 0x820
static void mana_gd_ring_doorbell(struct gdma_context *gc, u32 db_index,
enum gdma_queue_type q_type, u32 qid,
@@ -506,6 +508,16 @@ static void mana_gd_ring_doorbell(struct gdma_context *gc, u32 db_index,
addr += DOORBELL_OFFSET_SQ;
break;
+ case GDMA_DIM:
+ e.dim.id = qid;
+ e.dim.mod_usec = FIELD_GET(MANA_INTR_MODR_USEC_MAX, tail_ptr);
+ e.dim.mod_usec_vld = !!(tail_ptr & MANA_INTR_MODR_USEC_VLD);
+ e.dim.mod_comps = FIELD_GET(MANA_INTR_MODR_COMP_MASK, tail_ptr);
+ e.dim.mod_comps_vld = num_req;
+
+ addr += DOORBELL_OFFSET_DIM;
+ break;
+
default:
WARN_ON(1);
return;
@@ -540,6 +552,23 @@ void mana_gd_ring_cq(struct gdma_queue *cq, u8 arm_bit)
}
EXPORT_SYMBOL_NS(mana_gd_ring_cq, "NET_MANA");
+void mana_gd_ring_dim(struct gdma_queue *cq, u32 mod_usec, bool mod_usec_vld,
+ u32 mod_comps, bool mod_comps_vld)
+{
+ struct gdma_context *gc = cq->gdma_dev->gdma_context;
+ u32 dim_val;
+
+ /* Convert the DIM values to doorbell parameters */
+ dim_val = FIELD_PREP(MANA_INTR_MODR_USEC_MAX, mod_usec) |
+ FIELD_PREP(MANA_INTR_MODR_COMP_MASK, mod_comps);
+ if (mod_usec_vld)
+ dim_val |= MANA_INTR_MODR_USEC_VLD;
+
+ mana_gd_ring_doorbell(gc, cq->gdma_dev->doorbell, GDMA_DIM, cq->id,
+ dim_val, mod_comps_vld);
+}
+EXPORT_SYMBOL_NS(mana_gd_ring_dim, "NET_MANA");
+
#define MANA_SERVICE_PERIOD 10
static void mana_serv_rescan(struct pci_dev *pdev)
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index 7438ea6b3f26..89e7f59f635d 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -1591,6 +1591,15 @@ int mana_create_wq_obj(struct mana_port_context *apc,
mana_gd_init_req_hdr(&req.hdr, MANA_CREATE_WQ_OBJ,
sizeof(req), sizeof(resp));
+
+ /* Our driver uses different message versions for request and
+ * response in this case.
+ * Our firmware is forward compatible with newer message versions, so
+ * the old firmware still properly handles this message, just the new
+ * feature fields are ignored, and queue creation will be successful.
+ */
+ req.hdr.req.msg_version = GDMA_MESSAGE_V3;
+ req.hdr.resp.msg_version = GDMA_MESSAGE_V2;
req.vport = vport;
req.wq_type = wq_type;
req.wq_gdma_region = wq_spec->gdma_region;
@@ -1599,6 +1608,9 @@ int mana_create_wq_obj(struct mana_port_context *apc,
req.cq_size = cq_spec->queue_size;
req.cq_moderation_ctx_id = cq_spec->modr_ctx_id;
req.cq_parent_qid = cq_spec->attached_eq;
+ req.req_cq_moderation = cq_spec->req_cq_moderation;
+ req.cq_moderation_comp = cq_spec->cq_moderation_comp;
+ req.cq_moderation_usec = cq_spec->cq_moderation_usec;
err = mana_send_request(apc->ac, &req, sizeof(req), &resp,
sizeof(resp));
@@ -1856,6 +1868,7 @@ static void mana_poll_tx_cq(struct mana_cq *cq)
struct gdma_posted_wqe_info *wqe_info;
unsigned int pkt_transmitted = 0;
unsigned int wqe_unit_cnt = 0;
+ unsigned int tx_bytes = 0;
struct mana_txq *txq = cq->txq;
struct mana_port_context *apc;
struct netdev_queue *net_txq;
@@ -1937,6 +1950,8 @@ static void mana_poll_tx_cq(struct mana_cq *cq)
mana_unmap_skb(skb, apc);
+ tx_bytes += skb->len;
+
napi_consume_skb(skb, cq->budget);
pkt_transmitted++;
@@ -1967,6 +1982,10 @@ static void mana_poll_tx_cq(struct mana_cq *cq)
if (atomic_sub_return(pkt_transmitted, &txq->pending_sends) < 0)
WARN_ON_ONCE(1);
+ /* Feed DIM with the completion rate observed here, in NAPI context. */
+ cq->tx_dim_pkts += pkt_transmitted;
+ cq->tx_dim_bytes += tx_bytes;
+
cq->work_done = pkt_transmitted;
}
@@ -2120,12 +2139,16 @@ drop:
}
static void *mana_get_rxfrag(struct mana_rxq *rxq, struct device *dev,
- dma_addr_t *da, bool *from_pool)
+ dma_addr_t *da, bool *from_pool,
+ struct page **pp_page, u32 *dma_sync_offset)
{
struct page *page;
u32 offset;
void *va;
+
*from_pool = false;
+ *pp_page = NULL;
+ *dma_sync_offset = 0;
/* Don't use fragments for jumbo frames or XDP where it's 1 fragment
* per page.
@@ -2163,31 +2186,47 @@ static void *mana_get_rxfrag(struct mana_rxq *rxq, struct device *dev,
va = page_to_virt(page) + offset;
*da = page_pool_get_dma_addr(page) + offset + rxq->headroom;
*from_pool = true;
+ *pp_page = page;
+ *dma_sync_offset = offset + rxq->headroom;
return va;
}
/* Allocate frag for rx buffer, and save the old buf */
static void mana_refill_rx_oob(struct device *dev, struct mana_rxq *rxq,
- struct mana_recv_buf_oob *rxoob, void **old_buf,
- bool *old_fp)
+ struct mana_recv_buf_oob *rxoob, u32 pktlen,
+ void **old_buf, bool *old_fp)
{
+ struct page *pp_page;
+ u32 dma_sync_offset;
bool from_pool;
dma_addr_t da;
void *va;
- va = mana_get_rxfrag(rxq, dev, &da, &from_pool);
+ va = mana_get_rxfrag(rxq, dev, &da, &from_pool, &pp_page,
+ &dma_sync_offset);
if (!va)
return;
- if (!rxoob->from_pool || rxq->frag_count == 1)
+ if (!rxoob->from_pool || rxq->frag_count == 1) {
dma_unmap_single(dev, rxoob->sgl[0].address, rxq->datasize,
DMA_FROM_DEVICE);
+ } else {
+ /* The page pool maps the whole page and only syncs for device
+ * automatically (PP_FLAG_DMA_SYNC_DEV). Sync the received bytes
+ * for the CPU before they are read: this is required if DMA
+ * is incoherent or bounce buffers are used.
+ */
+ page_pool_dma_sync_for_cpu(rxq->page_pool, rxoob->pp_page,
+ rxoob->dma_sync_offset, pktlen);
+ }
*old_buf = rxoob->buf_va;
*old_fp = rxoob->from_pool;
rxoob->buf_va = va;
rxoob->sgl[0].address = da;
rxoob->from_pool = from_pool;
+ rxoob->pp_page = pp_page;
+ rxoob->dma_sync_offset = dma_sync_offset;
}
static void mana_process_rx_cqe(struct mana_rxq *rxq, struct mana_cq *cq,
@@ -2246,12 +2285,26 @@ static void mana_process_rx_cqe(struct mana_rxq *rxq, struct mana_cq *cq,
rxbuf_oob = &rxq->rx_oobs[curr];
WARN_ON_ONCE(rxbuf_oob->wqe_inf.wqe_size_in_bu != 1);
- mana_refill_rx_oob(dev, rxq, rxbuf_oob, &old_buf, &old_fp);
+ if (unlikely(pktlen > rxq->datasize)) {
+ /* Increase it even if mana_rx_skb() isn't called. */
+ rxq->rx_cq.work_done++;
- /* Unsuccessful refill will have old_buf == NULL.
- * In this case, mana_rx_skb() will drop the packet.
- */
- mana_rx_skb(old_buf, old_fp, oob, rxq, i);
+ ++ndev->stats.rx_dropped;
+ netdev_warn_once(ndev,
+ "Dropped oversized RX packet: len=%u, datasize=%u\n",
+ pktlen, rxq->datasize);
+
+ /* Reuse the RX buffer since rxbuf_oob is unchanged. */
+ } else {
+
+ mana_refill_rx_oob(dev, rxq, rxbuf_oob, pktlen,
+ &old_buf, &old_fp);
+
+ /* Unsuccessful refill will have old_buf == NULL.
+ * In this case, mana_rx_skb() will drop the packet.
+ */
+ mana_rx_skb(old_buf, old_fp, oob, rxq, i);
+ }
mana_move_wq_tail(rxq->gdma_rq,
rxbuf_oob->wqe_inf.wqe_size_in_bu);
@@ -2318,6 +2371,117 @@ static void mana_poll_rx_cq(struct mana_cq *cq)
xdp_do_flush();
}
+static void mana_rx_dim_work(struct work_struct *work)
+{
+ struct dim *dim = container_of(work, struct dim, work);
+ struct dim_cq_moder cur_moder;
+ struct mana_cq *cq;
+
+ cur_moder = net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
+ cq = container_of(dim, struct mana_cq, dim);
+
+ cur_moder.usec = min_t(u16, cur_moder.usec, MANA_INTR_MODR_USEC_MAX);
+ cur_moder.pkts = min_t(u16, cur_moder.pkts, MANA_INTR_MODR_COMP_MAX);
+
+ mana_gd_ring_dim(cq->gdma_cq, cur_moder.usec, true,
+ cur_moder.pkts, true);
+
+ dim->state = DIM_START_MEASURE;
+}
+
+static void mana_tx_dim_work(struct work_struct *work)
+{
+ struct dim *dim = container_of(work, struct dim, work);
+ struct dim_cq_moder cur_moder;
+ struct mana_cq *cq;
+
+ cur_moder = net_dim_get_tx_moderation(dim->mode, dim->profile_ix);
+ cq = container_of(dim, struct mana_cq, dim);
+
+ cur_moder.usec = min_t(u16, cur_moder.usec, MANA_INTR_MODR_USEC_MAX);
+ cur_moder.pkts = min_t(u16, cur_moder.pkts, MANA_INTR_MODR_COMP_MAX);
+
+ mana_gd_ring_dim(cq->gdma_cq, cur_moder.usec, true,
+ cur_moder.pkts, true);
+
+ dim->state = DIM_START_MEASURE;
+}
+
+/* The caller must update apc->rx/tx_dim_enabled before disabling and
+ * after enabling. And synchronize_net() before draining the DIM work,
+ * so that NAPI cannot observe a stale flag.
+ */
+void mana_dim_change(struct mana_cq *cq, bool enable)
+{
+ bool is_rx = cq->type == MANA_CQ_TYPE_RX;
+ struct mana_port_context *apc;
+ work_func_t work_func;
+ u32 usec, comp;
+
+ if (is_rx) {
+ apc = netdev_priv(cq->rxq->ndev);
+ usec = apc->intr_modr_rx_usec;
+ comp = apc->intr_modr_rx_comp;
+ work_func = mana_rx_dim_work;
+ } else {
+ apc = netdev_priv(cq->txq->ndev);
+ usec = apc->intr_modr_tx_usec;
+ comp = apc->intr_modr_tx_comp;
+ work_func = mana_tx_dim_work;
+ }
+
+ /* On enable, zero the DIM state so net_dim() starts measuring from
+ * scratch.
+ * On disable, drain any pending DIM work and restore the static
+ * moderation values.
+ */
+ if (enable) {
+ memset(&cq->dim, 0, sizeof(cq->dim));
+ cq->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
+ INIT_WORK(&cq->dim.work, work_func);
+ } else {
+ cancel_work_sync(&cq->dim.work);
+ mana_gd_ring_dim(cq->gdma_cq, usec, true, comp, true);
+ }
+}
+
+static void mana_update_rx_dim(struct mana_cq *cq)
+{
+ struct mana_port_context *apc = netdev_priv(cq->rxq->ndev);
+ struct dim_sample dim_sample = {};
+ struct mana_rxq *rxq = cq->rxq;
+
+ /* Pairs with smp_store_release() in mana_set_coalesce(): observing the
+ * enable flag set guarantees the DIM (re)initialization is visible.
+ */
+ if (!smp_load_acquire(&apc->rx_dim_enabled))
+ return;
+
+ dim_update_sample(READ_ONCE(cq->dim_event_ctr), rxq->stats.packets,
+ rxq->stats.bytes, &dim_sample);
+ net_dim(&cq->dim, &dim_sample);
+}
+
+static void mana_update_tx_dim(struct mana_cq *cq)
+{
+ struct mana_port_context *apc = netdev_priv(cq->txq->ndev);
+ struct dim_sample dim_sample = {};
+
+ /* Pairs with smp_store_release() in mana_set_coalesce(): observing the
+ * enable flag set guarantees the DIM (re)initialization is visible.
+ */
+ if (!smp_load_acquire(&apc->tx_dim_enabled))
+ return;
+
+ /* cq->tx_dim_pkts/bytes are accumulated in mana_poll_tx_cq(), in the
+ * same NAPI context as this read, so they track the hardware
+ * completion rate and need no u64_stats_sync protection.
+ */
+ dim_update_sample(READ_ONCE(cq->dim_event_ctr), cq->tx_dim_pkts,
+ cq->tx_dim_bytes, &dim_sample);
+ net_dim(&cq->dim, &dim_sample);
+}
+
static int mana_cq_handler(void *context, struct gdma_queue *gdma_queue)
{
struct mana_cq *cq = context;
@@ -2336,6 +2500,15 @@ static int mana_cq_handler(void *context, struct gdma_queue *gdma_queue)
if (w < cq->budget) {
mana_gd_ring_cq(gdma_queue, SET_ARM_BIT);
cq->work_done_since_doorbell = 0;
+
+ /* Update DIM before napi_complete_done() to prevent running
+ * net_dim() concurrently.
+ */
+ if (cq->type == MANA_CQ_TYPE_RX)
+ mana_update_rx_dim(cq);
+ else
+ mana_update_tx_dim(cq);
+
napi_complete_done(&cq->napi, w);
} else if (cq->work_done_since_doorbell >=
(cq->gdma_cq->queue_size / COMP_ENTRY_SIZE) * 4) {
@@ -2368,6 +2541,7 @@ static void mana_schedule_napi(void *context, struct gdma_queue *gdma_queue)
{
struct mana_cq *cq = context;
+ WRITE_ONCE(cq->dim_event_ctr, cq->dim_event_ctr + 1);
napi_schedule_irqoff(&cq->napi);
}
@@ -2410,6 +2584,7 @@ static void mana_destroy_txq(struct mana_port_context *apc)
if (apc->tx_qp[i]->txq.napi_initialized) {
napi_synchronize(napi);
napi_disable_locked(napi);
+ cancel_work_sync(&apc->tx_qp[i]->tx_cq.dim.work);
netif_napi_del_locked(napi);
apc->tx_qp[i]->txq.napi_initialized = false;
}
@@ -2543,6 +2718,11 @@ static int mana_create_txq(struct mana_port_context *apc,
cq_spec.modr_ctx_id = 0;
cq_spec.attached_eq = cq->gdma_cq->cq.parent->id;
+ /* DIM setting can be changed at runtime */
+ cq_spec.req_cq_moderation = true;
+ cq_spec.cq_moderation_usec = apc->intr_modr_tx_usec;
+ cq_spec.cq_moderation_comp = apc->intr_modr_tx_comp;
+
err = mana_create_wq_obj(apc, apc->port_handle, GDMA_SQ,
&wq_spec, &cq_spec,
&apc->tx_qp[i]->tx_object);
@@ -2573,6 +2753,13 @@ static int mana_create_txq(struct mana_port_context *apc,
set_bit(NAPI_STATE_NO_BUSY_POLL, &cq->napi.state);
netif_napi_add_locked(net, &cq->napi, mana_poll);
+
+ /* Initialize the DIM work before enabling NAPI, so that a poll
+ * cannot reach net_dim() with an uninitialized cq->dim.work.
+ */
+ INIT_WORK(&cq->dim.work, mana_tx_dim_work);
+ cq->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
+
napi_enable_locked(&cq->napi);
txq->napi_initialized = true;
@@ -2610,6 +2797,7 @@ static void mana_destroy_rxq(struct mana_port_context *apc,
napi_synchronize(napi);
napi_disable_locked(napi);
+ cancel_work_sync(&rxq->rx_cq.dim.work);
netif_napi_del_locked(napi);
}
@@ -2655,6 +2843,8 @@ static int mana_fill_rx_oob(struct mana_recv_buf_oob *rx_oob, u32 mem_key,
struct mana_rxq *rxq, struct device *dev)
{
struct mana_port_context *mpc = netdev_priv(rxq->ndev);
+ struct page *pp_page = NULL;
+ u32 dma_sync_offset = 0;
bool from_pool = false;
dma_addr_t da;
void *va;
@@ -2662,13 +2852,16 @@ static int mana_fill_rx_oob(struct mana_recv_buf_oob *rx_oob, u32 mem_key,
if (mpc->rxbufs_pre)
va = mana_get_rxbuf_pre(rxq, &da);
else
- va = mana_get_rxfrag(rxq, dev, &da, &from_pool);
+ va = mana_get_rxfrag(rxq, dev, &da, &from_pool, &pp_page,
+ &dma_sync_offset);
if (!va)
return -ENOMEM;
rx_oob->buf_va = va;
rx_oob->from_pool = from_pool;
+ rx_oob->pp_page = pp_page;
+ rx_oob->dma_sync_offset = dma_sync_offset;
rx_oob->sgl[0].address = da;
rx_oob->sgl[0].size = rxq->datasize;
@@ -2848,6 +3041,11 @@ static struct mana_rxq *mana_create_rxq(struct mana_port_context *apc,
cq_spec.modr_ctx_id = 0;
cq_spec.attached_eq = cq->gdma_cq->cq.parent->id;
+ /* DIM setting can be changed at runtime */
+ cq_spec.req_cq_moderation = true;
+ cq_spec.cq_moderation_usec = apc->intr_modr_rx_usec;
+ cq_spec.cq_moderation_comp = apc->intr_modr_rx_comp;
+
err = mana_create_wq_obj(apc, apc->port_handle, GDMA_RQ,
&wq_spec, &cq_spec, &rxq->rxobj);
if (err)
@@ -2880,6 +3078,12 @@ static struct mana_rxq *mana_create_rxq(struct mana_port_context *apc,
WARN_ON(xdp_rxq_info_reg_mem_model(&rxq->xdp_rxq, MEM_TYPE_PAGE_POOL,
rxq->page_pool));
+ /* Initialize the DIM work before enabling NAPI, so that a poll
+ * cannot reach net_dim() with an uninitialized cq->dim.work.
+ */
+ INIT_WORK(&cq->dim.work, mana_rx_dim_work);
+ cq->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
+
napi_enable_locked(&cq->napi);
mana_gd_ring_cq(cq->gdma_cq, SET_ARM_BIT);
@@ -3546,6 +3750,16 @@ static int mana_probe_port(struct mana_context *ac, int port_idx,
apc->link_cfg_error = 1;
apc->cqe_coalescing_enable = 0;
+ /* Initialize interrupt moderation settings if supported by HW */
+ if (gc->pf_cap_flags1 & GDMA_PF_CAP_FLAG_1_DYN_INTERRUPT_MODERATION) {
+ apc->intr_modr_rx_usec = MANA_INTR_MODR_USEC_DEF;
+ apc->intr_modr_rx_comp = MANA_INTR_MODR_COMP_DEF;
+ apc->intr_modr_tx_usec = MANA_INTR_MODR_USEC_DEF;
+ apc->intr_modr_tx_comp = MANA_INTR_MODR_COMP_DEF;
+ apc->rx_dim_enabled = MANA_ADAPTIVE_RX_DEF;
+ apc->tx_dim_enabled = MANA_ADAPTIVE_TX_DEF;
+ }
+
mutex_init(&apc->vport_mutex);
apc->vport_use_count = 0;
diff --git a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
index 881df597d7f9..9e31e2595ae3 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
@@ -419,6 +419,15 @@ static int mana_get_coalesce(struct net_device *ndev,
!kernel_coal->rx_cqe_nsecs)
kernel_coal->rx_cqe_nsecs = MANA_RX_CQE_NSEC_DEF;
+ ec->rx_coalesce_usecs = apc->intr_modr_rx_usec;
+ ec->rx_max_coalesced_frames = apc->intr_modr_rx_comp;
+
+ ec->tx_coalesce_usecs = apc->intr_modr_tx_usec;
+ ec->tx_max_coalesced_frames = apc->intr_modr_tx_comp;
+
+ ec->use_adaptive_rx_coalesce = apc->rx_dim_enabled;
+ ec->use_adaptive_tx_coalesce = apc->tx_dim_enabled;
+
return 0;
}
@@ -428,9 +437,34 @@ static int mana_set_coalesce(struct net_device *ndev,
struct netlink_ext_ack *extack)
{
struct mana_port_context *apc = netdev_priv(ndev);
- u8 saved_cqe_coalescing_enable;
+ struct {
+ u16 intr_modr_rx_usec;
+ u16 intr_modr_rx_comp;
+ u16 intr_modr_tx_usec;
+ u16 intr_modr_tx_comp;
+ u8 cqe_coalescing_enable;
+ bool rx_dim_enabled;
+ bool tx_dim_enabled;
+ } saved;
+ bool modr_changed = false;
+ bool dim_changed = false;
+ struct gdma_context *gc;
int err;
+ gc = apc->ac->gdma_dev->gdma_context;
+
+ /* Both static and dynamic interrupt moderation (DIM) rely on the
+ * same HW capability advertised by the PF.
+ */
+ if ((ec->use_adaptive_rx_coalesce || ec->use_adaptive_tx_coalesce ||
+ ec->rx_coalesce_usecs || ec->tx_coalesce_usecs ||
+ ec->rx_max_coalesced_frames || ec->tx_max_coalesced_frames) &&
+ !(gc->pf_cap_flags1 & GDMA_PF_CAP_FLAG_1_DYN_INTERRUPT_MODERATION)) {
+ NL_SET_ERR_MSG(extack,
+ "Interrupt Moderation is not supported by HW");
+ return -EOPNOTSUPP;
+ }
+
if (kernel_coal->rx_cqe_frames != 1 &&
kernel_coal->rx_cqe_frames != MANA_RXCOMP_OOB_NUM_PPI) {
NL_SET_ERR_MSG_FMT(extack,
@@ -440,18 +474,129 @@ static int mana_set_coalesce(struct net_device *ndev,
return -EINVAL;
}
- saved_cqe_coalescing_enable = apc->cqe_coalescing_enable;
+ if (ec->rx_coalesce_usecs > MANA_INTR_MODR_USEC_MAX ||
+ ec->tx_coalesce_usecs > MANA_INTR_MODR_USEC_MAX) {
+ NL_SET_ERR_MSG_FMT(extack,
+ "coalesce usecs must be <= %lu",
+ MANA_INTR_MODR_USEC_MAX);
+ return -EINVAL;
+ }
+
+ if (ec->rx_max_coalesced_frames > MANA_INTR_MODR_COMP_MAX ||
+ ec->tx_max_coalesced_frames > MANA_INTR_MODR_COMP_MAX) {
+ NL_SET_ERR_MSG_FMT(extack,
+ "coalesce frames must be <= %lu",
+ MANA_INTR_MODR_COMP_MAX);
+ return -EINVAL;
+ }
+
+ if (ec->rx_coalesce_usecs != apc->intr_modr_rx_usec ||
+ ec->rx_max_coalesced_frames != apc->intr_modr_rx_comp ||
+ ec->tx_coalesce_usecs != apc->intr_modr_tx_usec ||
+ ec->tx_max_coalesced_frames != apc->intr_modr_tx_comp)
+ modr_changed = true;
+
+ saved.intr_modr_rx_usec = apc->intr_modr_rx_usec;
+ saved.intr_modr_rx_comp = apc->intr_modr_rx_comp;
+ saved.intr_modr_tx_usec = apc->intr_modr_tx_usec;
+ saved.intr_modr_tx_comp = apc->intr_modr_tx_comp;
+
+ apc->intr_modr_rx_usec = ec->rx_coalesce_usecs;
+ apc->intr_modr_rx_comp = ec->rx_max_coalesced_frames;
+ apc->intr_modr_tx_usec = ec->tx_coalesce_usecs;
+ apc->intr_modr_tx_comp = ec->tx_max_coalesced_frames;
+
+ if (!!ec->use_adaptive_rx_coalesce != apc->rx_dim_enabled ||
+ !!ec->use_adaptive_tx_coalesce != apc->tx_dim_enabled)
+ dim_changed = true;
+
+ saved.rx_dim_enabled = apc->rx_dim_enabled;
+ saved.tx_dim_enabled = apc->tx_dim_enabled;
+
+ saved.cqe_coalescing_enable = apc->cqe_coalescing_enable;
apc->cqe_coalescing_enable =
kernel_coal->rx_cqe_frames == MANA_RXCOMP_OOB_NUM_PPI;
- if (!apc->port_is_up)
+ if (!apc->port_is_up) {
+ WRITE_ONCE(apc->rx_dim_enabled, !!ec->use_adaptive_rx_coalesce);
+ WRITE_ONCE(apc->tx_dim_enabled, !!ec->use_adaptive_tx_coalesce);
return 0;
+ }
- err = mana_config_rss(apc, TRI_STATE_TRUE, false, false);
- if (err)
- apc->cqe_coalescing_enable = saved_cqe_coalescing_enable;
+ if (apc->cqe_coalescing_enable != saved.cqe_coalescing_enable) {
+ /* CQE coalescing setting is applied via RSS configuration. */
+ err = mana_config_rss(apc, TRI_STATE_TRUE, false, false);
+ if (err) {
+ netdev_err(ndev, "Change CQE coalescing failed: %d\n",
+ err);
+ apc->cqe_coalescing_enable =
+ saved.cqe_coalescing_enable;
+ apc->intr_modr_rx_usec = saved.intr_modr_rx_usec;
+ apc->intr_modr_rx_comp = saved.intr_modr_rx_comp;
+ apc->intr_modr_tx_usec = saved.intr_modr_tx_usec;
+ apc->intr_modr_tx_comp = saved.intr_modr_tx_comp;
+ return err;
+ }
+ }
- return err;
+ if (modr_changed || dim_changed) {
+ bool new_rx_dim = !!ec->use_adaptive_rx_coalesce;
+ bool new_tx_dim = !!ec->use_adaptive_tx_coalesce;
+ bool disable_rx_dim = saved.rx_dim_enabled && !new_rx_dim;
+ bool disable_tx_dim = saved.tx_dim_enabled && !new_tx_dim;
+ bool enable_rx_dim = !saved.rx_dim_enabled && new_rx_dim;
+ bool enable_tx_dim = !saved.tx_dim_enabled && new_tx_dim;
+ int q;
+
+ /* On disable: clear the per-port flag first and
+ * synchronize_net() so any in-flight NAPI poll observes
+ * the new value and will not schedule further DIM work;
+ * then drain pending work and restore the static
+ * moderation values.
+ */
+ if (disable_rx_dim)
+ WRITE_ONCE(apc->rx_dim_enabled, false);
+ if (disable_tx_dim)
+ WRITE_ONCE(apc->tx_dim_enabled, false);
+ if (disable_rx_dim || disable_tx_dim)
+ synchronize_net();
+
+ for (q = 0; q < apc->num_queues; q++) {
+ struct mana_cq *rx_cq = &apc->rxqs[q]->rx_cq;
+ struct mana_cq *tx_cq = &apc->tx_qp[q]->tx_cq;
+
+ if (disable_rx_dim)
+ mana_dim_change(rx_cq, false);
+ else if (enable_rx_dim)
+ mana_dim_change(rx_cq, true);
+ else if (!new_rx_dim && modr_changed)
+ mana_gd_ring_dim(rx_cq->gdma_cq,
+ apc->intr_modr_rx_usec, true,
+ apc->intr_modr_rx_comp, true);
+
+ if (disable_tx_dim)
+ mana_dim_change(tx_cq, false);
+ else if (enable_tx_dim)
+ mana_dim_change(tx_cq, true);
+ else if (!new_tx_dim && modr_changed)
+ mana_gd_ring_dim(tx_cq->gdma_cq,
+ apc->intr_modr_tx_usec, true,
+ apc->intr_modr_tx_comp, true);
+ }
+
+ /* Publish the enable flag with release semantics so a
+ * concurrent NAPI poll that observes it set also sees the DIM
+ * (re)init done by mana_dim_change() above.
+ */
+ if (enable_rx_dim)
+ /* pairs with smp_load_acquire() in mana_update_rx_dim() */
+ smp_store_release(&apc->rx_dim_enabled, true);
+ if (enable_tx_dim)
+ /* pairs with smp_load_acquire() in mana_update_tx_dim() */
+ smp_store_release(&apc->tx_dim_enabled, true);
+ }
+
+ return 0;
}
/* mana_set_channels - change the number of queues on a port
@@ -595,7 +740,13 @@ static int mana_get_link_ksettings(struct net_device *ndev,
}
const struct ethtool_ops mana_ethtool_ops = {
- .supported_coalesce_params = ETHTOOL_COALESCE_RX_CQE_FRAMES,
+ .supported_coalesce_params = ETHTOOL_COALESCE_RX_CQE_FRAMES |
+ ETHTOOL_COALESCE_RX_USECS |
+ ETHTOOL_COALESCE_RX_MAX_FRAMES |
+ ETHTOOL_COALESCE_TX_USECS |
+ ETHTOOL_COALESCE_TX_MAX_FRAMES |
+ ETHTOOL_COALESCE_USE_ADAPTIVE_RX |
+ ETHTOOL_COALESCE_USE_ADAPTIVE_TX,
.op_needs_rtnl = ETHTOOL_OP_NEEDS_RTNL_SCHANNELS |
ETHTOOL_OP_NEEDS_RTNL_SRINGPARAM |
ETHTOOL_OP_NEEDS_RTNL_GLINK,
diff --git a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c
index 3a5c25026858..19c2b870feed 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c
@@ -639,7 +639,7 @@ qed_dcbx_get_operational_params(struct qed_hwfn *p_hwfn,
flags = p_hwfn->p_dcbx_info->operational.flags;
/* If DCBx version is non zero, then negotiation
- * was successfuly performed
+ * was successfully performed
*/
p_operational = &params->operational;
enabled = !!(QED_MFW_GET_FIELD(flags, DCBX_CONFIG_VERSION) !=
diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
index 1a968596ca45..aa28025a1da1 100644
--- a/drivers/net/macsec.c
+++ b/drivers/net/macsec.c
@@ -646,7 +646,7 @@ static struct sk_buff *macsec_encrypt(struct sk_buff *skb,
}
unprotected_len = skb->len;
- eth = eth_hdr(skb);
+ eth = skb_eth_hdr(skb);
sci_present = macsec_send_sci(secy);
hh = skb_push(skb, macsec_extra_len(sci_present));
memmove(hh, eth, 2 * ETH_ALEN);
diff --git a/drivers/net/ppp/ppp_async.c b/drivers/net/ppp/ppp_async.c
index 93a7b0f6c4e7..583426d06381 100644
--- a/drivers/net/ppp/ppp_async.c
+++ b/drivers/net/ppp/ppp_async.c
@@ -49,8 +49,6 @@ struct asyncppp {
unsigned long xmit_flags;
u32 xaccm[8];
u32 raccm;
- unsigned int bytes_sent;
- unsigned int bytes_rcvd;
struct sk_buff *tpkt;
int tpkt_pos;
diff --git a/drivers/net/ppp/ppp_synctty.c b/drivers/net/ppp/ppp_synctty.c
index b7f243b416f8..0b1bd1635c39 100644
--- a/drivers/net/ppp/ppp_synctty.c
+++ b/drivers/net/ppp/ppp_synctty.c
@@ -59,8 +59,6 @@ struct syncppp {
unsigned long xmit_flags;
u32 xaccm[8];
u32 raccm;
- unsigned int bytes_sent;
- unsigned int bytes_rcvd;
struct sk_buff *tpkt;
unsigned long last_xmit;
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index faac359aa9ac..b3f1b7186721 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -706,6 +706,7 @@ static int ath10k_htt_rx_pop_paddr32_list(struct ath10k_htt *htt,
if (!(__le32_to_cpu(rxd_attention->flags) &
RX_ATTENTION_FLAGS_MSDU_DONE)) {
ath10k_warn(htt->ar, "tried to pop an incomplete frame, oops!\n");
+ __skb_queue_purge(list);
return -EIO;
}
}
@@ -770,6 +771,7 @@ static int ath10k_htt_rx_pop_paddr64_list(struct ath10k_htt *htt,
if (!(__le32_to_cpu(rxd_attention->flags) &
RX_ATTENTION_FLAGS_MSDU_DONE)) {
ath10k_warn(htt->ar, "tried to pop an incomplete frame, oops!\n");
+ __skb_queue_purge(list);
return -EIO;
}
}
diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c
index f566d699d074..1e1dea485760 100644
--- a/drivers/net/wireless/ath/ath11k/ahb.c
+++ b/drivers/net/wireless/ath/ath11k/ahb.c
@@ -996,6 +996,7 @@ static int ath11k_ahb_fw_resources_init(struct ath11k_base *ab)
ret = ath11k_ahb_setup_msa_resources(ab);
if (ret) {
ath11k_err(ab, "failed to setup msa resources\n");
+ of_node_put(node);
return ret;
}
diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c
index 9e90d8e3f155..8e2abc7b8383 100644
--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
@@ -4618,6 +4618,9 @@ static void ath11k_hal_rx_msdu_list_get(struct ath11k *ar,
msdu_details = &msdu_link->msdu_link[0];
for (i = 0; i < HAL_RX_NUM_MSDU_DESC; i++) {
+ if (!i && FIELD_GET(BUFFER_ADDR_INFO0_ADDR,
+ msdu_details[i].buf_addr_info.info0) == 0)
+ break;
if (FIELD_GET(BUFFER_ADDR_INFO0_ADDR,
msdu_details[i].buf_addr_info.info0) == 0) {
msdu_desc_info = &msdu_details[i - 1].rx_msdu_info;
diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c
index 35bb9e7a63a2..a163168f3617 100644
--- a/drivers/net/wireless/ath/ath11k/pci.c
+++ b/drivers/net/wireless/ath/ath11k/pci.c
@@ -199,6 +199,8 @@ static void ath11k_pci_soc_global_reset(struct ath11k_base *ab)
val |= PCIE_SOC_GLOBAL_RESET_V;
ath11k_pcic_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
+ /* Flush the posted write to the device */
+ ath11k_pcic_read32(ab, PCIE_SOC_GLOBAL_RESET);
/* TODO: exact time to sleep is uncertain */
delay = 10;
@@ -208,6 +210,8 @@ static void ath11k_pci_soc_global_reset(struct ath11k_base *ab)
val &= ~PCIE_SOC_GLOBAL_RESET_V;
ath11k_pcic_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
+ /* Flush the posted write to the device */
+ ath11k_pcic_read32(ab, PCIE_SOC_GLOBAL_RESET);
mdelay(delay);
diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c
index ae8a9acee3f1..ad74140e0fa5 100644
--- a/drivers/net/wireless/ath/ath12k/pci.c
+++ b/drivers/net/wireless/ath/ath12k/pci.c
@@ -189,6 +189,8 @@ static void ath12k_pci_soc_global_reset(struct ath12k_base *ab)
val |= PCIE_SOC_GLOBAL_RESET_V;
ath12k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
+ /* Flush the posted write to the device */
+ ath12k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
/* TODO: exact time to sleep is uncertain */
delay = 10;
@@ -198,6 +200,8 @@ static void ath12k_pci_soc_global_reset(struct ath12k_base *ab)
val &= ~PCIE_SOC_GLOBAL_RESET_V;
ath12k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
+ /* Flush the posted write to the device */
+ ath12k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
mdelay(delay);
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 6bcb90760bee..73be55cfa203 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -6,6 +6,7 @@
* Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
*/
+#include <linux/cleanup.h>
#include <linux/device.h>
#include <linux/export.h>
#include <linux/fs.h>
@@ -13,6 +14,7 @@
#include <linux/init.h>
#include <linux/kref.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/nvmem-consumer.h>
#include <linux/nvmem-provider.h>
#include <linux/gpio/consumer.h>
@@ -55,25 +57,44 @@ static BLOCKING_NOTIFIER_HEAD(nvmem_notifier);
static int __nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset,
void *val, size_t bytes)
{
- if (nvmem->reg_read)
- return nvmem->reg_read(nvmem->priv, offset, val, bytes);
+ struct nvmem_operations *ops;
- return -EINVAL;
+ guard(srcu)(&nvmem->srcu);
+ ops = srcu_dereference(nvmem->ops, &nvmem->srcu);
+ if (!ops)
+ return -ENODEV;
+
+ if (!ops->reg_read)
+ return -EOPNOTSUPP;
+
+ return ops->reg_read(nvmem->priv, offset, val, bytes);
}
static int __nvmem_reg_write(struct nvmem_device *nvmem, unsigned int offset,
void *val, size_t bytes)
{
- int ret;
+ struct nvmem_operations *ops;
+ int ret, wr_ok;
+
+ guard(srcu)(&nvmem->srcu);
+ ops = srcu_dereference(nvmem->ops, &nvmem->srcu);
+ if (!ops)
+ return -ENODEV;
- if (nvmem->reg_write) {
- gpiod_set_value_cansleep(nvmem->wp_gpio, 0);
- ret = nvmem->reg_write(nvmem->priv, offset, val, bytes);
- gpiod_set_value_cansleep(nvmem->wp_gpio, 1);
+ if (!ops->reg_write)
+ return -EOPNOTSUPP;
+
+ ret = gpiod_set_value_cansleep(nvmem->wp_gpio, 0);
+ if (ret)
return ret;
- }
- return -EINVAL;
+ wr_ok = ops->reg_write(nvmem->priv, offset, val, bytes);
+
+ ret = gpiod_set_value_cansleep(nvmem->wp_gpio, 1);
+ if (ret)
+ return ret;
+
+ return wr_ok;
}
static int nvmem_access_with_keepouts(struct nvmem_device *nvmem,
@@ -231,13 +252,12 @@ static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj,
count = round_down(count, nvmem->word_size);
- if (!nvmem->reg_read)
- return -EPERM;
-
rc = nvmem_reg_read(nvmem, pos, buf, count);
-
- if (rc)
+ if (rc) {
+ if (rc == -EOPNOTSUPP)
+ return -EPERM;
return rc;
+ }
return count;
}
@@ -264,19 +284,23 @@ static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj,
count = round_down(count, nvmem->word_size);
- if (!nvmem->reg_write || nvmem->read_only)
+ if (nvmem->read_only)
return -EPERM;
rc = nvmem_reg_write(nvmem, pos, buf, count);
-
- if (rc)
+ if (rc) {
+ if (rc == -EOPNOTSUPP)
+ return -EPERM;
return rc;
+ }
return count;
}
static umode_t nvmem_bin_attr_get_umode(struct nvmem_device *nvmem)
{
+ struct nvmem_operations *ops = rcu_dereference_raw(nvmem->ops);
+
umode_t mode = 0400;
if (!nvmem->root_only)
@@ -285,10 +309,10 @@ static umode_t nvmem_bin_attr_get_umode(struct nvmem_device *nvmem)
if (!nvmem->read_only)
mode |= 0200;
- if (!nvmem->reg_write)
+ if (!ops->reg_write)
mode &= ~0200;
- if (!nvmem->reg_read)
+ if (!ops->reg_read)
mode &= ~0444;
return mode;
@@ -319,6 +343,7 @@ static umode_t nvmem_attr_is_visible(struct kobject *kobj,
{
struct device *dev = kobj_to_dev(kobj);
struct nvmem_device *nvmem = to_nvmem_device(dev);
+ struct nvmem_operations *ops = rcu_dereference_raw(nvmem->ops);
/*
* If the device has no .reg_write operation, do not allow
@@ -327,7 +352,7 @@ static umode_t nvmem_attr_is_visible(struct kobject *kobj,
* can be forced into read-write mode using the 'force_ro'
* attribute.
*/
- if (attr == &dev_attr_force_ro.attr && !nvmem->reg_write)
+ if (attr == &dev_attr_force_ro.attr && !ops->reg_write)
return 0; /* Attribute not visible */
return attr->mode;
@@ -445,10 +470,9 @@ static int nvmem_sysfs_setup_compat(struct nvmem_device *nvmem,
return 0;
}
-static void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem,
- const struct nvmem_config *config)
+static void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem)
{
- if (config->compat)
+ if (nvmem->flags & FLAG_COMPAT)
device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom);
}
@@ -461,27 +485,23 @@ static int nvmem_populate_sysfs_cells(struct nvmem_device *nvmem)
const struct bin_attribute **pattrs;
struct bin_attribute *attrs;
unsigned int ncells = 0, i = 0;
- int ret = 0;
+ int ret;
- mutex_lock(&nvmem_mutex);
+ guard(mutex)(&nvmem_mutex);
if (list_empty(&nvmem->cells) || nvmem->sysfs_cells_populated)
- goto unlock_mutex;
+ return 0;
/* Allocate an array of attributes with a sentinel */
ncells = list_count_nodes(&nvmem->cells);
pattrs = devm_kcalloc(&nvmem->dev, ncells + 1,
sizeof(struct bin_attribute *), GFP_KERNEL);
- if (!pattrs) {
- ret = -ENOMEM;
- goto unlock_mutex;
- }
+ if (!pattrs)
+ return -ENOMEM;
attrs = devm_kcalloc(&nvmem->dev, ncells, sizeof(struct bin_attribute), GFP_KERNEL);
- if (!attrs) {
- ret = -ENOMEM;
- goto unlock_mutex;
- }
+ if (!attrs)
+ return -ENOMEM;
/* Initialize each attribute to take the name and size of the cell */
list_for_each_entry(entry, &nvmem->cells, node) {
@@ -494,10 +514,8 @@ static int nvmem_populate_sysfs_cells(struct nvmem_device *nvmem)
attrs[i].size = entry->bytes;
attrs[i].read = &nvmem_cell_attr_read;
attrs[i].private = entry;
- if (!attrs[i].attr.name) {
- ret = -ENOMEM;
- goto unlock_mutex;
- }
+ if (!attrs[i].attr.name)
+ return -ENOMEM;
pattrs[i] = &attrs[i];
i++;
@@ -507,13 +525,10 @@ static int nvmem_populate_sysfs_cells(struct nvmem_device *nvmem)
ret = device_add_group(&nvmem->dev, &group);
if (ret)
- goto unlock_mutex;
+ return ret;
nvmem->sysfs_cells_populated = true;
-unlock_mutex:
- mutex_unlock(&nvmem_mutex);
-
return ret;
}
@@ -524,36 +539,17 @@ static int nvmem_sysfs_setup_compat(struct nvmem_device *nvmem,
{
return -ENOSYS;
}
-static void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem,
- const struct nvmem_config *config)
+static void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem)
{
}
#endif /* CONFIG_NVMEM_SYSFS */
-static void nvmem_release(struct device *dev)
-{
- struct nvmem_device *nvmem = to_nvmem_device(dev);
-
- ida_free(&nvmem_ida, nvmem->id);
- gpiod_put(nvmem->wp_gpio);
- kfree(nvmem);
-}
-
-static const struct device_type nvmem_provider_type = {
- .release = nvmem_release,
-};
-
-static const struct bus_type nvmem_bus_type = {
- .name = "nvmem",
-};
-
static void nvmem_cell_entry_drop(struct nvmem_cell_entry *cell)
{
blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_REMOVE, cell);
- mutex_lock(&nvmem_mutex);
- list_del(&cell->node);
- mutex_unlock(&nvmem_mutex);
+ scoped_guard(mutex, &nvmem_mutex)
+ list_del(&cell->node);
of_node_put(cell->np);
kfree_const(cell->name);
kfree(cell);
@@ -567,11 +563,29 @@ static void nvmem_device_remove_all_cells(const struct nvmem_device *nvmem)
nvmem_cell_entry_drop(cell);
}
+static void nvmem_release(struct device *dev)
+{
+ struct nvmem_device *nvmem = to_nvmem_device(dev);
+
+ gpiod_put(nvmem->wp_gpio);
+ nvmem_device_remove_all_cells(nvmem);
+ ida_free(&nvmem_ida, nvmem->id);
+ cleanup_srcu_struct(&nvmem->srcu);
+ kfree(nvmem);
+}
+
+static const struct device_type nvmem_provider_type = {
+ .release = nvmem_release,
+};
+
+static const struct bus_type nvmem_bus_type = {
+ .name = "nvmem",
+};
+
static void nvmem_cell_entry_add(struct nvmem_cell_entry *cell)
{
- mutex_lock(&nvmem_mutex);
- list_add_tail(&cell->node, &cell->nvmem->cells);
- mutex_unlock(&nvmem_mutex);
+ scoped_guard(mutex, &nvmem_mutex)
+ list_add_tail(&cell->node, &cell->nvmem->cells);
blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_ADD, cell);
}
@@ -721,14 +735,14 @@ nvmem_find_cell_entry_by_name(struct nvmem_device *nvmem, const char *cell_id)
{
struct nvmem_cell_entry *iter, *cell = NULL;
- mutex_lock(&nvmem_mutex);
+ guard(mutex)(&nvmem_mutex);
+
list_for_each_entry(iter, &nvmem->cells, node) {
if (strcmp(cell_id, iter->name) == 0) {
cell = iter;
break;
}
}
- mutex_unlock(&nvmem_mutex);
return cell;
}
@@ -899,6 +913,7 @@ EXPORT_SYMBOL_GPL(nvmem_layout_unregister);
struct nvmem_device *nvmem_register(const struct nvmem_config *config)
{
+ struct nvmem_operations *ops;
struct nvmem_device *nvmem;
int rval;
@@ -912,8 +927,15 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
if (!nvmem)
return ERR_PTR(-ENOMEM);
+ ops = kzalloc_obj(*ops);
+ if (!ops) {
+ kfree(nvmem);
+ return ERR_PTR(-ENOMEM);
+ }
+
rval = ida_alloc(&nvmem_ida, GFP_KERNEL);
if (rval < 0) {
+ kfree(ops);
kfree(nvmem);
return ERR_PTR(rval);
}
@@ -923,6 +945,21 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
nvmem->dev.type = &nvmem_provider_type;
nvmem->dev.bus = &nvmem_bus_type;
nvmem->dev.parent = config->dev;
+ INIT_LIST_HEAD(&nvmem->cells);
+
+ /*
+ * Must happen before we assign the release() callback in
+ * device_initialize().
+ */
+ rval = init_srcu_struct(&nvmem->srcu);
+ if (rval) {
+ ida_free(&nvmem_ida, nvmem->id);
+ kfree(ops);
+ kfree(nvmem);
+ return ERR_PTR(rval);
+ }
+
+ rcu_assign_pointer(nvmem->ops, ops);
device_initialize(&nvmem->dev);
@@ -935,10 +972,11 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
goto err_put_device;
}
- kref_init(&nvmem->refcnt);
- INIT_LIST_HEAD(&nvmem->cells);
nvmem->fixup_dt_cell_info = config->fixup_dt_cell_info;
+ ops->reg_read = config->reg_read;
+ ops->reg_write = config->reg_write;
+
nvmem->owner = config->owner;
if (!nvmem->owner && config->dev->driver)
nvmem->owner = config->dev->driver->owner;
@@ -948,8 +986,6 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
nvmem->root_only = config->root_only;
nvmem->priv = config->priv;
nvmem->type = config->type;
- nvmem->reg_read = config->reg_read;
- nvmem->reg_write = config->reg_write;
nvmem->keepout = config->keepout;
nvmem->nkeepout = config->nkeepout;
if (config->of_node)
@@ -975,7 +1011,7 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
goto err_put_device;
nvmem->read_only = device_property_present(config->dev, "read-only") ||
- config->read_only || !nvmem->reg_write;
+ config->read_only || !ops->reg_write;
#ifdef CONFIG_NVMEM_SYSFS
nvmem->dev.groups = nvmem_dev_groups;
@@ -996,24 +1032,24 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
if (config->cells) {
rval = nvmem_add_cells(nvmem, config->cells, config->ncells);
if (rval)
- goto err_remove_cells;
+ goto err_remove_compat;
}
if (config->add_legacy_fixed_of_cells) {
rval = nvmem_add_cells_from_legacy_of(nvmem);
if (rval)
- goto err_remove_cells;
+ goto err_remove_compat;
}
rval = nvmem_add_cells_from_fixed_layout(nvmem);
if (rval)
- goto err_remove_cells;
+ goto err_remove_compat;
dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name);
rval = device_add(&nvmem->dev);
if (rval)
- goto err_remove_cells;
+ goto err_remove_compat;
rval = nvmem_populate_layout(nvmem);
if (rval)
@@ -1039,42 +1075,40 @@ err_destroy_layout:
#endif
err_remove_dev:
device_del(&nvmem->dev);
-err_remove_cells:
- nvmem_device_remove_all_cells(nvmem);
- if (config->compat)
- nvmem_sysfs_remove_compat(nvmem, config);
+err_remove_compat:
+ nvmem_sysfs_remove_compat(nvmem);
err_put_device:
+ ops = rcu_replace_pointer(nvmem->ops, NULL, true);
+ synchronize_srcu(&nvmem->srcu);
put_device(&nvmem->dev);
+ kfree(ops);
return ERR_PTR(rval);
}
EXPORT_SYMBOL_GPL(nvmem_register);
-static void nvmem_device_release(struct kref *kref)
+/**
+ * nvmem_unregister() - Unregister previously registered nvmem device
+ *
+ * @nvmem: Pointer to previously registered nvmem device.
+ */
+void nvmem_unregister(struct nvmem_device *nvmem)
{
- struct nvmem_device *nvmem;
+ struct nvmem_operations *ops;
- nvmem = container_of(kref, struct nvmem_device, refcnt);
+ if (!nvmem)
+ return;
blocking_notifier_call_chain(&nvmem_notifier, NVMEM_REMOVE, nvmem);
- if (nvmem->flags & FLAG_COMPAT)
- device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom);
+ ops = rcu_replace_pointer(nvmem->ops, NULL, true);
+ synchronize_srcu(&nvmem->srcu);
- nvmem_device_remove_all_cells(nvmem);
+ nvmem_sysfs_remove_compat(nvmem);
nvmem_destroy_layout(nvmem);
- device_unregister(&nvmem->dev);
-}
+ kfree(ops);
-/**
- * nvmem_unregister() - Unregister previously registered nvmem device
- *
- * @nvmem: Pointer to previously registered nvmem device.
- */
-void nvmem_unregister(struct nvmem_device *nvmem)
-{
- if (nvmem)
- kref_put(&nvmem->refcnt, nvmem_device_release);
+ device_unregister(&nvmem->dev);
}
EXPORT_SYMBOL_GPL(nvmem_unregister);
@@ -1112,17 +1146,17 @@ struct nvmem_device *devm_nvmem_register(struct device *dev,
}
EXPORT_SYMBOL_GPL(devm_nvmem_register);
-static struct nvmem_device *__nvmem_device_get(void *data,
+static struct nvmem_device *nvmem_device_match(void *data,
int (*match)(struct device *dev, const void *data))
{
struct nvmem_device *nvmem = NULL;
struct device *dev;
- mutex_lock(&nvmem_mutex);
- dev = bus_find_device(&nvmem_bus_type, NULL, data, match);
- if (dev)
- nvmem = to_nvmem_device(dev);
- mutex_unlock(&nvmem_mutex);
+ scoped_guard(mutex, &nvmem_mutex) {
+ dev = bus_find_device(&nvmem_bus_type, NULL, data, match);
+ if (dev)
+ nvmem = to_nvmem_device(dev);
+ }
if (!nvmem)
return ERR_PTR(-EPROBE_DEFER);
@@ -1135,18 +1169,9 @@ static struct nvmem_device *__nvmem_device_get(void *data,
return ERR_PTR(-EINVAL);
}
- kref_get(&nvmem->refcnt);
-
return nvmem;
}
-static void __nvmem_device_put(struct nvmem_device *nvmem)
-{
- put_device(&nvmem->dev);
- module_put(nvmem->owner);
- kref_put(&nvmem->refcnt, nvmem_device_release);
-}
-
#if IS_ENABLED(CONFIG_OF)
/**
* of_nvmem_device_get() - Get nvmem device from a given id
@@ -1171,7 +1196,7 @@ struct nvmem_device *of_nvmem_device_get(struct device_node *np, const char *id)
if (!nvmem_np)
return ERR_PTR(-ENOENT);
- nvmem = __nvmem_device_get(nvmem_np, device_match_of_node);
+ nvmem = nvmem_device_match(nvmem_np, device_match_of_node);
of_node_put(nvmem_np);
return nvmem;
}
@@ -1199,7 +1224,7 @@ struct nvmem_device *nvmem_device_get(struct device *dev, const char *dev_name)
}
- return __nvmem_device_get((void *)dev_name, device_match_name);
+ return nvmem_device_match((void *)dev_name, device_match_name);
}
EXPORT_SYMBOL_GPL(nvmem_device_get);
@@ -1215,7 +1240,7 @@ EXPORT_SYMBOL_GPL(nvmem_device_get);
struct nvmem_device *nvmem_device_find(void *data,
int (*match)(struct device *dev, const void *data))
{
- return __nvmem_device_get(data, match);
+ return nvmem_device_match(data, match);
}
EXPORT_SYMBOL_GPL(nvmem_device_find);
@@ -1259,7 +1284,8 @@ EXPORT_SYMBOL_GPL(devm_nvmem_device_put);
*/
void nvmem_device_put(struct nvmem_device *nvmem)
{
- __nvmem_device_put(nvmem);
+ module_put(nvmem->owner);
+ put_device(&nvmem->dev);
}
EXPORT_SYMBOL_GPL(nvmem_device_put);
@@ -1332,35 +1358,32 @@ nvmem_cell_get_from_lookup(struct device *dev, const char *con_id)
dev_id = dev_name(dev);
- mutex_lock(&nvmem_lookup_mutex);
+ guard(mutex)(&nvmem_lookup_mutex);
list_for_each_entry(lookup, &nvmem_lookup_list, node) {
if ((strcmp(lookup->dev_id, dev_id) == 0) &&
(strcmp(lookup->con_id, con_id) == 0)) {
/* This is the right entry. */
- nvmem = __nvmem_device_get((void *)lookup->nvmem_name,
+ nvmem = nvmem_device_match((void *)lookup->nvmem_name,
device_match_name);
- if (IS_ERR(nvmem)) {
+ if (IS_ERR(nvmem))
/* Provider may not be registered yet. */
- cell = ERR_CAST(nvmem);
- break;
- }
+ return ERR_CAST(nvmem);
cell_entry = nvmem_find_cell_entry_by_name(nvmem,
lookup->cell_name);
if (!cell_entry) {
- __nvmem_device_put(nvmem);
+ nvmem_device_put(nvmem);
cell = ERR_PTR(-ENOENT);
} else {
cell = nvmem_create_cell(cell_entry, con_id, 0);
if (IS_ERR(cell))
- __nvmem_device_put(nvmem);
+ nvmem_device_put(nvmem);
}
break;
}
}
- mutex_unlock(&nvmem_lookup_mutex);
return cell;
}
@@ -1374,18 +1397,16 @@ static void nvmem_layout_module_put(struct nvmem_device *nvmem)
static struct nvmem_cell_entry *
nvmem_find_cell_entry_by_node(struct nvmem_device *nvmem, struct device_node *np)
{
- struct nvmem_cell_entry *iter, *cell = NULL;
+ struct nvmem_cell_entry *cell;
- mutex_lock(&nvmem_mutex);
- list_for_each_entry(iter, &nvmem->cells, node) {
- if (np == iter->np) {
- cell = iter;
- break;
- }
+ guard(mutex)(&nvmem_mutex);
+
+ list_for_each_entry(cell, &nvmem->cells, node) {
+ if (np == cell->np)
+ return cell;
}
- mutex_unlock(&nvmem_mutex);
- return cell;
+ return NULL;
}
static int nvmem_layout_module_get_optional(struct nvmem_device *nvmem)
@@ -1455,7 +1476,7 @@ struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id)
}
}
- nvmem = __nvmem_device_get(nvmem_np, device_match_of_node);
+ nvmem = nvmem_device_match(nvmem_np, device_match_of_node);
of_node_put(nvmem_np);
if (IS_ERR(nvmem)) {
of_node_put(cell_np);
@@ -1465,7 +1486,7 @@ struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id)
ret = nvmem_layout_module_get_optional(nvmem);
if (ret) {
of_node_put(cell_np);
- __nvmem_device_put(nvmem);
+ nvmem_device_put(nvmem);
return ERR_PTR(ret);
}
@@ -1474,14 +1495,14 @@ struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id)
if (!cell_entry) {
nvmem_layout_module_put(nvmem);
ret = nvmem->layout ? -EPROBE_DEFER : -ENOENT;
- __nvmem_device_put(nvmem);
+ nvmem_device_put(nvmem);
return ERR_PTR(ret);
}
cell = nvmem_create_cell(cell_entry, id, cell_index);
if (IS_ERR(cell)) {
nvmem_layout_module_put(nvmem);
- __nvmem_device_put(nvmem);
+ nvmem_device_put(nvmem);
}
return cell;
@@ -1596,7 +1617,7 @@ void nvmem_cell_put(struct nvmem_cell *cell)
kfree(cell);
nvmem_layout_module_put(nvmem);
- __nvmem_device_put(nvmem);
+ nvmem_device_put(nvmem);
}
EXPORT_SYMBOL_GPL(nvmem_cell_put);
@@ -2118,10 +2139,10 @@ void nvmem_add_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries)
{
int i;
- mutex_lock(&nvmem_lookup_mutex);
+ guard(mutex)(&nvmem_lookup_mutex);
+
for (i = 0; i < nentries; i++)
list_add_tail(&entries[i].node, &nvmem_lookup_list);
- mutex_unlock(&nvmem_lookup_mutex);
}
EXPORT_SYMBOL_GPL(nvmem_add_cell_lookups);
@@ -2136,10 +2157,10 @@ void nvmem_del_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries)
{
int i;
- mutex_lock(&nvmem_lookup_mutex);
+ guard(mutex)(&nvmem_lookup_mutex);
+
for (i = 0; i < nentries; i++)
list_del(&entries[i].node);
- mutex_unlock(&nvmem_lookup_mutex);
}
EXPORT_SYMBOL_GPL(nvmem_del_cell_lookups);
diff --git a/drivers/nvmem/internals.h b/drivers/nvmem/internals.h
index 18fed57270e5..17418fd0dcc9 100644
--- a/drivers/nvmem/internals.h
+++ b/drivers/nvmem/internals.h
@@ -6,15 +6,21 @@
#include <linux/device.h>
#include <linux/nvmem-consumer.h>
#include <linux/nvmem-provider.h>
+#include <linux/srcu.h>
+
+/* Hold pointers to callbacks owned by the nvmem provider module. */
+struct nvmem_operations {
+ nvmem_reg_read_t reg_read;
+ nvmem_reg_write_t reg_write;
+};
struct nvmem_device {
struct module *owner;
struct device dev;
- struct list_head node;
+ struct srcu_struct srcu;
int stride;
int word_size;
int id;
- struct kref refcnt;
size_t size;
bool read_only;
bool root_only;
@@ -27,10 +33,9 @@ struct nvmem_device {
struct nvmem_cell_info *cell);
const struct nvmem_keepout *keepout;
unsigned int nkeepout;
- nvmem_reg_read_t reg_read;
- nvmem_reg_write_t reg_write;
struct gpio_desc *wp_gpio;
struct nvmem_layout *layout;
+ struct nvmem_operations __rcu *ops;
void *priv;
bool sysfs_cells_populated;
};
diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c
index 96efa00d9743..9cb23780093d 100644
--- a/drivers/pci/ats.c
+++ b/drivers/pci/ats.c
@@ -40,10 +40,13 @@ void pci_ats_init(struct pci_dev *dev)
*/
bool pci_ats_supported(struct pci_dev *dev)
{
- if (!dev->ats_cap)
+ if (!dev->ats_cap || dev->untrusted)
return false;
- return (dev->untrusted == 0);
+ if (dev->is_virtfn)
+ return pci_ats_supported(pci_physfn(dev));
+
+ return true;
}
EXPORT_SYMBOL_GPL(pci_ats_supported);
@@ -70,8 +73,12 @@ int pci_prepare_ats(struct pci_dev *dev, int ps)
if (ps < PCI_ATS_MIN_STU)
return -EINVAL;
- if (dev->is_virtfn)
+ if (dev->is_virtfn) {
+ if (pci_physfn(dev)->ats_stu != ps)
+ return -EINVAL;
+
return 0;
+ }
dev->ats_stu = ps;
ctrl = PCI_ATS_CTRL_STU(dev->ats_stu - PCI_ATS_MIN_STU);
diff --git a/drivers/pci/controller/cadence/pcie-cadence-plat.c b/drivers/pci/controller/cadence/pcie-cadence-plat.c
index b067a3296dd3..a1ea24fc3b63 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-plat.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-plat.c
@@ -163,6 +163,7 @@ static const struct of_device_id cdns_plat_pcie_of_match[] = {
},
{},
};
+MODULE_DEVICE_TABLE(of, cdns_plat_pcie_of_match);
static struct platform_driver cdns_plat_pcie_driver = {
.driver = {
diff --git a/drivers/phy/motorola/phy-cpcap-usb.c b/drivers/phy/motorola/phy-cpcap-usb.c
index 7cb020dd3423..9591672b0511 100644
--- a/drivers/phy/motorola/phy-cpcap-usb.c
+++ b/drivers/phy/motorola/phy-cpcap-usb.c
@@ -717,3 +717,4 @@ MODULE_ALIAS("platform:cpcap_usb");
MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>");
MODULE_DESCRIPTION("CPCAP usb phy driver");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/pinctrl/intel/pinctrl-tigerlake.c b/drivers/pinctrl/intel/pinctrl-tigerlake.c
index 3ac35a153e8c..93234f4a9bd0 100644
--- a/drivers/pinctrl/intel/pinctrl-tigerlake.c
+++ b/drivers/pinctrl/intel/pinctrl-tigerlake.c
@@ -329,6 +329,34 @@ static const struct pinctrl_pin_desc tgllp_pins[] = {
PINCTRL_PIN(276, "SPI0_CLK_LOOPBK"),
};
+static const unsigned int tgllp_i2c0_pins[] = { 5, 6 };
+static const unsigned int tgllp_i2c1_pins[] = { 7, 8 };
+static const unsigned int tgllp_pwm0_pins[] = { 99 };
+static const unsigned int tgllp_uart1_pins[] = { 85, 86, 87, 88 };
+static const unsigned int tgllp_ssp2_pins[] = { 108, 109, 110, 111 };
+
+static const struct intel_pingroup tgllp_groups[] = {
+ PIN_GROUP("i2c0_grp", tgllp_i2c0_pins, 2),
+ PIN_GROUP("i2c1_grp", tgllp_i2c1_pins, 2),
+ PIN_GROUP("pwm0_grp", tgllp_pwm0_pins, 2),
+ PIN_GROUP("uart1_grp", tgllp_uart1_pins, 2),
+ PIN_GROUP("ssp2_grp", tgllp_ssp2_pins, 7),
+};
+
+static const char * const tgllp_i2c0_groups[] = { "i2c0_grp" };
+static const char * const tgllp_i2c1_groups[] = { "i2c1_grp" };
+static const char * const tgllp_pwm0_groups[] = { "pwm0_grp" };
+static const char * const tgllp_uart1_groups[] = { "uart1_grp" };
+static const char * const tgllp_ssp2_groups[] = { "ssp2_grp" };
+
+static const struct intel_function tgllp_functions[] = {
+ FUNCTION("i2c0", tgllp_i2c0_groups),
+ FUNCTION("i2c1", tgllp_i2c1_groups),
+ FUNCTION("pwm0", tgllp_pwm0_groups),
+ FUNCTION("uart1", tgllp_uart1_groups),
+ FUNCTION("ssp2", tgllp_ssp2_groups),
+};
+
static const struct intel_padgroup tgllp_community0_gpps[] = {
INTEL_GPP(0, 0, 25, 0), /* GPP_B */
INTEL_GPP(1, 26, 41, 32), /* GPP_T */
@@ -366,6 +394,10 @@ static const struct intel_community tgllp_communities[] = {
static const struct intel_pinctrl_soc_data tgllp_soc_data = {
.pins = tgllp_pins,
.npins = ARRAY_SIZE(tgllp_pins),
+ .groups = tgllp_groups,
+ .ngroups = ARRAY_SIZE(tgllp_groups),
+ .functions = tgllp_functions,
+ .nfunctions = ARRAY_SIZE(tgllp_functions),
.communities = tgllp_communities,
.ncommunities = ARRAY_SIZE(tgllp_communities),
};
diff --git a/drivers/pinctrl/pinctrl-upboard.c b/drivers/pinctrl/pinctrl-upboard.c
index f8c8b9d84990..de1920a3387d 100644
--- a/drivers/pinctrl/pinctrl-upboard.c
+++ b/drivers/pinctrl/pinctrl-upboard.c
@@ -912,6 +912,19 @@ static const struct upboard_pinctrl_map upboard_pinctrl_map_apl01 = {
.nmaps = ARRAY_SIZE(pinctrl_map_apl01),
};
+static const struct pinctrl_map pinctrl_map_adl[] = {
+ PIN_MAP_MUX_GROUP_DEFAULT("upboard-pinctrl", "INTC1055:00", "i2c0_grp", "i2c0"),
+ PIN_MAP_MUX_GROUP_DEFAULT("upboard-pinctrl", "INTC1055:00", "i2c1_grp", "i2c1"),
+ PIN_MAP_MUX_GROUP_DEFAULT("upboard-pinctrl", "INTC1055:00", "pwm0_grp", "pwm0"),
+ PIN_MAP_MUX_GROUP_DEFAULT("upboard-pinctrl", "INTC1055:00", "uart1_grp", "uart1"),
+ PIN_MAP_MUX_GROUP_DEFAULT("upboard-pinctrl", "INTC1055:00", "ssp2_grp", "ssp2"),
+};
+
+static const struct upboard_pinctrl_map upboard_pinctrl_map_adl = {
+ .maps = &pinctrl_map_adl[0],
+ .nmaps = ARRAY_SIZE(pinctrl_map_adl),
+};
+
static const struct dmi_system_id dmi_platform_info[] = {
{
/* UP Squared */
@@ -921,6 +934,14 @@ static const struct dmi_system_id dmi_platform_info[] = {
},
.driver_data = (void *)&upboard_pinctrl_map_apl01,
},
+ {
+ /* UP Xtreme i12 */
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "AAEON"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "UPX-ADLP01"),
+ },
+ .driver_data = (void *)&upboard_pinctrl_map_adl,
+ },
{ }
};
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c
index fe94ce5f9b81..9c720f49465b 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -994,6 +994,16 @@ static void msm_gpio_irq_ack(struct irq_data *d)
if (test_bit(d->hwirq, pctrl->skip_wake_irqs)) {
if (test_bit(d->hwirq, pctrl->dual_edge_irqs))
msm_gpio_update_dual_edge_parent(d);
+
+ /*
+ * During early initialization of the IRQ hierarchy,
+ * irq_ack() is called by __irq_set_handler() before
+ * the parent IRQ chip has been set up. This is why
+ * we additionally need to check for d->parent_data->chip.
+ */
+
+ if (d->parent_data->chip && d->parent_data->chip->irq_ack)
+ irq_chip_ack_parent(d);
return;
}
@@ -1064,7 +1074,10 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)
if (test_bit(d->hwirq, pctrl->skip_wake_irqs)) {
clear_bit(d->hwirq, pctrl->dual_edge_irqs);
- irq_set_handler_locked(d, handle_fasteoi_irq);
+ if (type & IRQ_TYPE_LEVEL_MASK)
+ irq_set_handler_locked(d, handle_fasteoi_irq);
+ else
+ irq_set_handler_locked(d, handle_fasteoi_ack_irq);
return 0;
}
diff --git a/drivers/pinctrl/qcom/pinctrl-x1e80100.c b/drivers/pinctrl/qcom/pinctrl-x1e80100.c
index 8d2b8246170b..e4c0abcd95b9 100644
--- a/drivers/pinctrl/qcom/pinctrl-x1e80100.c
+++ b/drivers/pinctrl/qcom/pinctrl-x1e80100.c
@@ -1836,9 +1836,7 @@ static const struct msm_pinctrl_soc_data x1e80100_pinctrl = {
.ngroups = ARRAY_SIZE(x1e80100_groups),
.ngpios = 239,
.wakeirq_map = x1e80100_pdc_map,
- /* TODO: Enabling PDC currently breaks GPIO interrupts */
- .nwakeirq_map = 0,
- /* .nwakeirq_map = ARRAY_SIZE(x1e80100_pdc_map), */
+ .nwakeirq_map = ARRAY_SIZE(x1e80100_pdc_map),
.egpio_func = 9,
};
diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c
index 388a3e1a488c..b38aa010053e 100644
--- a/drivers/platform/surface/surfacepro3_button.c
+++ b/drivers/platform/surface/surfacepro3_button.c
@@ -20,7 +20,6 @@
#define SURFACE_PRO3_BUTTON_HID "MSHW0028"
#define SURFACE_PRO4_BUTTON_HID "MSHW0040"
#define SURFACE_BUTTON_OBJ_NAME "VGBI"
-#define SURFACE_BUTTON_DEVICE_NAME "Surface Pro 3/4 Buttons"
#define MSHW0040_DSM_REVISION 0x01
#define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision
@@ -212,11 +211,10 @@ static int surface_button_probe(struct platform_device *pdev)
goto err_free_button;
}
- strscpy(acpi_device_name(device), SURFACE_BUTTON_DEVICE_NAME);
snprintf(button->phys, sizeof(button->phys), "%s/buttons",
acpi_device_hid(device));
- input->name = acpi_device_name(device);
+ input->name = "Surface Pro 3/4 Buttons";
input->phys = button->phys;
input->id.bustype = BUS_HOST;
input->dev.parent = &pdev->dev;
@@ -239,8 +237,8 @@ static int surface_button_probe(struct platform_device *pdev)
goto err_free_button;
}
- dev_info(&pdev->dev, "%s [%s]\n", acpi_device_name(device),
- acpi_device_bid(device));
+ dev_info(&pdev->dev, "%s [%s]\n", input->name, acpi_device_bid(device));
+
return 0;
err_free_input:
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index b54b5212b204..957034f39e4e 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -802,7 +802,6 @@ config LG_LAPTOP
tristate "LG Laptop Extras"
depends on ACPI
depends on ACPI_BATTERY
- depends on ACPI_WMI
depends on INPUT
select INPUT_SPARSEKMAP
select NEW_LEDS
diff --git a/drivers/platform/x86/amd/pmc/pmc.c b/drivers/platform/x86/amd/pmc/pmc.c
index 347c3f6c5ae7..a37083cdb908 100644
--- a/drivers/platform/x86/amd/pmc/pmc.c
+++ b/drivers/platform/x86/amd/pmc/pmc.c
@@ -33,6 +33,28 @@
#include "pmc.h"
+static const struct amd_pmc_bit_map soc15_ip_blk_v3[] = {
+ {"VDDCR", BIT(0)},
+ {"VDDCR_LP", BIT(1)},
+ {"LSOCV", BIT(2)},
+ {"DISPLAY", BIT(3)},
+ {"VCN", BIT(4)},
+ {"JPEG", BIT(5)},
+ {"UMSCH", BIT(6)},
+ {"VPE", BIT(7)},
+ {"MPM", BIT(8)},
+ {"NPU", BIT(9)},
+ {"USB_HC0", BIT(10)},
+ {"eUSB_HC0", BIT(11)},
+ {"RT0_ADP_HC1", BIT(12)},
+ {"RT1_ADP_HC1", BIT(13)},
+ {"RT2_ADP_HC2", BIT(14)},
+ {"USB4_RT0", BIT(15)},
+ {"USB4_RT1", BIT(16)},
+ {"USB4-RT2", BIT(17)},
+ {"LAPIC", BIT(18)},
+};
+
static const struct amd_pmc_bit_map soc15_ip_blk_v2[] = {
{"DISPLAY", BIT(0)},
{"CPU", BIT(1)},
@@ -159,9 +181,9 @@ static const struct amd_pmc_cpu_info amd_1ah_m80_cpu_info = {
.smu_msg = AMD_PMC_REGISTER_MSG_1AH_80H,
.smu_arg = AMD_PMC_REGISTER_ARG_1AH_80H,
.smu_rsp = AMD_PMC_REGISTER_RSP_1AH_80H,
- .num_ips = ARRAY_SIZE(soc15_ip_blk),
+ .num_ips = ARRAY_SIZE(soc15_ip_blk_v3),
.scratch_reg = AMD_PMC_SCRATCH_REG_1AH,
- .ips_ptr = soc15_ip_blk,
+ .ips_ptr = soc15_ip_blk_v3,
.os_hint = MSG_OS_HINT_RN,
};
diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c
index f2a880eb0cdf..93d9665717af 100644
--- a/drivers/platform/x86/asus-armoury.c
+++ b/drivers/platform/x86/asus-armoury.c
@@ -16,6 +16,7 @@
#include <linux/acpi.h>
#include <linux/array_size.h>
#include <linux/bitfield.h>
+#include <linux/cleanup.h>
#include <linux/device.h>
#include <linux/dmi.h>
#include <linux/err.h>
@@ -1007,10 +1008,11 @@ fail_class_get:
/* Init / exit ****************************************************************/
/* Set up the min/max and defaults for ROG tunables */
-static void init_rog_tunables(void)
+static int init_rog_tunables(void)
{
const struct power_limits *ac_limits, *dc_limits;
- struct rog_tunables *ac_rog_tunables = NULL, *dc_rog_tunables = NULL;
+ struct rog_tunables *ac_rog_tunables __free(kfree) = NULL;
+ struct rog_tunables *dc_rog_tunables __free(kfree) = NULL;
const struct power_data *power_data;
const struct dmi_system_id *dmi_id;
@@ -1018,14 +1020,14 @@ static void init_rog_tunables(void)
dmi_id = dmi_first_match(power_limits);
if (!dmi_id) {
pr_warn("No matching power limits found for this system\n");
- return;
+ return 0;
}
/* 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;
+ return 0;
}
asus_armoury.requires_fan_curve = power_data->requires_fan_curve;
@@ -1033,11 +1035,10 @@ static void init_rog_tunables(void)
/* Initialize AC power tunables */
ac_limits = power_data->ac_data;
if (ac_limits) {
- ac_rog_tunables = kzalloc_obj(*asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC]);
+ ac_rog_tunables = kzalloc_obj(*ac_rog_tunables);
if (!ac_rog_tunables)
- goto err_nomem;
+ return -ENOMEM;
- asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC] = ac_rog_tunables;
ac_rog_tunables->power_limits = ac_limits;
/* Set initial AC values */
@@ -1080,13 +1081,10 @@ static void init_rog_tunables(void)
/* Initialize DC power tunables */
dc_limits = power_data->dc_data;
if (dc_limits) {
- dc_rog_tunables = kzalloc_obj(*asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC]);
- if (!dc_rog_tunables) {
- kfree(ac_rog_tunables);
- goto err_nomem;
- }
+ dc_rog_tunables = kzalloc_obj(*dc_rog_tunables);
+ if (!dc_rog_tunables)
+ return -ENOMEM;
- asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC] = dc_rog_tunables;
dc_rog_tunables->power_limits = dc_limits;
/* Set initial DC values */
@@ -1126,15 +1124,16 @@ static void init_rog_tunables(void)
pr_debug("No DC PPT limits defined\n");
}
- return;
+ asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC] = no_free_ptr(ac_rog_tunables);
+ asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC] = no_free_ptr(dc_rog_tunables);
-err_nomem:
- pr_err("Failed to allocate memory for tunables\n");
+ return 0;
}
static int __init asus_fw_init(void)
{
char *wmi_uid;
+ int err;
wmi_uid = wmi_get_acpi_device_uid(ASUS_WMI_MGMT_GUID);
if (!wmi_uid)
@@ -1147,10 +1146,21 @@ static int __init asus_fw_init(void)
if (!strcmp(wmi_uid, ASUS_ACPI_UID_ASUSWMI))
return -ENODEV;
- init_rog_tunables();
+ err = init_rog_tunables();
+ if (err)
+ return err;
/* Must always be last step to ensure data is available */
- return asus_fw_attr_add();
+ err = asus_fw_attr_add();
+ if (err)
+ goto err_free_tunables;
+
+ return 0;
+
+err_free_tunables:
+ kfree(asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC]);
+ kfree(asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC]);
+ return err;
}
static void __exit asus_fw_exit(void)
diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h
index 65166b50a2c3..afcb517dc5bf 100644
--- a/drivers/platform/x86/asus-armoury.h
+++ b/drivers/platform/x86/asus-armoury.h
@@ -371,6 +371,38 @@ static const struct dmi_system_id power_limits[] = {
},
{
.matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "FA401KM"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .nv_dynamic_boost_max = 15,
+ .nv_dynamic_boost_min = 5,
+ .nv_temp_target_max = 87,
+ .nv_temp_target_min = 75,
+ .nv_tgp_max = 95,
+ .nv_tgp_min = 55,
+ .ppt_pl1_spl_max = 80,
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl2_sppt_max = 80,
+ .ppt_pl2_sppt_min = 35,
+ .ppt_pl3_fppt_max = 80,
+ .ppt_pl3_fppt_min = 35,
+ },
+ .dc_data = &(struct power_limits) {
+ .nv_temp_target_max = 87,
+ .nv_temp_target_min = 75,
+ .ppt_pl1_spl_max = 35,
+ .ppt_pl1_spl_min = 25,
+ .ppt_pl2_sppt_max = 44,
+ .ppt_pl2_sppt_min = 31,
+ .ppt_pl3_fppt_max = 65,
+ .ppt_pl3_fppt_min = 45,
+ },
+ .requires_fan_curve = true,
+ },
+ },
+ {
+ .matches = {
DMI_MATCH(DMI_BOARD_NAME, "FA401UM"),
},
.driver_data = &(struct power_data) {
@@ -756,6 +788,40 @@ static const struct dmi_system_id power_limits[] = {
},
{
.matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "FA608WV"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .nv_dynamic_boost_max = 25,
+ .nv_dynamic_boost_min = 5,
+ .nv_temp_target_max = 87,
+ .nv_temp_target_min = 75,
+ .nv_tgp_max = 115,
+ .nv_tgp_min = 55,
+ .ppt_pl1_spl_max = 90,
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl2_sppt_max = 90,
+ .ppt_pl2_sppt_min = 35,
+ .ppt_pl3_fppt_max = 90,
+ .ppt_pl3_fppt_min = 35,
+ },
+ .dc_data = &(struct power_limits) {
+ .nv_temp_target_max = 87,
+ .nv_temp_target_min = 75,
+ .ppt_pl1_spl_def = 45,
+ .ppt_pl1_spl_max = 65,
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl2_sppt_def = 54,
+ .ppt_pl2_sppt_max = 65,
+ .ppt_pl2_sppt_min = 35,
+ .ppt_pl3_fppt_max = 65,
+ .ppt_pl3_fppt_min = 35,
+ },
+ .requires_fan_curve = true,
+ },
+ },
+ {
+ .matches = {
DMI_MATCH(DMI_BOARD_NAME, "FA617NS"),
},
.driver_data = &(struct power_data) {
@@ -1997,13 +2063,13 @@ static const struct dmi_system_id power_limits[] = {
.driver_data = &(struct power_data) {
.ac_data = &(struct power_limits) {
.ppt_pl1_spl_min = 30,
- .ppt_pl1_spl_max = 90,
+ .ppt_pl1_spl_max = 120,
.ppt_pl2_sppt_min = 65,
- .ppt_pl2_sppt_def = 110,
- .ppt_pl2_sppt_max = 125,
+ .ppt_pl2_sppt_def = 140,
+ .ppt_pl2_sppt_max = 145,
.ppt_pl3_fppt_min = 65,
- .ppt_pl3_fppt_def = 110,
- .ppt_pl3_fppt_max = 125,
+ .ppt_pl3_fppt_def = 140,
+ .ppt_pl3_fppt_max = 145,
.nv_temp_target_min = 75,
.nv_temp_target_max = 87,
.nv_dynamic_boost_min = 5,
@@ -2081,6 +2147,35 @@ static const struct dmi_system_id power_limits[] = {
},
{
.matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "G635LX"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 28,
+ .ppt_pl1_spl_def = 140,
+ .ppt_pl1_spl_max = 175,
+ .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,
+ .nv_tgp_min = 80,
+ .nv_tgp_max = 150,
+ },
+ .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) {
@@ -2324,6 +2419,35 @@ static const struct dmi_system_id power_limits[] = {
},
{
.matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "HN7306EA"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 35,
+ .ppt_pl1_spl_def = 60,
+ .ppt_pl1_spl_max = 85,
+ .ppt_pl2_sppt_min = 40,
+ .ppt_pl2_sppt_def = 70,
+ .ppt_pl2_sppt_max = 95,
+ .ppt_pl3_fppt_min = 50,
+ .ppt_pl3_fppt_def = 85,
+ .ppt_pl3_fppt_max = 115,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 35,
+ .ppt_pl1_spl_def = 45,
+ .ppt_pl1_spl_max = 60,
+ .ppt_pl2_sppt_min = 40,
+ .ppt_pl2_sppt_def = 55,
+ .ppt_pl2_sppt_max = 70,
+ .ppt_pl3_fppt_min = 50,
+ .ppt_pl3_fppt_def = 65,
+ .ppt_pl3_fppt_max = 85,
+ },
+ },
+ },
+ {
+ .matches = {
DMI_MATCH(DMI_BOARD_NAME, "RC71"),
},
.driver_data = &(struct power_data) {
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index 140ac8a10537..449addd1ac7a 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -42,8 +42,6 @@
#define ASUS_LAPTOP_VERSION "0.42"
#define ASUS_LAPTOP_NAME "Asus Laptop Support"
-#define ASUS_LAPTOP_CLASS "hotkey"
-#define ASUS_LAPTOP_DEVICE_NAME "Hotkey"
#define ASUS_LAPTOP_FILE KBUILD_MODNAME
#define ASUS_LAPTOP_PREFIX "\\_SB.ATKD."
@@ -1524,9 +1522,8 @@ static void asus_acpi_notify(acpi_handle handle, u32 event, void *data)
/* TODO Find a better way to handle events count. */
count = asus->event_count[event % 128]++;
- acpi_bus_generate_netlink_event(asus->device->pnp.device_class,
- dev_name(&asus->device->dev), event,
- count);
+ acpi_bus_generate_netlink_event("hotkey", dev_name(&asus->device->dev),
+ event, count);
if (event >= ATKD_BRNUP_MIN && event <= ATKD_BRNUP_MAX)
event = ATKD_BRNUP;
@@ -1840,8 +1837,6 @@ static int asus_acpi_probe(struct platform_device *pdev)
if (!asus)
return -ENOMEM;
asus->handle = device->handle;
- strscpy(acpi_device_name(device), ASUS_LAPTOP_DEVICE_NAME);
- strscpy(acpi_device_class(device), ASUS_LAPTOP_CLASS);
asus->device = device;
asus_dmi_check();
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index d18a80907611..8a640c25830a 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -34,8 +34,6 @@
#define EEEPC_LAPTOP_NAME "Eee PC Hotkey Driver"
#define EEEPC_LAPTOP_FILE "eeepc"
-#define EEEPC_ACPI_CLASS "hotkey"
-#define EEEPC_ACPI_DEVICE_NAME "Hotkey"
#define EEEPC_ACPI_HID "ASUS010"
MODULE_AUTHOR("Corentin Chary, Eric Cooper");
@@ -1214,8 +1212,7 @@ static void eeepc_acpi_notify(acpi_handle handle, u32 event, void *data)
if (event > ACPI_MAX_SYS_NOTIFY)
return;
count = eeepc->event_count[event % 128]++;
- acpi_bus_generate_netlink_event(device->pnp.device_class,
- dev_name(&device->dev), event,
+ acpi_bus_generate_netlink_event("hotkey", dev_name(&device->dev), event,
count);
/* Brightness events are special */
@@ -1376,8 +1373,6 @@ static int eeepc_acpi_probe(struct platform_device *pdev)
if (!eeepc)
return -ENOMEM;
eeepc->handle = device->handle;
- strscpy(acpi_device_name(device), EEEPC_ACPI_DEVICE_NAME);
- strscpy(acpi_device_class(device), EEEPC_ACPI_CLASS);
eeepc->device = device;
platform_set_drvdata(pdev, eeepc);
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c
index 54d0b9cec4d3..ea543deef68f 100644
--- a/drivers/platform/x86/fujitsu-laptop.c
+++ b/drivers/platform/x86/fujitsu-laptop.c
@@ -56,7 +56,6 @@
#define FUJITSU_LCD_N_LEVELS 8
-#define ACPI_FUJITSU_CLASS "fujitsu"
#define ACPI_FUJITSU_BL_HID "FUJ02B1"
#define ACPI_FUJITSU_BL_DRIVER_NAME "Fujitsu laptop FUJ02B1 ACPI brightness driver"
#define ACPI_FUJITSU_BL_DEVICE_NAME "Fujitsu FUJ02B1"
@@ -466,7 +465,7 @@ static int acpi_fujitsu_bl_input_setup(struct device *dev)
snprintf(priv->phys, sizeof(priv->phys), "%s/video/input0",
acpi_device_hid(device));
- priv->input->name = acpi_device_name(device);
+ priv->input->name = ACPI_FUJITSU_BL_DEVICE_NAME;
priv->input->phys = priv->phys;
priv->input->id.bustype = BUS_HOST;
priv->input->id.product = 0x06;
@@ -546,13 +545,11 @@ static int acpi_fujitsu_bl_probe(struct platform_device *pdev)
return -ENOMEM;
fujitsu_bl = priv;
- strscpy(acpi_device_name(device), ACPI_FUJITSU_BL_DEVICE_NAME);
- strscpy(acpi_device_class(device), ACPI_FUJITSU_CLASS);
platform_set_drvdata(pdev, priv);
- pr_info("ACPI: %s [%s]\n",
- acpi_device_name(device), acpi_device_bid(device));
+ pr_info("ACPI: %s [%s]\n", ACPI_FUJITSU_BL_DEVICE_NAME,
+ acpi_device_bid(device));
if (get_max_brightness(&pdev->dev) <= 0)
priv->max_brightness = FUJITSU_LCD_N_LEVELS;
@@ -681,7 +678,7 @@ static int acpi_fujitsu_laptop_input_setup(struct device *dev)
snprintf(priv->phys, sizeof(priv->phys), "%s/input0",
acpi_device_hid(device));
- priv->input->name = acpi_device_name(device);
+ priv->input->name = ACPI_FUJITSU_LAPTOP_DEVICE_NAME;
priv->input->phys = priv->phys;
priv->input->id.bustype = BUS_HOST;
@@ -1012,9 +1009,6 @@ static int acpi_fujitsu_laptop_probe(struct platform_device *pdev)
WARN_ONCE(fext, "More than one FUJ02E3 ACPI device was found. Driver may not work as intended.");
fext = &pdev->dev;
- strscpy(acpi_device_name(device), ACPI_FUJITSU_LAPTOP_DEVICE_NAME);
- strscpy(acpi_device_class(device), ACPI_FUJITSU_CLASS);
-
platform_set_drvdata(pdev, priv);
/* kfifo */
@@ -1024,8 +1018,8 @@ static int acpi_fujitsu_laptop_probe(struct platform_device *pdev)
if (ret)
return ret;
- pr_info("ACPI: %s [%s]\n",
- acpi_device_name(device), acpi_device_bid(device));
+ pr_info("ACPI: %s [%s]\n", ACPI_FUJITSU_LAPTOP_DEVICE_NAME,
+ acpi_device_bid(device));
while (call_fext_func(fext, FUNC_BUTTONS, 0x1, 0x0, 0x0) != 0 &&
i++ < MAX_HOTKEY_RINGBUFFER_SIZE)
diff --git a/drivers/platform/x86/fujitsu-tablet.c b/drivers/platform/x86/fujitsu-tablet.c
index 2f8c1b89cbca..e1f5dc86dc4d 100644
--- a/drivers/platform/x86/fujitsu-tablet.c
+++ b/drivers/platform/x86/fujitsu-tablet.c
@@ -22,8 +22,6 @@
#define MODULENAME "fujitsu-tablet"
-#define ACPI_FUJITSU_CLASS "fujitsu"
-
#define INVERT_TABLET_MODE_BIT 0x01
#define INVERT_DOCK_STATE_BIT 0x02
#define FORCE_TABLET_MODE_IF_UNDOCK 0x04
@@ -160,6 +158,7 @@ static struct {
struct fujitsu_config config;
unsigned long prev_keymask;
+ char name[17];
char phys[21];
int irq;
@@ -458,14 +457,10 @@ static int acpi_fujitsu_probe(struct platform_device *pdev)
if (ACPI_FAILURE(status) || !fujitsu.irq || !fujitsu.io_base)
return -ENODEV;
- sprintf(acpi_device_name(adev), "Fujitsu %s", acpi_device_hid(adev));
- sprintf(acpi_device_class(adev), "%s", ACPI_FUJITSU_CLASS);
-
- snprintf(fujitsu.phys, sizeof(fujitsu.phys),
- "%s/input0", acpi_device_hid(adev));
+ scnprintf(fujitsu.name, sizeof(fujitsu.name), "Fujitsu %s", acpi_device_hid(adev));
+ scnprintf(fujitsu.phys, sizeof(fujitsu.phys), "%s/input0", acpi_device_hid(adev));
- error = input_fujitsu_setup(&pdev->dev,
- acpi_device_name(adev), fujitsu.phys);
+ error = input_fujitsu_setup(&pdev->dev, fujitsu.name, fujitsu.phys);
if (error)
return error;
diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c
index 0dcf2901259e..5353d997d272 100644
--- a/drivers/platform/x86/hp/hp-wmi.c
+++ b/drivers/platform/x86/hp/hp-wmi.c
@@ -311,6 +311,10 @@ static const struct dmi_system_id hp_wmi_feature_boards[] __initconst = {
.driver_data = (void *)&omen_v1_no_ec_board_params,
},
{
+ .matches = { DMI_MATCH(DMI_BOARD_NAME, "8DD6") },
+ .driver_data = (void *)&omen_v1_no_ec_thermal_params,
+ },
+ {
.matches = { DMI_MATCH(DMI_BOARD_NAME, "8E35") },
.driver_data = (void *)&omen_v1_legacy_board_params,
},
@@ -545,9 +549,9 @@ struct hp_wmi_hwmon_priv {
struct mutex lock; /* protects mode, pwm */
u8 min_rpm;
u8 max_rpm;
- int gpu_delta;
u8 mode;
- u8 pwm;
+ u8 cpu_pwm;
+ u8 gpu_pwm;
struct delayed_work keep_alive_dwork;
};
@@ -874,24 +878,20 @@ static int hp_wmi_fan_speed_max_set(int enabled)
return enabled;
}
-static int hp_wmi_fan_speed_set(struct hp_wmi_hwmon_priv *priv, u8 speed)
+static int hp_wmi_fan_speed_set(struct hp_wmi_hwmon_priv *priv)
{
u8 fan_speed[2];
- int gpu_speed, ret;
+ int ret;
- fan_speed[CPU_FAN] = speed;
- fan_speed[GPU_FAN] = speed;
+ if (priv->cpu_pwm == HP_FAN_SPEED_AUTOMATIC)
+ fan_speed[CPU_FAN] = HP_FAN_SPEED_AUTOMATIC;
+ else
+ fan_speed[CPU_FAN] = pwm_to_rpm(priv->cpu_pwm, priv);
- /*
- * GPU fan speed is always a little higher than CPU fan speed, we fetch
- * this delta value from the fan table during hwmon init.
- * Exception: Speed is set to HP_FAN_SPEED_AUTOMATIC, to revert to
- * automatic mode.
- */
- if (speed != HP_FAN_SPEED_AUTOMATIC) {
- gpu_speed = speed + priv->gpu_delta;
- fan_speed[GPU_FAN] = clamp_val(gpu_speed, 0, U8_MAX);
- }
+ if (priv->gpu_pwm == HP_FAN_SPEED_AUTOMATIC)
+ fan_speed[GPU_FAN] = HP_FAN_SPEED_AUTOMATIC;
+ else
+ fan_speed[GPU_FAN] = pwm_to_rpm(priv->gpu_pwm, priv);
ret = hp_wmi_get_fan_count_userdefine_trigger();
if (ret < 0)
@@ -908,7 +908,9 @@ static int hp_wmi_fan_speed_set(struct hp_wmi_hwmon_priv *priv, u8 speed)
static int hp_wmi_fan_speed_reset(struct hp_wmi_hwmon_priv *priv)
{
- return hp_wmi_fan_speed_set(priv, HP_FAN_SPEED_AUTOMATIC);
+ priv->cpu_pwm = HP_FAN_SPEED_AUTOMATIC;
+ priv->gpu_pwm = HP_FAN_SPEED_AUTOMATIC;
+ return hp_wmi_fan_speed_set(priv);
}
static int hp_wmi_fan_speed_max_reset(struct hp_wmi_hwmon_priv *priv)
@@ -2499,7 +2501,7 @@ static int hp_wmi_apply_fan_settings(struct hp_wmi_hwmon_priv *priv)
case PWM_MODE_MANUAL:
if (!hp_wmi_fan_control_supported())
return -EOPNOTSUPP;
- ret = hp_wmi_fan_speed_set(priv, pwm_to_rpm(priv->pwm, priv));
+ ret = hp_wmi_fan_speed_set(priv);
if (ret < 0)
return ret;
mod_delayed_work(system_dfl_wq, &priv->keep_alive_dwork,
@@ -2599,13 +2601,14 @@ static int hp_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long val)
{
struct hp_wmi_hwmon_priv *priv;
- int rpm;
+ int cpu_rpm, gpu_rpm;
priv = dev_get_drvdata(dev);
guard(mutex)(&priv->lock);
switch (type) {
case hwmon_pwm:
if (attr == hwmon_pwm_input) {
+ int rpm;
if (!hp_wmi_fan_control_supported())
return -EOPNOTSUPP;
/* PWM input is invalid when not in manual mode */
@@ -2615,7 +2618,10 @@ static int hp_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
/* ensure PWM input is within valid fan speeds */
rpm = pwm_to_rpm(val, priv);
rpm = clamp_val(rpm, priv->min_rpm, priv->max_rpm);
- priv->pwm = rpm_to_pwm(rpm, priv);
+ if (channel == CPU_FAN)
+ priv->cpu_pwm = rpm_to_pwm(rpm, priv);
+ else if (channel == GPU_FAN)
+ priv->gpu_pwm = rpm_to_pwm(rpm, priv);
return hp_wmi_apply_fan_settings(priv);
}
switch (val) {
@@ -2629,10 +2635,14 @@ static int hp_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
* When switching to manual mode, set fan speed to
* current RPM values to ensure a smooth transition.
*/
- rpm = hp_wmi_get_active_fan_speed(channel);
- if (rpm < 0)
- return rpm;
- priv->pwm = rpm_to_pwm(rpm / 100, priv);
+ cpu_rpm = hp_wmi_get_active_fan_speed(CPU_FAN);
+ if (cpu_rpm < 0)
+ return cpu_rpm;
+ gpu_rpm = hp_wmi_get_active_fan_speed(GPU_FAN);
+ if (gpu_rpm < 0)
+ return gpu_rpm;
+ priv->cpu_pwm = rpm_to_pwm(cpu_rpm / 100, priv);
+ priv->gpu_pwm = rpm_to_pwm(gpu_rpm / 100, priv);
priv->mode = PWM_MODE_MANUAL;
return hp_wmi_apply_fan_settings(priv);
case PWM_MODE_AUTO:
@@ -2648,7 +2658,7 @@ static int hp_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
static const struct hwmon_channel_info * const info[] = {
HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT, HWMON_F_INPUT),
- HWMON_CHANNEL_INFO(pwm, HWMON_PWM_ENABLE | HWMON_PWM_INPUT),
+ HWMON_CHANNEL_INFO(pwm, HWMON_PWM_ENABLE | HWMON_PWM_INPUT, HWMON_PWM_INPUT),
NULL
};
@@ -2689,7 +2699,7 @@ static int hp_wmi_setup_fan_settings(struct hp_wmi_hwmon_priv *priv)
struct victus_s_fan_table *fan_table;
u8 min_rpm, max_rpm;
u8 cpu_rpm, gpu_rpm, noise_db;
- int gpu_delta, i, num_entries, ret;
+ int i, num_entries, ret;
size_t header_size, entry_size;
/* Default behaviour on hwmon init is automatic mode */
@@ -2735,10 +2745,8 @@ static int hp_wmi_setup_fan_settings(struct hp_wmi_hwmon_priv *priv)
if (min_rpm == U8_MAX || max_rpm == 0)
return -EINVAL;
- gpu_delta = fan_table->entries[0].gpu_rpm - fan_table->entries[0].cpu_rpm;
priv->min_rpm = min_rpm;
priv->max_rpm = max_rpm;
- priv->gpu_delta = gpu_delta;
return 0;
}
diff --git a/drivers/platform/x86/huawei-wmi.c b/drivers/platform/x86/huawei-wmi.c
index 93cca17fdf58..d6aaf14d66a5 100644
--- a/drivers/platform/x86/huawei-wmi.c
+++ b/drivers/platform/x86/huawei-wmi.c
@@ -6,6 +6,7 @@
*/
#include <linux/acpi.h>
+#include <linux/cleanup.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/dmi.h>
@@ -527,11 +528,104 @@ static void huawei_wmi_battery_exit(struct device *dev)
/* Fn lock */
+/* GFRS byte[1] / SFRS byte[2] (FRSR) fn-lock state values */
+#define FN_LOCK_ACPI_OFF 1
+#define FN_LOCK_ACPI_ON 2
+#define FN_LOCK_ACPI_STAT_OK 0
+
+/*
+ * Newer Huawei models (e.g. HUAWEI FLMH-XX / MateBook 14 2024) use direct
+ * ACPI methods \GFRS / \SFRS (Get/Set Fn key Reversal Status) to control
+ * Fn-lock via EC registers 0x6B (read) and 0x6C (write).
+ *
+ * GFRS response buffer layout:
+ * byte[0] = STAT (FN_LOCK_ACPI_STAT_OK = success)
+ * byte[1] = FN_LOCK_ACPI_OFF (fn-lock off) or FN_LOCK_ACPI_ON (fn-lock on)
+ *
+ * SFRS argument layout (CreateByteField(Arg0, 0x02, FRSR)):
+ * Value is read from byte[2] of the integer argument, so it must be
+ * passed as (value << 16):
+ * (FN_LOCK_ACPI_OFF << 16) = fn-lock off (writes 0x55 to EC 0x6C)
+ * (FN_LOCK_ACPI_ON << 16) = fn-lock on (writes 0x5A to EC 0x6C)
+ */
+
+static int huawei_acpi_fn_lock_get(int *on)
+{
+ union acpi_object acpi_arg;
+ struct acpi_object_list arg_list = { .count = 1, .pointer = &acpi_arg };
+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+ acpi_status status;
+
+ acpi_arg.type = ACPI_TYPE_INTEGER;
+ acpi_arg.integer.value = 0;
+
+ status = acpi_evaluate_object(NULL, "\\GFRS", &arg_list, &output);
+ if (ACPI_FAILURE(status))
+ return -EIO;
+
+ union acpi_object *obj __free(kfree) = output.pointer;
+ if (!obj || obj->type != ACPI_TYPE_BUFFER || obj->buffer.length < 2)
+ return -ENODATA;
+
+ /* byte[0] = STAT, byte[1] = fn-lock state */
+ if (obj->buffer.pointer[0] != FN_LOCK_ACPI_STAT_OK)
+ return -EIO;
+
+ switch (obj->buffer.pointer[1]) {
+ case FN_LOCK_ACPI_OFF:
+ if (on)
+ *on = 0;
+ break;
+ case FN_LOCK_ACPI_ON:
+ if (on)
+ *on = 1;
+ break;
+ default:
+ return -ENODATA;
+ }
+
+ return 0;
+}
+
+static int huawei_acpi_fn_lock_set(int on)
+{
+ union acpi_object acpi_arg;
+ struct acpi_object_list arg_list = { .count = 1, .pointer = &acpi_arg };
+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+ acpi_status status;
+
+ /*
+ * SFRS reads byte[2] of its argument via CreateByteField(Arg0, 0x02).
+ * on=0 → FRSR=FN_LOCK_ACPI_OFF → EC gets 0x55 (fn-lock off)
+ * on=1 → FRSR=FN_LOCK_ACPI_ON → EC gets 0x5A (fn-lock on)
+ */
+ acpi_arg.type = ACPI_TYPE_INTEGER;
+ acpi_arg.integer.value = (on ? FN_LOCK_ACPI_ON : FN_LOCK_ACPI_OFF) << 16;
+
+ status = acpi_evaluate_object(NULL, "\\SFRS", &arg_list, &output);
+ if (ACPI_FAILURE(status))
+ return -EIO;
+
+ union acpi_object *obj __free(kfree) = output.pointer;
+ if (!obj || obj->type != ACPI_TYPE_BUFFER || obj->buffer.length < 1)
+ return -ENODATA;
+
+ if (obj->buffer.pointer[0] != FN_LOCK_ACPI_STAT_OK)
+ return -EIO;
+
+ return 0;
+}
+
static int huawei_wmi_fn_lock_get(int *on)
{
u8 ret[0x100] = { 0 };
int err, i;
+ /* Newer models: use direct ACPI \GFRS method */
+ if (acpi_has_method(NULL, "\\GFRS"))
+ return huawei_acpi_fn_lock_get(on);
+
+ /* WMI fallback */
err = huawei_wmi_cmd(FN_LOCK_GET, ret, 0x100);
if (err)
return err;
@@ -550,6 +644,11 @@ static int huawei_wmi_fn_lock_set(int on)
{
union hwmi_arg arg;
+ /* Newer models: use direct ACPI \SFRS method */
+ if (acpi_has_method(NULL, "\\SFRS"))
+ return huawei_acpi_fn_lock_set(on);
+
+ /* WMI fallback */
arg.cmd = FN_LOCK_SET;
arg.args[2] = on + 1; // 0 undefined, 1 off, 2 on.
diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c
index 115bb37577a1..adff564bf3fd 100644
--- a/drivers/platform/x86/intel/int3472/discrete.c
+++ b/drivers/platform/x86/intel/int3472/discrete.c
@@ -164,6 +164,24 @@ static const struct int3472_gpio_map int3472_gpio_map[] = {
.con_id = "dvdd",
.enable_time_us = 45 * USEC_PER_MSEC,
},
+ { /* imx471 expects "vana" as con_id for power enable */
+ .hid = "SONY471A",
+ .type_from = INT3472_GPIO_TYPE_POWER_ENABLE,
+ .type_to = INT3472_GPIO_TYPE_POWER_ENABLE,
+ .con_id = "vana",
+ .enable_time_us = GPIO_REGULATOR_ENABLE_TIME,
+ },
+ {
+ /*
+ * imx471 (on Lenovo ThinkPads X1 G14) expects "vana" as con_id
+ * for power enable
+ */
+ .hid = "TBE20A0",
+ .type_from = INT3472_GPIO_TYPE_POWER_ENABLE,
+ .type_to = INT3472_GPIO_TYPE_POWER_ENABLE,
+ .con_id = "vana",
+ .enable_time_us = GPIO_REGULATOR_ENABLE_TIME,
+ },
};
static void int3472_get_con_id_and_polarity(struct int3472_discrete_device *int3472, u8 *type,
diff --git a/drivers/platform/x86/intel/ishtp_eclite.c b/drivers/platform/x86/intel/ishtp_eclite.c
index 93ac8b2dbf38..bca7e217878b 100644
--- a/drivers/platform/x86/intel/ishtp_eclite.c
+++ b/drivers/platform/x86/intel/ishtp_eclite.c
@@ -600,13 +600,16 @@ static int ecl_ishtp_cl_probe(struct ishtp_cl_device *cl_device)
rv = acpi_opregion_init(opr_dev);
if (rv) {
dev_err(cl_data_to_dev(opr_dev), "ACPI opregion init failed\n");
- goto err_exit;
+ goto err_put;
}
/* Reprobe devices depending on ECLite - battery, fan, etc. */
acpi_dev_clear_dependencies(opr_dev->adev);
return 0;
+
+err_put:
+ acpi_dev_put(opr_dev->adev);
err_exit:
ishtp_set_connection_state(ecl_ishtp_cl, ISHTP_CL_DISCONNECTING);
ishtp_cl_disconnect(ecl_ishtp_cl);
diff --git a/drivers/platform/x86/lenovo/thinkpad_acpi.c b/drivers/platform/x86/lenovo/thinkpad_acpi.c
index 445e1403308e..6dd7c28fc0db 100644
--- a/drivers/platform/x86/lenovo/thinkpad_acpi.c
+++ b/drivers/platform/x86/lenovo/thinkpad_acpi.c
@@ -38,6 +38,7 @@
#include <linux/backlight.h>
#include <linux/bitfield.h>
#include <linux/bitops.h>
+#include <linux/cleanup.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/dmi.h>
@@ -67,6 +68,7 @@
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/string.h>
+#include <linux/string_choices.h>
#include <linux/string_helpers.h>
#include <linux/sysfs.h>
#include <linux/types.h>
@@ -186,6 +188,7 @@ enum tpacpi_hkey_event_t {
TP_HKEY_EV_AMT_TOGGLE = 0x131a, /* Toggle AMT on/off */
TP_HKEY_EV_CAMERASHUTTER_TOGGLE = 0x131b, /* Toggle Camera Shutter */
TP_HKEY_EV_DOUBLETAP_TOGGLE = 0x131c, /* Toggle trackpoint doubletap on/off */
+ TP_HKEY_EV_USB_C_SECURITY = 0x131e, /* USB C Security (Fn+U, Fn+S) */
TP_HKEY_EV_PROFILE_TOGGLE = 0x131f, /* Toggle platform profile in 2024 systems */
TP_HKEY_EV_PROFILE_TOGGLE2 = 0x1401, /* Toggle platform profile in 2025 + systems */
@@ -309,6 +312,7 @@ struct tp_acpi_drv_struct {
struct ibm_struct {
char *name;
+ acpi_device_class device_class;
int (*read) (struct seq_file *);
int (*write) (char *);
@@ -374,6 +378,8 @@ static struct {
u32 has_adaptive_kbd:1;
u32 kbd_lang:1;
u32 trackpoint_doubletap_enable:1;
+ u32 usbc_security_supported:1;
+ bool usbc_security_enabled;
struct quirk_entry *quirks;
} tp_features;
@@ -838,9 +844,8 @@ static int __init setup_acpi_notify(struct ibm_struct *ibm)
}
ibm->acpi->device->driver_data = ibm;
- scnprintf(acpi_device_class(ibm->acpi->device),
- sizeof(acpi_device_class(ibm->acpi->device)),
- "%s/%s", TPACPI_ACPI_EVENT_PREFIX, ibm->name);
+ scnprintf(ibm->device_class, sizeof(ibm->device_class), "%s/%s",
+ TPACPI_ACPI_EVENT_PREFIX, ibm->name);
status = acpi_install_notify_handler(*ibm->acpi->handle,
ibm->acpi->type, dispatch_acpi_notify, ibm);
@@ -3869,7 +3874,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
pr_err("unknown HKEY notification event %d\n", event);
/* forward it to userspace, maybe it knows how to handle it */
acpi_bus_generate_netlink_event(
- ibm->acpi->device->pnp.device_class,
+ ibm->device_class,
dev_name(&ibm->acpi->device->dev),
event, 0);
return;
@@ -3949,7 +3954,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
/* netlink events */
if (send_acpi_ev) {
acpi_bus_generate_netlink_event(
- ibm->acpi->device->pnp.device_class,
+ ibm->device_class,
dev_name(&ibm->acpi->device->dev),
event, hkey);
}
@@ -11285,6 +11290,111 @@ static struct ibm_struct hwdd_driver_data = {
.name = "hwdd",
};
+/*************************************************************************
+ * USB-C Security subdriver
+ *
+ * HKEY.USCS(0) is a read-only ACPI method; its argument is ignored.
+ * It always returns:
+ * bit 16 - USB-C security capability present on this SKU or not
+ * bit 0 - USB-C Security state (enable or disable)
+ *
+ * Hotkey
+ * ------
+ * 0x131e (Fn+U, Fn+S): firmware toggles USBS before firing the event.
+ * The driver reads back the new state and notifies the sysfs attribute.
+ */
+
+/* USCS() return word bit layout */
+#define USCS_CAP_BIT BIT(16) /* capability: feature present on SKU */
+#define USCS_STATUS_BIT BIT(0) /* current security state */
+
+/* Protects USCS() ACPI method calls in usbc_security_query() */
+static DEFINE_MUTEX(usbc_security_mutex);
+
+/**
+ * usbc_security_query - read current USB-C security state via USCS()
+ * @enabled: out - true when security is ON (data connections blocked)
+ *
+ * Returns:
+ * 0 success, @enabled contains the current state
+ * -EIO ACPI evaluation failed
+ * -ENODEV capability bit absent; feature not present on this SKU*
+ */
+static int usbc_security_query(bool *enabled)
+{
+ int status;
+
+ guard(mutex)(&usbc_security_mutex);
+ if (!acpi_evalf(hkey_handle, &status, "USCS", "dd", 0))
+ return -EIO;
+
+ if (!(status & USCS_CAP_BIT)) {
+ pr_debug("USCS cap bit absent (raw=0x%x)\n", status);
+ return -ENODEV;
+ }
+
+ *enabled = status & USCS_STATUS_BIT;
+ return 0;
+}
+
+/* sysfs: /sys/devices/platform/thinkpad_acpi/usb_c_security ---------- */
+static ssize_t usb_c_security_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sysfs_emit(buf, "%s\n",
+ str_enabled_disabled(tp_features.usbc_security_enabled));
+}
+
+static DEVICE_ATTR_RO(usb_c_security);
+
+static struct attribute *usbc_security_attributes[] = {
+ &dev_attr_usb_c_security.attr,
+ NULL,
+};
+
+static umode_t usbc_security_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ return tp_features.usbc_security_supported ? attr->mode : 0;
+}
+
+static const struct attribute_group usbc_security_attr_group = {
+ .is_visible = usbc_security_attr_is_visible,
+ .attrs = usbc_security_attributes,
+};
+
+static int tpacpi_usbc_security_init(struct ibm_init_struct *iibm)
+{
+ int err;
+
+ err = usbc_security_query(&tp_features.usbc_security_enabled);
+ if (err == -ENODEV)
+ return 0;
+ if (err)
+ return err;
+
+ tp_features.usbc_security_supported = true;
+ return 0;
+}
+
+/* tpacpi_usbc_security_hotkey - handle Fn+U Fn+S hotkey (0x131e) */
+static bool tpacpi_usbc_security_hotkey(void)
+{
+ if (!tp_features.usbc_security_supported)
+ return false;
+
+ if (usbc_security_query(&tp_features.usbc_security_enabled))
+ return false;
+
+ sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, "usb_c_security");
+ return true;
+}
+
+static struct ibm_struct usbc_security_driver_data = {
+ .name = "usbc_security",
+};
+
/* --------------------------------------------------------------------- */
static struct attribute *tpacpi_driver_attributes[] = {
@@ -11345,6 +11455,7 @@ static const struct attribute_group *tpacpi_groups[] = {
&dprc_attr_group,
&auxmac_attr_group,
&hwdd_attr_group,
+ &usbc_security_attr_group,
NULL,
};
@@ -11499,6 +11610,8 @@ static bool tpacpi_driver_event(const unsigned int hkey_event)
case TP_HKEY_EV_PROFILE_TOGGLE2:
platform_profile_cycle();
return true;
+ case TP_HKEY_EV_USB_C_SECURITY:
+ return tpacpi_usbc_security_hotkey();
}
return false;
@@ -11964,6 +12077,10 @@ static struct ibm_init_struct ibms_init[] __initdata = {
.init = tpacpi_hwdd_init,
.data = &hwdd_driver_data,
},
+ {
+ .init = tpacpi_usbc_security_init,
+ .data = &usbc_security_driver_data,
+ },
};
static int __init set_ibm_param(const char *val, const struct kernel_param *kp)
diff --git a/drivers/platform/x86/lg-laptop.c b/drivers/platform/x86/lg-laptop.c
index a8f2f465ef3f..36ad1e269443 100644
--- a/drivers/platform/x86/lg-laptop.c
+++ b/drivers/platform/x86/lg-laptop.c
@@ -8,8 +8,11 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/acpi.h>
+#include <linux/array_size.h>
#include <linux/bitfield.h>
#include <linux/bits.h>
+#include <linux/compiler_attributes.h>
+#include <linux/cleanup.h>
#include <linux/device.h>
#include <linux/dev_printk.h>
#include <linux/dmi.h>
@@ -17,10 +20,12 @@
#include <linux/input/sparse-keymap.h>
#include <linux/kernel.h>
#include <linux/leds.h>
+#include <linux/limits.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/string_choices.h>
#include <linux/types.h>
+#include <linux/unaligned.h>
#include <acpi/battery.h>
@@ -57,13 +62,18 @@ MODULE_PARM_DESC(fw_debug, "Enable printing of firmware debug messages");
#define LG_ADDRESS_SPACE_DEBUG_MSG_START_ADR 0x3E8
#define LG_ADDRESS_SPACE_DEBUG_MSG_END_ADR 0x5E8
-#define WMI_EVENT_GUID0 "E4FB94F9-7F2B-4173-AD1A-CD1D95086248"
-#define WMI_EVENT_GUID1 "023B133E-49D1-4E10-B313-698220140DC2"
-#define WMI_EVENT_GUID2 "37BE1AC0-C3F2-4B1F-BFBE-8FDEAF2814D6"
-#define WMI_EVENT_GUID3 "911BAD44-7DF8-4FBB-9319-BABA1C4B293B"
-#define WMI_METHOD_WMAB "C3A72B38-D3EF-42D3-8CBB-D5A57049F66D"
-#define WMI_METHOD_WMBB "2B4F501A-BD3C-4394-8DCF-00A7D2BC8210"
-#define WMI_EVENT_GUID WMI_EVENT_GUID0
+#define LG_NOTIFY_TABLET_MODE_OFF 0x50
+#define LG_NOTIFY_TABLET_MODE_ON 0x51
+#define LG_NOTIFY_HOTKEY 0x80
+#define LG_NOTIFY_THERMAL 0x81
+#define LG_NOTIFY_MISC 0x82
+
+#define LG_OREP_READ_EC 0
+#define LG_OREP_WRITE_EC 1
+#define LG_OREP_DEBUG 2
+#define LG_OREP_UPDATE_SYSTEM_STATE 3
+#define LG_OREP_INTERCEPT_WMI_EVENTS 4
+#define LG_OREP_WAKE_ON_LAN 6
#define SB_GGOV_METHOD "\\_SB.GGOV"
#define GOV_TLED 0x2020008
@@ -78,42 +88,95 @@ MODULE_PARM_DESC(fw_debug, "Enable printing of firmware debug messages");
#define WMBB_USB_CHARGE 0x10B
#define WMBB_BATT_LIMIT 0x10C
+#define KBD_LED_BRIGHTNESS_MASK GENMASK(4, 0)
+#define KBD_LED_BRIGHTNESS_OFF 0x0
+#define KBD_LED_BRIGHTNESS_HALF 0x2
+#define KBD_LED_BRIGHTNESS_FULL 0x4
+#define KBD_LED_MODE_MASK GENMASK(6, 5)
+#define KBD_LED_MODE_OFF 0x0
+#define KBD_LED_MODE_ON 0x1
+#define KBD_LED_STATUS BIT(7)
+#define KBD_LED_MAGIC_MASK GENMASK(15, 8)
+/* Exact purpose is unknown, maybe some sort of brightness limit? */
+#define KBD_LED_MAGIC 0x05
+
#define FAN_MODE_LOWER GENMASK(1, 0)
#define FAN_MODE_UPPER GENMASK(5, 4)
#define PLATFORM_NAME "lg-laptop"
-MODULE_ALIAS("wmi:" WMI_EVENT_GUID0);
-MODULE_ALIAS("wmi:" WMI_EVENT_GUID1);
-MODULE_ALIAS("wmi:" WMI_EVENT_GUID2);
-MODULE_ALIAS("wmi:" WMI_EVENT_GUID3);
-MODULE_ALIAS("wmi:" WMI_METHOD_WMAB);
-MODULE_ALIAS("wmi:" WMI_METHOD_WMBB);
+struct lg_wmab_buffer_result {
+ __le32 value;
+ __le32 status;
+} __packed;
static struct platform_device *pf_device;
-static struct input_dev *wmi_input_dev;
-
-static u32 inited;
-#define INIT_INPUT_WMI_0 0x01
-#define INIT_INPUT_WMI_2 0x02
-#define INIT_INPUT_ACPI 0x04
-#define INIT_SPARSE_KEYMAP 0x80
static int battery_limit_use_wmbb;
+static bool kbd_backlight_available;
static struct led_classdev kbd_backlight;
static enum led_brightness get_kbd_backlight_level(struct device *dev);
static const struct key_entry wmi_keymap[] = {
- {KE_KEY, 0x70, {KEY_F15} }, /* LG control panel (F1) */
- {KE_KEY, 0x74, {KEY_F21} }, /* Touchpad toggle (F5) */
- {KE_KEY, 0xf020000, {KEY_F14} }, /* Read mode (F9) */
- {KE_KEY, 0x10000000, {KEY_F16} },/* Keyboard backlight (F8) - pressing
- * this key both sends an event and
- * changes backlight level.
- */
+ /* Placeholder value send by multiple hotkeys handled by ACPI */
+ { KE_IGNORE, 0x0, { KEY_UNKNOWN }},
+ /* LG control panel */
+ { KE_KEY, 0x70, { KEY_F15 }},
+ /* Touchpad toggle */
+ { KE_KEY, 0x74, { KEY_F21 }},
+ /* Mute Audio, already handled by ACPI */
+ { KE_IGNORE, 0x78, { KEY_MUTE }},
+ /* Read mode */
+ { KE_KEY, 0xf020000, { KEY_F14 }},
+ /* Open settings */
+ { KE_KEY, 0xf070002, { KEY_CONFIG }},
+ /* Keyboard backlight - pressing this key both sends an event and changes backlight level */
+ { KE_KEY, 0x10000000, { KEY_F16 }},
+ /* Hotkey combination pressed */
+ { KE_IGNORE, 0x30010000, { KEY_UNKNOWN }},
+ /* Hotkey combination released */
+ { KE_IGNORE, 0x30010001, { KEY_UNKNOWN }},
+ /* Change fan mode */
+ { KE_KEY, 0x30010051, { KEY_PERFORMANCE }},
+ /* Disable camera */
+ { KE_KEY, 0x40020000, { KEY_CAMERA_ACCESS_TOGGLE }},
+ /* Mute microphone */
+ { KE_KEY, 0x40020001, { KEY_MICMUTE }},
+ /* Fn-Lock */
+ { KE_KEY, 0x40030001, { KEY_FN_ESC }},
{KE_END, 0}
};
+static int lg_laptop_execute_orep(acpi_handle handle, u64 command, u64 value,
+ unsigned long long *result)
+{
+ union acpi_object objs[] = {
+ {
+ .integer = {
+ .type = ACPI_TYPE_INTEGER,
+ .value = command,
+ },
+ },
+ {
+ .integer = {
+ .type = ACPI_TYPE_INTEGER,
+ .value = value,
+ },
+ }
+ };
+ struct acpi_object_list args = {
+ .count = ARRAY_SIZE(objs),
+ .pointer = objs,
+ };
+ acpi_status status;
+
+ status = acpi_evaluate_integer(handle, "OREP", &args, result);
+ if (ACPI_FAILURE(status))
+ return -EIO;
+
+ return 0;
+}
+
static int ggov(u32 arg0)
{
union acpi_object args[1];
@@ -154,30 +217,97 @@ static int ggov(u32 arg0)
return res;
}
-static union acpi_object *lg_wmab(struct device *dev, u32 method, u32 arg1, u32 arg2)
+static int lg_wmab_get(struct device *dev, u32 method, u32 *result)
{
- union acpi_object args[3];
- acpi_status status;
- struct acpi_object_list arg;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object in[] = {
+ {
+ .integer = {
+ .type = ACPI_TYPE_INTEGER,
+ .value = method,
+ },
+ },
+ {
+ .integer = {
+ .type = ACPI_TYPE_INTEGER,
+ .value = WM_GET,
+ },
+ },
+ {
+ .integer = {
+ .type = ACPI_TYPE_INTEGER,
+ .value = 0,
+ },
+ },
+ };
+ struct lg_wmab_buffer_result *buffer_result;
+ struct acpi_object_list input = {
+ .count = ARRAY_SIZE(in),
+ .pointer = in,
+ };
+ acpi_status status;
- args[0].type = ACPI_TYPE_INTEGER;
- args[0].integer.value = method;
- args[1].type = ACPI_TYPE_INTEGER;
- args[1].integer.value = arg1;
- args[2].type = ACPI_TYPE_INTEGER;
- args[2].integer.value = arg2;
+ status = acpi_evaluate_object(ACPI_HANDLE(dev), "WMAB", &input, &buffer);
+ if (ACPI_FAILURE(status))
+ return -EIO;
- arg.count = 3;
- arg.pointer = args;
+ union acpi_object *obj __free(kfree) = buffer.pointer;
- status = acpi_evaluate_object(ACPI_HANDLE(dev), "WMAB", &arg, &buffer);
- if (ACPI_FAILURE(status)) {
- dev_err(dev, "WMAB: call failed.\n");
- return NULL;
+ if (!obj)
+ return -ENODATA;
+
+ switch (obj->type) {
+ case ACPI_TYPE_INTEGER:
+ *result = obj->integer.value;
+ return 0;
+ case ACPI_TYPE_BUFFER:
+ if (obj->buffer.length != sizeof(*buffer_result))
+ return -EPROTO;
+
+ buffer_result = (struct lg_wmab_buffer_result *)obj->buffer.pointer;
+ if (get_unaligned_le32(&buffer_result->status))
+ return -EIO;
+
+ *result = get_unaligned_le32(&buffer_result->value);
+ return 0;
+ default:
+ return -EPROTO;
}
+}
+
+static int lg_wmab_set(struct device *dev, u32 method, u32 arg)
+{
+ union acpi_object in[] = {
+ {
+ .integer = {
+ .type = ACPI_TYPE_INTEGER,
+ .value = method,
+ },
+ },
+ {
+ .integer = {
+ .type = ACPI_TYPE_INTEGER,
+ .value = WM_SET,
+ },
+ },
+ {
+ .integer = {
+ .type = ACPI_TYPE_INTEGER,
+ .value = arg,
+ },
+ },
+ };
+ struct acpi_object_list input = {
+ .count = ARRAY_SIZE(in),
+ .pointer = in,
+ };
+ acpi_status status;
+
+ status = acpi_evaluate_object(ACPI_HANDLE(dev), "WMAB", &input, NULL);
+ if (ACPI_FAILURE(status))
+ return -EIO;
- return buffer.pointer;
+ return 0;
}
static union acpi_object *lg_wmbb(struct device *dev, u32 method_id, u32 arg1, u32 arg2)
@@ -211,72 +341,11 @@ static union acpi_object *lg_wmbb(struct device *dev, u32 method_id, u32 arg1, u
return (union acpi_object *)buffer.pointer;
}
-static void wmi_notify(union acpi_object *obj, void *context)
-{
- long data = (long)context;
-
- pr_debug("event guid %li\n", data);
- if (!obj)
- return;
-
- if (obj->type == ACPI_TYPE_INTEGER) {
- int eventcode = obj->integer.value;
- struct key_entry *key;
-
- if (eventcode == 0x10000000) {
- led_classdev_notify_brightness_hw_changed(
- &kbd_backlight, get_kbd_backlight_level(kbd_backlight.dev->parent));
- } else {
- key = sparse_keymap_entry_from_scancode(
- wmi_input_dev, eventcode);
- if (key && key->type == KE_KEY)
- sparse_keymap_report_entry(wmi_input_dev,
- key, 1, true);
- }
- }
-
- pr_debug("Type: %i Eventcode: 0x%llx\n", obj->type,
- obj->integer.value);
-}
-
-static void wmi_input_setup(void)
-{
- acpi_status status;
-
- wmi_input_dev = input_allocate_device();
- if (wmi_input_dev) {
- wmi_input_dev->name = "LG WMI hotkeys";
- wmi_input_dev->phys = "wmi/input0";
- wmi_input_dev->id.bustype = BUS_HOST;
-
- if (sparse_keymap_setup(wmi_input_dev, wmi_keymap, NULL) ||
- input_register_device(wmi_input_dev)) {
- pr_info("Cannot initialize input device");
- input_free_device(wmi_input_dev);
- return;
- }
-
- inited |= INIT_SPARSE_KEYMAP;
- status = wmi_install_notify_handler(WMI_EVENT_GUID0, wmi_notify,
- (void *)0);
- if (ACPI_SUCCESS(status))
- inited |= INIT_INPUT_WMI_0;
-
- status = wmi_install_notify_handler(WMI_EVENT_GUID2, wmi_notify,
- (void *)2);
- if (ACPI_SUCCESS(status))
- inited |= INIT_INPUT_WMI_2;
- } else {
- pr_info("Cannot allocate input device");
- }
-}
-
static ssize_t fan_mode_store(struct device *dev,
struct device_attribute *attr,
const char *buffer, size_t count)
{
unsigned long value;
- union acpi_object *r;
int ret;
ret = kstrtoul(buffer, 10, &value);
@@ -285,10 +354,10 @@ static ssize_t fan_mode_store(struct device *dev,
if (value >= 3)
return -EINVAL;
- r = lg_wmab(dev, WM_FAN_MODE, WM_SET,
- FIELD_PREP(FAN_MODE_LOWER, value) |
- FIELD_PREP(FAN_MODE_UPPER, value));
- kfree(r);
+ ret = lg_wmab_set(dev, WM_FAN_MODE, FIELD_PREP(FAN_MODE_LOWER, value) |
+ FIELD_PREP(FAN_MODE_UPPER, value));
+ if (ret < 0)
+ return ret;
return count;
}
@@ -296,22 +365,14 @@ static ssize_t fan_mode_store(struct device *dev,
static ssize_t fan_mode_show(struct device *dev,
struct device_attribute *attr, char *buffer)
{
- unsigned int mode;
- union acpi_object *r;
-
- r = lg_wmab(dev, WM_FAN_MODE, WM_GET, 0);
- if (!r)
- return -EIO;
-
- if (r->type != ACPI_TYPE_INTEGER) {
- kfree(r);
- return -EIO;
- }
+ u32 mode;
+ int ret;
- mode = FIELD_GET(FAN_MODE_LOWER, r->integer.value);
- kfree(r);
+ ret = lg_wmab_get(dev, WM_FAN_MODE, &mode);
+ if (ret < 0)
+ return ret;
- return sysfs_emit(buffer, "%d\n", mode);
+ return sysfs_emit(buffer, "%lu\n", FIELD_GET(FAN_MODE_LOWER, mode));
}
static ssize_t usb_charge_store(struct device *dev,
@@ -361,41 +422,30 @@ static ssize_t reader_mode_store(struct device *dev,
const char *buffer, size_t count)
{
bool value;
- union acpi_object *r;
int ret;
ret = kstrtobool(buffer, &value);
if (ret)
return ret;
- r = lg_wmab(dev, WM_READER_MODE, WM_SET, value);
- if (!r)
- return -EIO;
+ ret = lg_wmab_set(dev, WM_READER_MODE, value);
+ if (ret < 0)
+ return ret;
- kfree(r);
return count;
}
static ssize_t reader_mode_show(struct device *dev,
struct device_attribute *attr, char *buffer)
{
- unsigned int status;
- union acpi_object *r;
-
- r = lg_wmab(dev, WM_READER_MODE, WM_GET, 0);
- if (!r)
- return -EIO;
-
- if (r->type != ACPI_TYPE_INTEGER) {
- kfree(r);
- return -EIO;
- }
-
- status = !!r->integer.value;
+ u32 status;
+ int ret;
- kfree(r);
+ ret = lg_wmab_get(dev, WM_READER_MODE, &status);
+ if (ret < 0)
+ return ret;
- return sysfs_emit(buffer, "%d\n", status);
+ return sysfs_emit(buffer, "%d\n", !!status);
}
static ssize_t fn_lock_store(struct device *dev,
@@ -403,40 +453,30 @@ static ssize_t fn_lock_store(struct device *dev,
const char *buffer, size_t count)
{
bool value;
- union acpi_object *r;
int ret;
ret = kstrtobool(buffer, &value);
if (ret)
return ret;
- r = lg_wmab(dev, WM_FN_LOCK, WM_SET, value);
- if (!r)
- return -EIO;
+ ret = lg_wmab_set(dev, WM_FN_LOCK, value);
+ if (ret < 0)
+ return ret;
- kfree(r);
return count;
}
static ssize_t fn_lock_show(struct device *dev,
struct device_attribute *attr, char *buffer)
{
- unsigned int status;
- union acpi_object *r;
-
- r = lg_wmab(dev, WM_FN_LOCK, WM_GET, 0);
- if (!r)
- return -EIO;
-
- if (r->type != ACPI_TYPE_BUFFER) {
- kfree(r);
- return -EIO;
- }
+ u32 status;
+ int ret;
- status = !!r->buffer.pointer[0];
- kfree(r);
+ ret = lg_wmab_get(dev, WM_FN_LOCK, &status);
+ if (ret < 0)
+ return ret;
- return sysfs_emit(buffer, "%d\n", status);
+ return sysfs_emit(buffer, "%d\n", !!status);
}
static ssize_t charge_control_end_threshold_store(struct device *dev,
@@ -453,14 +493,18 @@ static ssize_t charge_control_end_threshold_store(struct device *dev,
if (value == 100 || value == 80) {
union acpi_object *r;
- if (battery_limit_use_wmbb)
+ if (battery_limit_use_wmbb) {
r = lg_wmbb(&pf_device->dev, WMBB_BATT_LIMIT, WM_SET, value);
- else
- r = lg_wmab(&pf_device->dev, WM_BATT_LIMIT, WM_SET, value);
- if (!r)
- return -EIO;
+ if (!r)
+ return -EIO;
+
+ kfree(r);
+ } else {
+ ret = lg_wmab_set(&pf_device->dev, WM_BATT_LIMIT, value);
+ if (ret < 0)
+ return ret;
+ }
- kfree(r);
return count;
}
@@ -471,8 +515,9 @@ static ssize_t charge_control_end_threshold_show(struct device *device,
struct device_attribute *attr,
char *buf)
{
- unsigned int status;
union acpi_object *r;
+ u32 status;
+ int ret;
if (battery_limit_use_wmbb) {
r = lg_wmbb(&pf_device->dev, WMBB_BATT_LIMIT, WM_GET, 0);
@@ -485,19 +530,13 @@ static ssize_t charge_control_end_threshold_show(struct device *device,
}
status = r->buffer.pointer[0x10];
+ kfree(r);
} else {
- r = lg_wmab(&pf_device->dev, WM_BATT_LIMIT, WM_GET, 0);
- if (!r)
- return -EIO;
-
- if (r->type != ACPI_TYPE_INTEGER) {
- kfree(r);
- return -EIO;
- }
-
- status = r->integer.value;
+ ret = lg_wmab_get(&pf_device->dev, WM_BATT_LIMIT, &status);
+ if (ret < 0)
+ return ret;
}
- kfree(r);
+
if (status != 80 && status != 100)
status = 0;
@@ -563,10 +602,7 @@ static const struct attribute_group dev_attribute_group = {
static void tpad_led_set(struct led_classdev *cdev,
enum led_brightness brightness)
{
- union acpi_object *r;
-
- r = lg_wmab(cdev->dev->parent, WM_TLED, WM_SET, brightness > LED_OFF);
- kfree(r);
+ lg_wmab_set(cdev->dev->parent, WM_TLED, brightness > LED_OFF);
}
static enum led_brightness tpad_led_get(struct led_classdev *cdev)
@@ -579,47 +615,50 @@ static LED_DEVICE(tpad_led, 1, 0);
static void kbd_backlight_set(struct led_classdev *cdev,
enum led_brightness brightness)
{
- u32 val;
- union acpi_object *r;
+ /* Must always be written */
+ u32 value = KBD_LED_STATUS;
+ u32 mode, bright;
- val = 0x22;
- if (brightness <= LED_OFF)
- val = 0;
- if (brightness >= LED_FULL)
- val = 0x24;
- r = lg_wmab(cdev->dev->parent, WM_KEY_LIGHT, WM_SET, val);
- kfree(r);
+ if (brightness <= LED_OFF) {
+ mode = KBD_LED_MODE_OFF;
+ bright = KBD_LED_BRIGHTNESS_OFF;
+ } else {
+ mode = KBD_LED_MODE_ON;
+ if (brightness >= LED_FULL)
+ bright = KBD_LED_BRIGHTNESS_FULL;
+ else
+ bright = KBD_LED_BRIGHTNESS_HALF;
+ }
+
+ value |= FIELD_PREP(KBD_LED_BRIGHTNESS_MASK, bright);
+ value |= FIELD_PREP(KBD_LED_MODE_MASK, mode);
+
+ lg_wmab_set(cdev->dev->parent, WM_KEY_LIGHT, value);
}
static enum led_brightness get_kbd_backlight_level(struct device *dev)
{
- union acpi_object *r;
- int val;
+ u32 value;
+ int ret;
- r = lg_wmab(dev, WM_KEY_LIGHT, WM_GET, 0);
+ ret = lg_wmab_get(dev, WM_KEY_LIGHT, &value);
+ if (ret < 0)
+ return LED_OFF;
- if (!r)
+ if (FIELD_GET(KBD_LED_MAGIC_MASK, value) != KBD_LED_MAGIC)
return LED_OFF;
- if (r->type != ACPI_TYPE_BUFFER || r->buffer.pointer[1] != 0x05) {
- kfree(r);
+ if (FIELD_GET(KBD_LED_MODE_MASK, value) == KBD_LED_MODE_OFF)
return LED_OFF;
- }
- switch (r->buffer.pointer[0] & 0x27) {
- case 0x24:
- val = LED_FULL;
- break;
- case 0x22:
- val = LED_HALF;
- break;
+ switch (FIELD_GET(KBD_LED_BRIGHTNESS_MASK, value)) {
+ case KBD_LED_BRIGHTNESS_FULL:
+ return LED_FULL;
+ case KBD_LED_BRIGHTNESS_HALF:
+ return LED_HALF;
default:
- val = LED_OFF;
+ return LED_OFF;
}
-
- kfree(r);
-
- return val;
}
static enum led_brightness kbd_backlight_get(struct led_classdev *cdev)
@@ -629,26 +668,163 @@ static enum led_brightness kbd_backlight_get(struct led_classdev *cdev)
static LED_DEVICE(kbd_backlight, 255, LED_BRIGHT_HW_CHANGED);
-static void wmi_input_destroy(void)
+static struct platform_driver pf_driver = {
+ .driver = {
+ .name = PLATFORM_NAME,
+ }
+};
+
+static int lg_laptop_get_event_data(acpi_handle handle, u32 value, u32 *data)
{
- if (inited & INIT_INPUT_WMI_2)
- wmi_remove_notify_handler(WMI_EVENT_GUID2);
+ union acpi_object objs[] = {
+ {
+ .integer = {
+ .type = ACPI_TYPE_INTEGER,
+ .value = value,
+ },
+ }
+ };
+ struct acpi_object_list args = {
+ .count = ARRAY_SIZE(objs),
+ .pointer = objs,
+ };
+ unsigned long long result;
+ acpi_status status;
+
+ status = acpi_evaluate_integer(handle, "_WED", &args, &result);
+ if (ACPI_FAILURE(status))
+ return -EIO;
- if (inited & INIT_INPUT_WMI_0)
- wmi_remove_notify_handler(WMI_EVENT_GUID0);
+ if (result > U32_MAX)
+ return -EPROTO;
- if (inited & INIT_SPARSE_KEYMAP)
- input_unregister_device(wmi_input_dev);
+ *data = result;
- inited &= ~(INIT_INPUT_WMI_0 | INIT_INPUT_WMI_2 | INIT_SPARSE_KEYMAP);
+ return 0;
}
-static struct platform_driver pf_driver = {
- .driver = {
- .name = PLATFORM_NAME,
+static void lg_laptop_handle_input_event(struct input_dev *input_dev, u32 value, u32 data)
+{
+ unsigned int kbd_brightness;
+
+ switch (value) {
+ case LG_NOTIFY_HOTKEY:
+ sparse_keymap_report_event(input_dev, data, 1, true);
+ break;
+ case LG_NOTIFY_THERMAL:
+ /* Currently not supported */
+ break;
+ case LG_NOTIFY_MISC:
+ switch (data) {
+ case 0x10000000:
+ if (!kbd_backlight_available)
+ break;
+
+ kbd_brightness = get_kbd_backlight_level(kbd_backlight.dev->parent);
+ led_classdev_notify_brightness_hw_changed(&kbd_backlight, kbd_brightness);
+ break;
+ default:
+ sparse_keymap_report_event(input_dev, data, 1, true);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void lg_laptop_notify_handler(acpi_handle handle, u32 value, void *context)
+{
+ struct input_dev *input_dev = context;
+ u32 data;
+ int ret;
+
+ switch (value) {
+ case LG_NOTIFY_TABLET_MODE_OFF:
+ case LG_NOTIFY_TABLET_MODE_ON:
+ /* Already handled by intel-hid */
+ return;
+ case LG_NOTIFY_HOTKEY:
+ case LG_NOTIFY_THERMAL:
+ case LG_NOTIFY_MISC:
+ ret = lg_laptop_get_event_data(handle, value, &data);
+ if (ret < 0) {
+ dev_notice(input_dev->dev.parent, "Failed to get event data: %d\n", ret);
+ return;
+ }
+
+ dev_dbg(input_dev->dev.parent, "Received event %u (%u)\n", value, data);
+
+ lg_laptop_handle_input_event(input_dev, value, data);
+ return;
+ default:
+ dev_notice(input_dev->dev.parent, "Received unknown event %u\n", value);
}
};
+static void lg_laptop_remove_notify_handler(void *context)
+{
+ acpi_handle handle = context;
+
+ acpi_remove_notify_handler(handle, ACPI_ALL_NOTIFY, lg_laptop_notify_handler);
+}
+
+static void lg_laptop_reenable_wmi_events(void *context)
+{
+ acpi_handle handle = context;
+ unsigned long long dummy;
+
+ lg_laptop_execute_orep(handle, LG_OREP_INTERCEPT_WMI_EVENTS, 0, &dummy);
+}
+
+static int lg_laptop_input_init(struct device *dev, acpi_handle handle)
+{
+ struct input_dev *input_dev;
+ unsigned long long result;
+ acpi_status status;
+ int ret;
+
+ if (!acpi_has_method(handle, "_WED"))
+ return 0;
+
+ input_dev = devm_input_allocate_device(dev);
+ if (!input_dev)
+ return -ENOMEM;
+
+ input_dev->name = "LG WMI hotkeys";
+ input_dev->phys = "wmi/input0";
+ input_dev->id.bustype = BUS_HOST;
+ ret = sparse_keymap_setup(input_dev, wmi_keymap, NULL);
+ if (ret < 0)
+ return ret;
+
+ ret = input_register_device(input_dev);
+ if (ret < 0)
+ return ret;
+
+ status = acpi_install_notify_handler(handle, ACPI_ALL_NOTIFY, lg_laptop_notify_handler,
+ input_dev);
+ if (ACPI_FAILURE(status))
+ return -EIO;
+
+ ret = devm_add_action_or_reset(dev, lg_laptop_remove_notify_handler, handle);
+ if (ret < 0)
+ return ret;
+
+ if (acpi_has_method(handle, "OREP")) {
+ ret = lg_laptop_execute_orep(handle, LG_OREP_INTERCEPT_WMI_EVENTS, 1, &result);
+ if (ret < 0)
+ return ret;
+ if (result)
+ return -EIO;
+
+ ret = devm_add_action_or_reset(dev, lg_laptop_reenable_wmi_events, handle);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
static acpi_status lg_laptop_address_space_write(struct device *dev, acpi_physical_address address,
size_t size, u64 value)
{
@@ -860,15 +1036,23 @@ static int acpi_probe(struct platform_device *pdev)
if (year >= 2019)
battery_limit_use_wmbb = 1;
+ /* LEDs are optional */
+ ret = devm_led_classdev_register(&pdev->dev, &kbd_backlight);
+ if (ret < 0)
+ kbd_backlight_available = false;
+ else
+ kbd_backlight_available = true;
+
+ devm_led_classdev_register(&pdev->dev, &tpad_led);
+
+ ret = lg_laptop_input_init(&pdev->dev, device->handle);
+ if (ret < 0)
+ goto out_platform_device;
+
ret = sysfs_create_group(&pf_device->dev.kobj, &dev_attribute_group);
if (ret)
goto out_platform_device;
- /* LEDs are optional */
- led_classdev_register(&pf_device->dev, &kbd_backlight);
- led_classdev_register(&pf_device->dev, &tpad_led);
-
- wmi_input_setup();
battery_hook_register(&battery_hook);
return 0;
@@ -884,11 +1068,7 @@ static void acpi_remove(struct platform_device *pdev)
{
sysfs_remove_group(&pf_device->dev.kobj, &dev_attribute_group);
- led_classdev_unregister(&tpad_led);
- led_classdev_unregister(&kbd_backlight);
-
battery_hook_unregister(&battery_hook);
- wmi_input_destroy();
platform_device_unregister(pf_device);
pf_device = NULL;
platform_driver_unregister(&pf_driver);
diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c
index 719add753cb3..3effb11c4153 100644
--- a/drivers/platform/x86/panasonic-laptop.c
+++ b/drivers/platform/x86/panasonic-laptop.c
@@ -159,8 +159,6 @@ MODULE_LICENSE("GPL");
#define ECO_MODE_ON 0x80
#define ACPI_PCC_DRIVER_NAME "Panasonic Laptop Support"
-#define ACPI_PCC_DEVICE_NAME "Hotkey"
-#define ACPI_PCC_CLASS "pcc"
#define ACPI_PCC_INPUT_PHYS "panasonic/hkey0"
@@ -1017,8 +1015,6 @@ static int acpi_pcc_hotkey_probe(struct platform_device *pdev)
pcc->device = device;
pcc->handle = device->handle;
device->driver_data = pcc;
- strscpy(acpi_device_name(device), ACPI_PCC_DEVICE_NAME);
- strscpy(acpi_device_class(device), ACPI_PCC_CLASS);
result = acpi_pcc_init_input(pcc);
if (result) {
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 67370967df6f..0bf4d3054e37 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -1264,7 +1264,7 @@ static void sony_nc_notify(acpi_handle ah, u32 event, void *data)
ev_type = HOTKEY;
sony_laptop_report_input_event(real_ev);
}
- acpi_bus_generate_netlink_event(sony_nc_acpi_device->pnp.device_class,
+ acpi_bus_generate_netlink_event("sony/hotkey",
dev_name(&sony_nc_acpi_device->dev), ev_type, real_ev);
}
@@ -3157,8 +3157,6 @@ static int sony_nc_probe(struct platform_device *pdev)
return -ENODEV;
sony_nc_acpi_device = device;
- strscpy(acpi_device_class(device), "sony/hotkey");
-
sony_nc_acpi_handle = device->handle;
/* read device status */
@@ -4523,7 +4521,6 @@ static int sony_pic_probe(struct platform_device *pdev)
return -ENODEV;
spic_dev.acpi_dev = device;
- strscpy(acpi_device_class(device), "sony/hotkey");
sony_pic_detect_device_type(&spic_dev);
mutex_init(&spic_dev.lock);
diff --git a/drivers/platform/x86/topstar-laptop.c b/drivers/platform/x86/topstar-laptop.c
index e09d7f8ce45f..0e842c55dcc5 100644
--- a/drivers/platform/x86/topstar-laptop.c
+++ b/drivers/platform/x86/topstar-laptop.c
@@ -299,8 +299,6 @@ static int topstar_acpi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, topstar);
- strscpy(acpi_device_name(device), "Topstar TPSACPI");
- strscpy(acpi_device_class(device), TOPSTAR_LAPTOP_CLASS);
topstar->device = device;
err = topstar_acpi_init(topstar);
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
index 7cecb3a70b9c..a0b8060836d0 100644
--- a/drivers/platform/x86/toshiba_acpi.c
+++ b/drivers/platform/x86/toshiba_acpi.c
@@ -2505,8 +2505,7 @@ static void toshiba_acpi_kbd_bl_work(struct work_struct *work)
LED_FULL : LED_OFF);
/* Emulate the keyboard backlight event */
- acpi_bus_generate_netlink_event(toshiba_acpi->acpi_dev->pnp.device_class,
- dev_name(&toshiba_acpi->acpi_dev->dev),
+ acpi_bus_generate_netlink_event("", dev_name(&toshiba_acpi->acpi_dev->dev),
0x92, 0);
}
@@ -3250,8 +3249,7 @@ static void toshiba_acpi_notify(acpi_handle handle, u32 event, void *data)
break;
}
- acpi_bus_generate_netlink_event(acpi_dev->pnp.device_class,
- dev_name(&acpi_dev->dev),
+ acpi_bus_generate_netlink_event("", dev_name(&acpi_dev->dev),
event, (event == 0x80) ?
dev->last_key_event : 0);
}
diff --git a/drivers/platform/x86/toshiba_haps.c b/drivers/platform/x86/toshiba_haps.c
index 8d12241924df..c6633b74029f 100644
--- a/drivers/platform/x86/toshiba_haps.c
+++ b/drivers/platform/x86/toshiba_haps.c
@@ -136,9 +136,7 @@ static void toshiba_haps_notify(acpi_handle handle, u32 event, void *data)
pr_debug("Received event: 0x%x\n", event);
- acpi_bus_generate_netlink_event(device->pnp.device_class,
- dev_name(&device->dev),
- event, 0);
+ acpi_bus_generate_netlink_event("", dev_name(&device->dev), event, 0);
}
static void toshiba_haps_remove(struct platform_device *pdev)
diff --git a/drivers/platform/x86/xo15-ebook.c b/drivers/platform/x86/xo15-ebook.c
index e40e385c52bd..4c3185e2ceec 100644
--- a/drivers/platform/x86/xo15-ebook.c
+++ b/drivers/platform/x86/xo15-ebook.c
@@ -19,13 +19,10 @@
#define MODULE_NAME "xo15-ebook"
-#define XO15_EBOOK_CLASS MODULE_NAME
#define XO15_EBOOK_TYPE_UNKNOWN 0x00
#define XO15_EBOOK_NOTIFY_STATUS 0x80
-#define XO15_EBOOK_SUBCLASS "ebook"
#define XO15_EBOOK_HID "XO15EBK"
-#define XO15_EBOOK_DEVICE_NAME "EBook Switch"
MODULE_DESCRIPTION("OLPC XO-1.5 ebook switch driver");
MODULE_LICENSE("GPL");
@@ -105,12 +102,9 @@ static int ebook_switch_probe(struct platform_device *pdev)
if (!id)
return dev_err_probe(dev, -ENODEV, "Unsupported hid\n");
- strscpy(acpi_device_name(device), XO15_EBOOK_DEVICE_NAME);
- strscpy(acpi_device_class(device), XO15_EBOOK_CLASS "/" XO15_EBOOK_SUBCLASS);
-
snprintf(button->phys, sizeof(button->phys), "%s/button/input0", id->id);
- input->name = acpi_device_name(device);
+ input->name = "EBook Switch";
input->phys = button->phys;
input->id.bustype = BUS_HOST;
diff --git a/drivers/pmdomain/imx/imx8m-blk-ctrl.c b/drivers/pmdomain/imx/imx8m-blk-ctrl.c
index 19e992d2ee3b..99d100e1d923 100644
--- a/drivers/pmdomain/imx/imx8m-blk-ctrl.c
+++ b/drivers/pmdomain/imx/imx8m-blk-ctrl.c
@@ -54,6 +54,15 @@ struct imx8m_blk_ctrl_domain_data {
* register.
*/
u32 mipi_phy_rst_mask;
+
+ /*
+ * VC8000E reset de-assertion edge and AXI clock may have a timing issue.
+ * Workaround: Set bit2 (vc8000e_clk_en) of BLK_CLK_EN_CSR to 0 to gate off
+ * both AXI clock and VC8000E clock sent to VC8000E and AXI clock sent to
+ * VPU_NOC m_v_2 interface during VC8000E power up(VC8000E reset is
+ * de-asserted by HW)
+ */
+ bool is_errata_err050531;
};
#define DOMAIN_MAX_CLKS 4
@@ -108,7 +117,11 @@ static int imx8m_blk_ctrl_power_on(struct generic_pm_domain *genpd)
dev_err(bc->dev, "failed to enable clocks\n");
goto bus_put;
}
- regmap_set_bits(bc->regmap, BLK_CLK_EN, data->clk_mask);
+
+ if (data->is_errata_err050531)
+ regmap_clear_bits(bc->regmap, BLK_CLK_EN, data->clk_mask);
+ else
+ regmap_set_bits(bc->regmap, BLK_CLK_EN, data->clk_mask);
/* power up upstream GPC domain */
ret = pm_runtime_get_sync(domain->power_dev);
@@ -117,6 +130,9 @@ static int imx8m_blk_ctrl_power_on(struct generic_pm_domain *genpd)
goto clk_disable;
}
+ if (data->is_errata_err050531)
+ regmap_set_bits(bc->regmap, BLK_CLK_EN, data->clk_mask);
+
/* wait for reset to propagate */
udelay(5);
@@ -511,12 +527,38 @@ static const struct imx8m_blk_ctrl_domain_data imx8mp_vpu_blk_ctl_domain_data[]
.clk_mask = BIT(2),
.path_names = (const char *[]){"vc8000e"},
.num_paths = 1,
+ .is_errata_err050531 = true,
},
};
+static int imx8mp_vpu_power_notifier(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct imx8m_blk_ctrl *bc = container_of(nb, struct imx8m_blk_ctrl,
+ power_nb);
+
+ if (action == GENPD_NOTIFY_ON) {
+ /*
+ * On power up we have no software backchannel to the GPC to
+ * wait for the ADB handshake to happen, so we just delay for a
+ * bit. On power down the GPC driver waits for the handshake.
+ */
+
+ udelay(5);
+
+ /* set "fuse" bits to enable the VPUs */
+ regmap_set_bits(bc->regmap, 0x8, 0xffffffff);
+ regmap_set_bits(bc->regmap, 0xc, 0xffffffff);
+ regmap_set_bits(bc->regmap, 0x10, 0xffffffff);
+ regmap_set_bits(bc->regmap, 0x14, 0xffffffff);
+ }
+
+ return NOTIFY_OK;
+}
+
static const struct imx8m_blk_ctrl_data imx8mp_vpu_blk_ctl_dev_data = {
.max_reg = 0x18,
- .power_notifier_fn = imx8mm_vpu_power_notifier,
+ .power_notifier_fn = imx8mp_vpu_power_notifier,
.domains = imx8mp_vpu_blk_ctl_domain_data,
.num_domains = ARRAY_SIZE(imx8mp_vpu_blk_ctl_domain_data),
};
diff --git a/drivers/pmdomain/imx/imx93-blk-ctrl.c b/drivers/pmdomain/imx/imx93-blk-ctrl.c
index 1afc78b034fa..243ce939ba68 100644
--- a/drivers/pmdomain/imx/imx93-blk-ctrl.c
+++ b/drivers/pmdomain/imx/imx93-blk-ctrl.c
@@ -48,6 +48,8 @@
#define PRIO(X) (X)
+#define BLK_CTRL_NO_PARENT UINT_MAX
+
struct imx93_blk_ctrl_domain;
struct imx93_blk_ctrl {
@@ -68,12 +70,18 @@ struct imx93_blk_ctrl_qos {
u32 cfg_prio;
};
+struct imx93_blk_ctrl_subdomain_link {
+ struct generic_pm_domain *parent;
+ struct generic_pm_domain *subdomain;
+};
+
struct imx93_blk_ctrl_domain_data {
const char *name;
const char * const *clk_names;
int num_clks;
u32 rst_mask;
u32 clk_mask;
+ u32 parent;
int num_qos;
struct imx93_blk_ctrl_qos qos[DOMAIN_MAX_QOS];
};
@@ -203,6 +211,13 @@ static void imx93_release_pm_genpd(void *data)
pm_genpd_remove(genpd);
}
+static void imx93_release_subdomain(void *data)
+{
+ struct imx93_blk_ctrl_subdomain_link *link = data;
+
+ pm_genpd_remove_subdomain(link->parent, link->subdomain);
+}
+
static struct lock_class_key blk_ctrl_genpd_lock_class;
static int imx93_blk_ctrl_probe(struct platform_device *pdev)
@@ -302,6 +317,34 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev)
bc->onecell_data.domains[i] = &domain->genpd;
}
+ for (i = 0; i < bc_data->num_domains; i++) {
+ struct imx93_blk_ctrl_domain *domain = &bc->domains[i];
+ const struct imx93_blk_ctrl_domain_data *data = domain->data;
+ struct imx93_blk_ctrl_subdomain_link *link;
+
+ if (bc_data->skip_mask & BIT(i) ||
+ data->parent == BLK_CTRL_NO_PARENT)
+ continue;
+
+ link = devm_kzalloc(dev, sizeof(*link), GFP_KERNEL);
+ if (!link)
+ return -ENOMEM;
+
+ link->parent = &bc->domains[data->parent].genpd;
+ link->subdomain = &domain->genpd;
+
+ ret = pm_genpd_add_subdomain(&bc->domains[data->parent].genpd,
+ &domain->genpd);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to add subdomain %s\n",
+ domain->genpd.name);
+
+ ret = devm_add_action_or_reset(dev, imx93_release_subdomain, link);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to add subdomain release callback\n");
+ }
+
ret = devm_pm_runtime_enable(dev);
if (ret)
return dev_err_probe(dev, ret, "failed to enable pm-runtime\n");
@@ -326,8 +369,9 @@ static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[]
.name = "mediablk-mipi-dsi",
.clk_names = (const char *[]){ "dsi" },
.num_clks = 1,
- .rst_mask = BIT(11) | BIT(12),
- .clk_mask = BIT(11) | BIT(12),
+ .rst_mask = BIT(11),
+ .clk_mask = BIT(11),
+ .parent = IMX93_MEDIABLK_PD_MIPI_PHY,
},
[IMX93_MEDIABLK_PD_MIPI_CSI] = {
.name = "mediablk-mipi-csi",
@@ -335,6 +379,7 @@ static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[]
.num_clks = 2,
.rst_mask = BIT(9) | BIT(10),
.clk_mask = BIT(9) | BIT(10),
+ .parent = IMX93_MEDIABLK_PD_MIPI_PHY,
},
[IMX93_MEDIABLK_PD_PXP] = {
.name = "mediablk-pxp",
@@ -342,6 +387,7 @@ static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[]
.num_clks = 1,
.rst_mask = BIT(7) | BIT(8),
.clk_mask = BIT(7) | BIT(8),
+ .parent = BLK_CTRL_NO_PARENT,
.num_qos = 2,
.qos = {
{
@@ -363,6 +409,7 @@ static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[]
.num_clks = 2,
.rst_mask = BIT(4) | BIT(5) | BIT(6),
.clk_mask = BIT(4) | BIT(5) | BIT(6),
+ .parent = BLK_CTRL_NO_PARENT,
.num_qos = 1,
.qos = {
{
@@ -379,6 +426,7 @@ static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[]
.num_clks = 1,
.rst_mask = BIT(2) | BIT(3),
.clk_mask = BIT(2) | BIT(3),
+ .parent = BLK_CTRL_NO_PARENT,
.num_qos = 4,
.qos = {
{
@@ -404,6 +452,14 @@ static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[]
}
}
},
+ [IMX93_MEDIABLK_PD_MIPI_PHY] = {
+ .name = "mediablk-mipi-phy",
+ .clk_names = NULL,
+ .num_clks = 0,
+ .rst_mask = BIT(12),
+ .clk_mask = BIT(12),
+ .parent = BLK_CTRL_NO_PARENT,
+ },
};
static const struct regmap_range imx93_media_blk_ctl_yes_ranges[] = {
diff --git a/drivers/pmdomain/qcom/rpmhpd.c b/drivers/pmdomain/qcom/rpmhpd.c
index 63120e703923..c12127d8e8ae 100644
--- a/drivers/pmdomain/qcom/rpmhpd.c
+++ b/drivers/pmdomain/qcom/rpmhpd.c
@@ -305,10 +305,10 @@ static struct rpmhpd *sa8775p_rpmhpds[] = {
[SA8775P_LMX] = &lmx,
[SA8775P_MMCX] = &mmcx,
[SA8775P_MMCX_AO] = &mmcx_ao,
- [SA8775P_MXC] = &mxc,
- [SA8775P_MXC_AO] = &mxc_ao,
[SA8775P_MX] = &mx,
[SA8775P_MX_AO] = &mx_ao,
+ [SA8775P_MXC] = &mxc,
+ [SA8775P_MXC_AO] = &mxc_ao,
[SA8775P_NSP0] = &nsp0,
[SA8775P_NSP1] = &nsp1,
};
@@ -325,10 +325,10 @@ static struct rpmhpd *nord_rpmhpds[] = {
[RPMHPD_EBI] = &ebi,
[RPMHPD_GFX] = &gfx,
[RPMHPD_GFX1] = &gfx1,
- [RPMHPD_MX] = &mx,
- [RPMHPD_MX_AO] = &mx_ao,
[RPMHPD_MMCX] = &mmcx,
[RPMHPD_MMCX_AO] = &mmcx_ao,
+ [RPMHPD_MX] = &mx,
+ [RPMHPD_MX_AO] = &mx_ao,
[RPMHPD_MXC] = &mxc,
[RPMHPD_MXC_AO] = &mxc_ao,
[RPMHPD_NSP0] = &nsp0,
@@ -480,9 +480,9 @@ static struct rpmhpd *sm7150_rpmhpds[] = {
[RPMHPD_GFX] = &gfx,
[RPMHPD_LCX] = &lcx,
[RPMHPD_LMX] = &lmx,
+ [RPMHPD_MSS] = &mss,
[RPMHPD_MX] = &mx,
[RPMHPD_MX_AO] = &mx_ao,
- [RPMHPD_MSS] = &mss,
};
static const struct rpmhpd_desc sm7150_desc = {
@@ -698,11 +698,11 @@ static struct rpmhpd *hawi_rpmhpds[] = {
[RPMHPD_LMX] = &lmx,
[RPMHPD_MMCX] = &mmcx,
[RPMHPD_MMCX_AO] = &mmcx_ao,
+ [RPMHPD_MSS] = &mss,
[RPMHPD_MX] = &mx,
[RPMHPD_MX_AO] = &mx_ao,
[RPMHPD_MXC] = &mxc,
[RPMHPD_MXC_AO] = &mxc_ao,
- [RPMHPD_MSS] = &mss,
[RPMHPD_NSP] = &nsp,
[RPMHPD_NSP2] = &nsp2,
};
@@ -809,18 +809,18 @@ static struct rpmhpd *glymur_rpmhpds[] = {
[RPMHPD_CX_AO] = &cx_ao,
[RPMHPD_EBI] = &ebi,
[RPMHPD_GFX] = &gfx,
+ [RPMHPD_GMXC] = &gmxc,
[RPMHPD_LCX] = &lcx,
[RPMHPD_LMX] = &lmx,
[RPMHPD_MMCX] = &mmcx,
[RPMHPD_MMCX_AO] = &mmcx_ao,
+ [RPMHPD_MSS] = &mss,
[RPMHPD_MX] = &mx,
[RPMHPD_MX_AO] = &mx_ao,
[RPMHPD_MXC] = &mxc,
[RPMHPD_MXC_AO] = &mxc_ao,
- [RPMHPD_MSS] = &mss,
[RPMHPD_NSP] = &nsp,
[RPMHPD_NSP2] = &nsp2,
- [RPMHPD_GMXC] = &gmxc,
};
static const struct rpmhpd_desc glymur_desc = {
@@ -834,15 +834,15 @@ static struct rpmhpd *x1e80100_rpmhpds[] = {
[RPMHPD_CX_AO] = &cx_ao,
[RPMHPD_EBI] = &ebi,
[RPMHPD_GFX] = &gfx,
+ [RPMHPD_GMXC] = &gmxc,
[RPMHPD_LCX] = &lcx,
[RPMHPD_LMX] = &lmx,
[RPMHPD_MMCX] = &mmcx,
[RPMHPD_MMCX_AO] = &mmcx_ao,
[RPMHPD_MX] = &mx,
[RPMHPD_MX_AO] = &mx_ao,
- [RPMHPD_NSP] = &nsp,
[RPMHPD_MXC] = &mxc,
- [RPMHPD_GMXC] = &gmxc,
+ [RPMHPD_NSP] = &nsp,
};
static const struct rpmhpd_desc x1e80100_desc = {
@@ -860,10 +860,10 @@ static struct rpmhpd *qcs8300_rpmhpds[] = {
[RPMHPD_LMX] = &lmx,
[RPMHPD_MMCX] = &mmcx_w_cx_parent,
[RPMHPD_MMCX_AO] = &mmcx_ao_w_cx_parent,
- [RPMHPD_MXC] = &mxc,
- [RPMHPD_MXC_AO] = &mxc_ao,
[RPMHPD_MX] = &mx,
[RPMHPD_MX_AO] = &mx_ao,
+ [RPMHPD_MXC] = &mxc,
+ [RPMHPD_MXC_AO] = &mxc_ao,
[RPMHPD_NSP0] = &nsp0,
[RPMHPD_NSP1] = &nsp1,
};
diff --git a/drivers/power/supply/ab8500_btemp.c b/drivers/power/supply/ab8500_btemp.c
index e5202a7b6209..36b0c52a4b8b 100644
--- a/drivers/power/supply/ab8500_btemp.c
+++ b/drivers/power/supply/ab8500_btemp.c
@@ -829,3 +829,4 @@ MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Johan Palsson, Karl Komierowski, Arun R Murthy");
MODULE_ALIAS("platform:ab8500-btemp");
MODULE_DESCRIPTION("AB8500 battery temperature driver");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c
index 1813fbdfa1c1..5c3af3571013 100644
--- a/drivers/power/supply/ab8500_charger.c
+++ b/drivers/power/supply/ab8500_charger.c
@@ -3751,3 +3751,4 @@ MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Johan Palsson, Karl Komierowski, Arun R Murthy");
MODULE_ALIAS("platform:ab8500-charger");
MODULE_DESCRIPTION("AB8500 charger management driver");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c
index eb5c1ae68e44..3ab33cf465c6 100644
--- a/drivers/power/supply/ab8500_fg.c
+++ b/drivers/power/supply/ab8500_fg.c
@@ -3252,3 +3252,4 @@ MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Johan Palsson, Karl Komierowski");
MODULE_ALIAS("platform:ab8500-fg");
MODULE_DESCRIPTION("AB8500 Fuel Gauge driver");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/power/supply/axp20x_ac_power.c b/drivers/power/supply/axp20x_ac_power.c
index 5f6ea416fa30..e9049d6229df 100644
--- a/drivers/power/supply/axp20x_ac_power.c
+++ b/drivers/power/supply/axp20x_ac_power.c
@@ -421,3 +421,4 @@ module_platform_driver(axp20x_ac_power_driver);
MODULE_AUTHOR("Quentin Schulz <quentin.schulz@free-electrons.com>");
MODULE_DESCRIPTION("AXP20X and AXP22X PMICs' AC power supply driver");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/power/supply/axp20x_battery.c b/drivers/power/supply/axp20x_battery.c
index 50ca8e110085..ee8701a6e907 100644
--- a/drivers/power/supply/axp20x_battery.c
+++ b/drivers/power/supply/axp20x_battery.c
@@ -1155,3 +1155,4 @@ module_platform_driver(axp20x_batt_driver);
MODULE_DESCRIPTION("Battery power supply driver for AXP20X and AXP22X PMICs");
MODULE_AUTHOR("Quentin Schulz <quentin.schulz@free-electrons.com>");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/power/supply/axp20x_usb_power.c b/drivers/power/supply/axp20x_usb_power.c
index e75d1e377ac1..599adcf84968 100644
--- a/drivers/power/supply/axp20x_usb_power.c
+++ b/drivers/power/supply/axp20x_usb_power.c
@@ -1080,3 +1080,4 @@ module_platform_driver(axp20x_usb_power_driver);
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
MODULE_DESCRIPTION("AXP20x PMIC USB power supply status driver");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/power/supply/axp288_fuel_gauge.c b/drivers/power/supply/axp288_fuel_gauge.c
index 5af334c0a980..05a850ec0131 100644
--- a/drivers/power/supply/axp288_fuel_gauge.c
+++ b/drivers/power/supply/axp288_fuel_gauge.c
@@ -817,3 +817,4 @@ MODULE_AUTHOR("Ramakrishna Pallala <ramakrishna.pallala@intel.com>");
MODULE_AUTHOR("Todd Brandt <todd.e.brandt@linux.intel.com>");
MODULE_DESCRIPTION("Xpower AXP288 Fuel Gauge Driver");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/power/supply/cpcap-battery.c b/drivers/power/supply/cpcap-battery.c
index 59c741993ef8..4d7e77d7375b 100644
--- a/drivers/power/supply/cpcap-battery.c
+++ b/drivers/power/supply/cpcap-battery.c
@@ -1206,3 +1206,4 @@ module_platform_driver(cpcap_battery_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>");
MODULE_DESCRIPTION("CPCAP PMIC Battery Driver");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/power/supply/cpcap-charger.c b/drivers/power/supply/cpcap-charger.c
index ec8d2a9245d9..744ee12edd1e 100644
--- a/drivers/power/supply/cpcap-charger.c
+++ b/drivers/power/supply/cpcap-charger.c
@@ -977,3 +977,4 @@ MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>");
MODULE_DESCRIPTION("CPCAP Battery Charger Interface driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:cpcap-charger");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/power/supply/da9150-charger.c b/drivers/power/supply/da9150-charger.c
index 27f36ef5b88d..58449df6068c 100644
--- a/drivers/power/supply/da9150-charger.c
+++ b/drivers/power/supply/da9150-charger.c
@@ -644,3 +644,4 @@ module_platform_driver(da9150_charger_driver);
MODULE_DESCRIPTION("Charger Driver for DA9150");
MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/power/supply/generic-adc-battery.c b/drivers/power/supply/generic-adc-battery.c
index f5f2566b3a32..d18c8ee40405 100644
--- a/drivers/power/supply/generic-adc-battery.c
+++ b/drivers/power/supply/generic-adc-battery.c
@@ -298,3 +298,4 @@ module_platform_driver(gab_driver);
MODULE_AUTHOR("anish kumar <yesanishhere@gmail.com>");
MODULE_DESCRIPTION("generic battery driver using IIO");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/power/supply/ingenic-battery.c b/drivers/power/supply/ingenic-battery.c
index b111c7ce2be3..5be269f17bff 100644
--- a/drivers/power/supply/ingenic-battery.c
+++ b/drivers/power/supply/ingenic-battery.c
@@ -190,3 +190,4 @@ module_platform_driver(ingenic_battery_driver);
MODULE_DESCRIPTION("Battery driver for Ingenic JZ47xx SoCs");
MODULE_AUTHOR("Artur Rojek <contact@artur-rojek.eu>");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/power/supply/intel_dc_ti_battery.c b/drivers/power/supply/intel_dc_ti_battery.c
index 67a75281b0ac..cb6fa8d88b43 100644
--- a/drivers/power/supply/intel_dc_ti_battery.c
+++ b/drivers/power/supply/intel_dc_ti_battery.c
@@ -389,3 +389,4 @@ MODULE_ALIAS("platform:" DEV_NAME);
MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>");
MODULE_DESCRIPTION("Intel Dollar Cove (TI) battery driver");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/power/supply/lego_ev3_battery.c b/drivers/power/supply/lego_ev3_battery.c
index 582644f4e8b3..1e53f11a8e2b 100644
--- a/drivers/power/supply/lego_ev3_battery.c
+++ b/drivers/power/supply/lego_ev3_battery.c
@@ -230,3 +230,4 @@ module_platform_driver(lego_ev3_battery_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Lechner <david@lechnology.com>");
MODULE_DESCRIPTION("LEGO MINDSTORMS EV3 Battery Driver");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/power/supply/lp8788-charger.c b/drivers/power/supply/lp8788-charger.c
index f0a680c155c4..8c6ec98362d0 100644
--- a/drivers/power/supply/lp8788-charger.c
+++ b/drivers/power/supply/lp8788-charger.c
@@ -727,3 +727,4 @@ MODULE_DESCRIPTION("TI LP8788 Charger Driver");
MODULE_AUTHOR("Milo Kim");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:lp8788-charger");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/power/supply/max17040_battery.c b/drivers/power/supply/max17040_battery.c
index e94d53b36aa4..19a9b1bed29e 100644
--- a/drivers/power/supply/max17040_battery.c
+++ b/drivers/power/supply/max17040_battery.c
@@ -639,3 +639,4 @@ module_i2c_driver(max17040_i2c_driver);
MODULE_AUTHOR("Minkyu Kang <mk7.kang@samsung.com>");
MODULE_DESCRIPTION("MAX17040 Fuel Gauge");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/power/supply/mp2629_charger.c b/drivers/power/supply/mp2629_charger.c
index f758d6a7bc8c..c06743d2abff 100644
--- a/drivers/power/supply/mp2629_charger.c
+++ b/drivers/power/supply/mp2629_charger.c
@@ -659,3 +659,4 @@ module_platform_driver(mp2629_charger_driver);
MODULE_AUTHOR("Saravanan Sekar <sravanhome@gmail.com>");
MODULE_DESCRIPTION("MP2629 Charger driver");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/power/supply/mt6370-charger.c b/drivers/power/supply/mt6370-charger.c
index 916556baa854..8ac5f4d59f39 100644
--- a/drivers/power/supply/mt6370-charger.c
+++ b/drivers/power/supply/mt6370-charger.c
@@ -930,3 +930,4 @@ module_platform_driver(mt6370_chg_driver);
MODULE_AUTHOR("ChiaEn Wu <chiaen_wu@richtek.com>");
MODULE_DESCRIPTION("MediaTek MT6370 Charger Driver");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/power/supply/qcom_smbx.c b/drivers/power/supply/qcom_smbx.c
index bf2e2ccc454a..7010374b302a 100644
--- a/drivers/power/supply/qcom_smbx.c
+++ b/drivers/power/supply/qcom_smbx.c
@@ -1057,3 +1057,4 @@ module_platform_driver(qcom_spmi_smb);
MODULE_AUTHOR("Casey Connolly <casey.connolly@linaro.org>");
MODULE_DESCRIPTION("Qualcomm SMB2 Charger Driver");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/power/supply/rn5t618_power.c b/drivers/power/supply/rn5t618_power.c
index 40dec55a9f73..a3f30e390c11 100644
--- a/drivers/power/supply/rn5t618_power.c
+++ b/drivers/power/supply/rn5t618_power.c
@@ -821,3 +821,4 @@ module_platform_driver(rn5t618_power_driver);
MODULE_ALIAS("platform:rn5t618-power");
MODULE_DESCRIPTION("Power supply driver for RICOH RN5T618");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/power/supply/rx51_battery.c b/drivers/power/supply/rx51_battery.c
index b0220ec2d926..57266921dc8e 100644
--- a/drivers/power/supply/rx51_battery.c
+++ b/drivers/power/supply/rx51_battery.c
@@ -246,3 +246,4 @@ MODULE_ALIAS("platform:rx51-battery");
MODULE_AUTHOR("Pali Rohár <pali@kernel.org>");
MODULE_DESCRIPTION("Nokia RX-51 battery driver");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/power/supply/sc27xx_fuel_gauge.c b/drivers/power/supply/sc27xx_fuel_gauge.c
index a7ed9de8a289..1719ec4173e6 100644
--- a/drivers/power/supply/sc27xx_fuel_gauge.c
+++ b/drivers/power/supply/sc27xx_fuel_gauge.c
@@ -1350,3 +1350,4 @@ module_platform_driver(sc27xx_fgu_driver);
MODULE_DESCRIPTION("Spreadtrum SC27XX PMICs Fual Gauge Unit Driver");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/power/supply/twl4030_charger.c b/drivers/power/supply/twl4030_charger.c
index 04216b2bfb6c..151f7b24e9b9 100644
--- a/drivers/power/supply/twl4030_charger.c
+++ b/drivers/power/supply/twl4030_charger.c
@@ -1144,3 +1144,4 @@ MODULE_AUTHOR("Gražvydas Ignotas");
MODULE_DESCRIPTION("TWL4030 Battery Charger Interface driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:twl4030_bci");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/power/supply/twl4030_madc_battery.c b/drivers/power/supply/twl4030_madc_battery.c
index a99b3ff26929..5e04b4f0a135 100644
--- a/drivers/power/supply/twl4030_madc_battery.c
+++ b/drivers/power/supply/twl4030_madc_battery.c
@@ -235,3 +235,4 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Lukas Märdian <lukas@goldelico.com>");
MODULE_DESCRIPTION("twl4030_madc battery driver");
MODULE_ALIAS("platform:twl4030_madc_battery");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/power/supply/twl6030_charger.c b/drivers/power/supply/twl6030_charger.c
index b4ec26ff257c..82911a811f4e 100644
--- a/drivers/power/supply/twl6030_charger.c
+++ b/drivers/power/supply/twl6030_charger.c
@@ -579,3 +579,4 @@ module_platform_driver(twl6030_charger_driver);
MODULE_DESCRIPTION("TWL6030 Battery Charger Interface driver");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index e8886a9b64d9..729776086879 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -569,7 +569,7 @@ config PWM_PCA9685
config PWM_PXA
tristate "PXA PWM support"
depends on ARCH_PXA || ARCH_MMP || ARCH_SPACEMIT || COMPILE_TEST
- depends on HAS_IOMEM
+ depends on HAS_IOMEM && OF
help
Generic PWM framework driver for PXA.
diff --git a/drivers/pwm/pwm-apple.c b/drivers/pwm/pwm-apple.c
index aa49ca1c30e8..dac8c9a76b2d 100644
--- a/drivers/pwm/pwm-apple.c
+++ b/drivers/pwm/pwm-apple.c
@@ -141,7 +141,7 @@ static int apple_pwm_probe(struct platform_device *pdev)
static const struct of_device_id apple_pwm_of_match[] = {
{ .compatible = "apple,s5l-fpwm" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, apple_pwm_of_match);
diff --git a/drivers/pwm/pwm-argon-fan-hat.c b/drivers/pwm/pwm-argon-fan-hat.c
index 2c59bd142d40..b480663e87d5 100644
--- a/drivers/pwm/pwm-argon-fan-hat.c
+++ b/drivers/pwm/pwm-argon-fan-hat.c
@@ -89,7 +89,7 @@ static int argon_fan_hat_i2c_probe(struct i2c_client *i2c)
static const struct of_device_id argon_fan_hat_dt_ids[] = {
{ .compatible = "argon40,fan-hat" },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, argon_fan_hat_dt_ids);
diff --git a/drivers/pwm/pwm-atmel-hlcdc.c b/drivers/pwm/pwm-atmel-hlcdc.c
index 387a0d1fa4f2..1ba2c9a049b9 100644
--- a/drivers/pwm/pwm-atmel-hlcdc.c
+++ b/drivers/pwm/pwm-atmel-hlcdc.c
@@ -217,23 +217,20 @@ static const struct of_device_id atmel_hlcdc_dt_ids[] = {
.compatible = "atmel,at91sam9n12-hlcdc",
/* 9n12 has same errata as 9x5 HLCDC PWM */
.data = &atmel_hlcdc_pwm_at91sam9x5_errata,
- },
- {
+ }, {
.compatible = "atmel,at91sam9x5-hlcdc",
.data = &atmel_hlcdc_pwm_at91sam9x5_errata,
- },
- {
+ }, {
.compatible = "atmel,sama5d2-hlcdc",
- },
- {
+ }, {
.compatible = "atmel,sama5d3-hlcdc",
.data = &atmel_hlcdc_pwm_sama5d3_errata,
- },
- {
+ }, {
.compatible = "atmel,sama5d4-hlcdc",
.data = &atmel_hlcdc_pwm_sama5d3_errata,
+ }, {
+ .compatible = "microchip,sam9x60-hlcdc",
},
- { .compatible = "microchip,sam9x60-hlcdc", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, atmel_hlcdc_dt_ids);
diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c
index a765ef279b51..f74a42d75b81 100644
--- a/drivers/pwm/pwm-atmel-tcb.c
+++ b/drivers/pwm/pwm-atmel-tcb.c
@@ -374,9 +374,9 @@ static struct atmel_tcb_config tcb_sama5d2_config = {
};
static const struct of_device_id atmel_tcb_of_match[] = {
- { .compatible = "atmel,at91rm9200-tcb", .data = &tcb_rm9200_config, },
- { .compatible = "atmel,at91sam9x5-tcb", .data = &tcb_sam9x5_config, },
- { .compatible = "atmel,sama5d2-tcb", .data = &tcb_sama5d2_config, },
+ { .compatible = "atmel,at91rm9200-tcb", .data = &tcb_rm9200_config },
+ { .compatible = "atmel,at91sam9x5-tcb", .data = &tcb_sam9x5_config },
+ { .compatible = "atmel,sama5d2-tcb", .data = &tcb_sama5d2_config },
{ /* sentinel */ }
};
diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c
index 06d22d0f7b26..86918523d821 100644
--- a/drivers/pwm/pwm-atmel.c
+++ b/drivers/pwm/pwm-atmel.c
@@ -441,9 +441,8 @@ static const struct of_device_id atmel_pwm_dt_ids[] = {
}, {
.compatible = "microchip,sam9x60-pwm",
.data = &mchp_sam9x60_pwm_data,
- }, {
- /* sentinel */
},
+ { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, atmel_pwm_dt_ids);
diff --git a/drivers/pwm/pwm-bcm-iproc.c b/drivers/pwm/pwm-bcm-iproc.c
index f4c9f10e490e..dc1e792b1e08 100644
--- a/drivers/pwm/pwm-bcm-iproc.c
+++ b/drivers/pwm/pwm-bcm-iproc.c
@@ -230,7 +230,7 @@ static int iproc_pwmc_probe(struct platform_device *pdev)
static const struct of_device_id bcm_iproc_pwmc_dt[] = {
{ .compatible = "brcm,iproc-pwm" },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, bcm_iproc_pwmc_dt);
diff --git a/drivers/pwm/pwm-bcm-kona.c b/drivers/pwm/pwm-bcm-kona.c
index 022c078aae84..ecfa3e3707f4 100644
--- a/drivers/pwm/pwm-bcm-kona.c
+++ b/drivers/pwm/pwm-bcm-kona.c
@@ -319,7 +319,7 @@ static int kona_pwmc_probe(struct platform_device *pdev)
static const struct of_device_id bcm_kona_pwmc_dt[] = {
{ .compatible = "brcm,kona-pwm" },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, bcm_kona_pwmc_dt);
diff --git a/drivers/pwm/pwm-bcm2835.c b/drivers/pwm/pwm-bcm2835.c
index 532903da521f..a4fbf9cfc6f7 100644
--- a/drivers/pwm/pwm-bcm2835.c
+++ b/drivers/pwm/pwm-bcm2835.c
@@ -165,7 +165,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(bcm2835_pwm_pm_ops, bcm2835_pwm_suspend,
bcm2835_pwm_resume);
static const struct of_device_id bcm2835_pwm_of_match[] = {
- { .compatible = "brcm,bcm2835-pwm", },
+ { .compatible = "brcm,bcm2835-pwm" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, bcm2835_pwm_of_match);
diff --git a/drivers/pwm/pwm-berlin.c b/drivers/pwm/pwm-berlin.c
index da9954818302..d36a245b6b4f 100644
--- a/drivers/pwm/pwm-berlin.c
+++ b/drivers/pwm/pwm-berlin.c
@@ -190,7 +190,7 @@ static const struct pwm_ops berlin_pwm_ops = {
static const struct of_device_id berlin_pwm_match[] = {
{ .compatible = "marvell,berlin-pwm" },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, berlin_pwm_match);
diff --git a/drivers/pwm/pwm-brcmstb.c b/drivers/pwm/pwm-brcmstb.c
index 82d27d07ba91..790ef7ffbbe5 100644
--- a/drivers/pwm/pwm-brcmstb.c
+++ b/drivers/pwm/pwm-brcmstb.c
@@ -222,7 +222,7 @@ static const struct pwm_ops brcmstb_pwm_ops = {
};
static const struct of_device_id brcmstb_pwm_of_match[] = {
- { .compatible = "brcm,bcm7038-pwm", },
+ { .compatible = "brcm,bcm7038-pwm" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, brcmstb_pwm_of_match);
diff --git a/drivers/pwm/pwm-clk.c b/drivers/pwm/pwm-clk.c
index f8f5af57acba..1907f2f10e5c 100644
--- a/drivers/pwm/pwm-clk.c
+++ b/drivers/pwm/pwm-clk.c
@@ -119,7 +119,7 @@ static void pwm_clk_remove(struct platform_device *pdev)
}
static const struct of_device_id pwm_clk_dt_ids[] = {
- { .compatible = "clk-pwm", },
+ { .compatible = "clk-pwm" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, pwm_clk_dt_ids);
diff --git a/drivers/pwm/pwm-clps711x.c b/drivers/pwm/pwm-clps711x.c
index 2c92ce754872..1ce12ee0329b 100644
--- a/drivers/pwm/pwm-clps711x.c
+++ b/drivers/pwm/pwm-clps711x.c
@@ -91,7 +91,7 @@ static int clps711x_pwm_probe(struct platform_device *pdev)
}
static const struct of_device_id clps711x_pwm_dt_ids[] = {
- { .compatible = "cirrus,ep7209-pwm", },
+ { .compatible = "cirrus,ep7209-pwm" },
{ }
};
MODULE_DEVICE_TABLE(of, clps711x_pwm_dt_ids);
diff --git a/drivers/pwm/pwm-cros-ec.c b/drivers/pwm/pwm-cros-ec.c
index 67cfa17f58e0..08a24a45c76d 100644
--- a/drivers/pwm/pwm-cros-ec.c
+++ b/drivers/pwm/pwm-cros-ec.c
@@ -267,7 +267,7 @@ static int cros_ec_pwm_probe(struct platform_device *pdev)
static const struct of_device_id cros_ec_pwm_of_match[] = {
{ .compatible = "google,cros-ec-pwm" },
{ .compatible = "google,cros-ec-pwm-type" },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, cros_ec_pwm_of_match);
#endif
diff --git a/drivers/pwm/pwm-hibvt.c b/drivers/pwm/pwm-hibvt.c
index e02ee6383dbc..29ad8d0b5536 100644
--- a/drivers/pwm/pwm-hibvt.c
+++ b/drivers/pwm/pwm-hibvt.c
@@ -266,7 +266,7 @@ static const struct of_device_id hibvt_pwm_of_match[] = {
.data = &hi3559v100_shub_soc_info },
{ .compatible = "hisilicon,hi3559v100-pwm",
.data = &hi3559v100_soc_info },
- { }
+ { }
};
MODULE_DEVICE_TABLE(of, hibvt_pwm_of_match);
diff --git a/drivers/pwm/pwm-imx-tpm.c b/drivers/pwm/pwm-imx-tpm.c
index 80fdb3303400..c20753a36d6d 100644
--- a/drivers/pwm/pwm-imx-tpm.c
+++ b/drivers/pwm/pwm-imx-tpm.c
@@ -442,7 +442,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(imx_tpm_pwm_pm,
pwm_imx_tpm_suspend, pwm_imx_tpm_resume);
static const struct of_device_id imx_tpm_pwm_dt_ids[] = {
- { .compatible = "fsl,imx7ulp-pwm", },
+ { .compatible = "fsl,imx7ulp-pwm" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, imx_tpm_pwm_dt_ids);
diff --git a/drivers/pwm/pwm-imx1.c b/drivers/pwm/pwm-imx1.c
index d5535d208005..075d46180dff 100644
--- a/drivers/pwm/pwm-imx1.c
+++ b/drivers/pwm/pwm-imx1.c
@@ -151,7 +151,7 @@ static const struct pwm_ops pwm_imx1_ops = {
};
static const struct of_device_id pwm_imx1_dt_ids[] = {
- { .compatible = "fsl,imx1-pwm", },
+ { .compatible = "fsl,imx1-pwm" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, pwm_imx1_dt_ids);
diff --git a/drivers/pwm/pwm-imx27.c b/drivers/pwm/pwm-imx27.c
index c8b801fcb525..7c1ad15008d2 100644
--- a/drivers/pwm/pwm-imx27.c
+++ b/drivers/pwm/pwm-imx27.c
@@ -378,7 +378,7 @@ static const struct pwm_ops pwm_imx27_ops = {
};
static const struct of_device_id pwm_imx27_dt_ids[] = {
- { .compatible = "fsl,imx27-pwm", },
+ { .compatible = "fsl,imx27-pwm" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, pwm_imx27_dt_ids);
diff --git a/drivers/pwm/pwm-ipq.c b/drivers/pwm/pwm-ipq.c
index c53373948136..6b7aec566f7e 100644
--- a/drivers/pwm/pwm-ipq.c
+++ b/drivers/pwm/pwm-ipq.c
@@ -245,8 +245,8 @@ static int ipq_pwm_probe(struct platform_device *pdev)
}
static const struct of_device_id pwm_ipq_dt_match[] = {
- { .compatible = "qcom,ipq6018-pwm", },
- {}
+ { .compatible = "qcom,ipq6018-pwm" },
+ { }
};
MODULE_DEVICE_TABLE(of, pwm_ipq_dt_match);
diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c
index e0b5966fc7fe..0db1474c7c8c 100644
--- a/drivers/pwm/pwm-jz4740.c
+++ b/drivers/pwm/pwm-jz4740.c
@@ -261,7 +261,7 @@ static const struct of_device_id jz4740_pwm_dt_ids[] = {
{ .compatible = "ingenic,jz4740-pwm", .data = &jz4740_soc_info },
{ .compatible = "ingenic,jz4725b-pwm", .data = &jz4725b_soc_info },
{ .compatible = "ingenic,x1000-pwm", .data = &x1000_soc_info },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, jz4740_pwm_dt_ids);
diff --git a/drivers/pwm/pwm-loongson.c b/drivers/pwm/pwm-loongson.c
index 31a57edecfd0..f2fb35b7af2b 100644
--- a/drivers/pwm/pwm-loongson.c
+++ b/drivers/pwm/pwm-loongson.c
@@ -269,7 +269,7 @@ static const struct of_device_id pwm_loongson_of_ids[] = {
MODULE_DEVICE_TABLE(of, pwm_loongson_of_ids);
static const struct acpi_device_id pwm_loongson_acpi_ids[] = {
- { "LOON0006" },
+ { .id = "LOON0006" },
{ }
};
MODULE_DEVICE_TABLE(acpi, pwm_loongson_acpi_ids);
diff --git a/drivers/pwm/pwm-lp3943.c b/drivers/pwm/pwm-lp3943.c
index 90b0733c00c1..10537e74be28 100644
--- a/drivers/pwm/pwm-lp3943.c
+++ b/drivers/pwm/pwm-lp3943.c
@@ -296,7 +296,7 @@ static int lp3943_pwm_probe(struct platform_device *pdev)
#ifdef CONFIG_OF
static const struct of_device_id lp3943_pwm_of_match[] = {
- { .compatible = "ti,lp3943-pwm", },
+ { .compatible = "ti,lp3943-pwm" },
{ }
};
MODULE_DEVICE_TABLE(of, lp3943_pwm_of_match);
diff --git a/drivers/pwm/pwm-lpc18xx-sct.c b/drivers/pwm/pwm-lpc18xx-sct.c
index 01d471725106..59e9b58a31bc 100644
--- a/drivers/pwm/pwm-lpc18xx-sct.c
+++ b/drivers/pwm/pwm-lpc18xx-sct.c
@@ -329,7 +329,7 @@ static const struct pwm_ops lpc18xx_pwm_ops = {
static const struct of_device_id lpc18xx_pwm_of_match[] = {
{ .compatible = "nxp,lpc1850-sct-pwm" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, lpc18xx_pwm_of_match);
diff --git a/drivers/pwm/pwm-lpc32xx.c b/drivers/pwm/pwm-lpc32xx.c
index c748537e57d1..19ec53648f40 100644
--- a/drivers/pwm/pwm-lpc32xx.c
+++ b/drivers/pwm/pwm-lpc32xx.c
@@ -155,7 +155,7 @@ static int lpc32xx_pwm_probe(struct platform_device *pdev)
}
static const struct of_device_id lpc32xx_pwm_dt_ids[] = {
- { .compatible = "nxp,lpc3220-pwm", },
+ { .compatible = "nxp,lpc3220-pwm" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, lpc32xx_pwm_dt_ids);
diff --git a/drivers/pwm/pwm-lpss-pci.c b/drivers/pwm/pwm-lpss-pci.c
index 3a0fd6593520..bcbfda1a6624 100644
--- a/drivers/pwm/pwm-lpss-pci.c
+++ b/drivers/pwm/pwm-lpss-pci.c
@@ -57,7 +57,7 @@ static const struct pci_device_id pwm_lpss_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x2289), .driver_data = (unsigned long)&pwm_lpss_bsw_info },
{ PCI_VDEVICE(INTEL, 0x31c8), .driver_data = (unsigned long)&pwm_lpss_bxt_info },
{ PCI_VDEVICE(INTEL, 0x5ac8), .driver_data = (unsigned long)&pwm_lpss_bxt_info },
- { },
+ { }
};
MODULE_DEVICE_TABLE(pci, pwm_lpss_pci_ids);
diff --git a/drivers/pwm/pwm-lpss-platform.c b/drivers/pwm/pwm-lpss-platform.c
index 8b95064b8703..489ca0c09c04 100644
--- a/drivers/pwm/pwm-lpss-platform.c
+++ b/drivers/pwm/pwm-lpss-platform.c
@@ -58,11 +58,11 @@ static int pwm_lpss_probe_platform(struct platform_device *pdev)
}
static const struct acpi_device_id pwm_lpss_acpi_match[] = {
- { "80860F09", (unsigned long)&pwm_lpss_byt_info },
- { "80862288", (unsigned long)&pwm_lpss_bsw_info },
- { "80862289", (unsigned long)&pwm_lpss_bsw_info },
- { "80865AC8", (unsigned long)&pwm_lpss_bxt_info },
- { },
+ { .id = "80860F09", .driver_data = (unsigned long)&pwm_lpss_byt_info },
+ { .id = "80862288", .driver_data = (unsigned long)&pwm_lpss_bsw_info },
+ { .id = "80862289", .driver_data = (unsigned long)&pwm_lpss_bsw_info },
+ { .id = "80865AC8", .driver_data = (unsigned long)&pwm_lpss_bxt_info },
+ { }
};
MODULE_DEVICE_TABLE(acpi, pwm_lpss_acpi_match);
diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c
index 992137a27750..0bb49be657b7 100644
--- a/drivers/pwm/pwm-mediatek.c
+++ b/drivers/pwm/pwm-mediatek.c
@@ -627,7 +627,7 @@ static const struct of_device_id pwm_mediatek_of_match[] = {
{ .compatible = "mediatek,mt8183-pwm", .data = &mt8183_pwm_data },
{ .compatible = "mediatek,mt8365-pwm", .data = &mt8365_pwm_data },
{ .compatible = "mediatek,mt8516-pwm", .data = &mt8516_pwm_data },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, pwm_mediatek_of_match);
diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c
index 8c6bf3d49753..20e6cd07127c 100644
--- a/drivers/pwm/pwm-meson.c
+++ b/drivers/pwm/pwm-meson.c
@@ -596,15 +596,14 @@ static const struct of_device_id meson_pwm_matches[] = {
{
.compatible = "amlogic,meson8-pwm-v2",
.data = &pwm_meson8_v2_data
- },
- {
+ }, {
.compatible = "amlogic,meson-axg-pwm-v2",
.data = &pwm_meson_axg_v2_data
- },
- {
+ }, {
.compatible = "amlogic,meson-g12-pwm-v2",
.data = &pwm_meson_axg_v2_data
},
+
/* The following compatibles are obsolete */
{
.compatible = "amlogic,meson8b-pwm",
@@ -642,7 +641,7 @@ static const struct of_device_id meson_pwm_matches[] = {
.compatible = "amlogic,meson-s4-pwm",
.data = &pwm_s4_data
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, meson_pwm_matches);
diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c
index bafd6b6195f6..b5409e15dac8 100644
--- a/drivers/pwm/pwm-mtk-disp.c
+++ b/drivers/pwm/pwm-mtk-disp.c
@@ -295,10 +295,10 @@ static const struct mtk_pwm_data mt8183_pwm_data = {
};
static const struct of_device_id mtk_disp_pwm_of_match[] = {
- { .compatible = "mediatek,mt2701-disp-pwm", .data = &mt2701_pwm_data},
- { .compatible = "mediatek,mt6595-disp-pwm", .data = &mt8173_pwm_data},
- { .compatible = "mediatek,mt8173-disp-pwm", .data = &mt8173_pwm_data},
- { .compatible = "mediatek,mt8183-disp-pwm", .data = &mt8183_pwm_data},
+ { .compatible = "mediatek,mt2701-disp-pwm", .data = &mt2701_pwm_data },
+ { .compatible = "mediatek,mt6595-disp-pwm", .data = &mt8173_pwm_data },
+ { .compatible = "mediatek,mt8173-disp-pwm", .data = &mt8173_pwm_data },
+ { .compatible = "mediatek,mt8183-disp-pwm", .data = &mt8183_pwm_data },
{ }
};
MODULE_DEVICE_TABLE(of, mtk_disp_pwm_of_match);
diff --git a/drivers/pwm/pwm-mxs.c b/drivers/pwm/pwm-mxs.c
index 8cad214b1c29..e1a3df6549fc 100644
--- a/drivers/pwm/pwm-mxs.c
+++ b/drivers/pwm/pwm-mxs.c
@@ -163,7 +163,7 @@ static int mxs_pwm_probe(struct platform_device *pdev)
}
static const struct of_device_id mxs_pwm_dt_ids[] = {
- { .compatible = "fsl,imx23-pwm", },
+ { .compatible = "fsl,imx23-pwm" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mxs_pwm_dt_ids);
diff --git a/drivers/pwm/pwm-omap-dmtimer.c b/drivers/pwm/pwm-omap-dmtimer.c
index 1858a77401f8..51830a87275c 100644
--- a/drivers/pwm/pwm-omap-dmtimer.c
+++ b/drivers/pwm/pwm-omap-dmtimer.c
@@ -444,8 +444,8 @@ static void pwm_omap_dmtimer_remove(struct platform_device *pdev)
}
static const struct of_device_id pwm_omap_dmtimer_of_match[] = {
- {.compatible = "ti,omap-dmtimer-pwm"},
- {}
+ { .compatible = "ti,omap-dmtimer-pwm" },
+ { }
};
MODULE_DEVICE_TABLE(of, pwm_omap_dmtimer_of_match);
diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index a02255a64ea8..a2792b803643 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -544,13 +544,13 @@ static const struct i2c_device_id pca9685_id[] = {
MODULE_DEVICE_TABLE(i2c, pca9685_id);
static const struct acpi_device_id pca9685_acpi_ids[] = {
- { "INT3492", 0 },
- { /* sentinel */ },
+ { .id = "INT3492" },
+ { /* sentinel */ }
};
MODULE_DEVICE_TABLE(acpi, pca9685_acpi_ids);
static const struct of_device_id pca9685_dt_ids[] = {
- { .compatible = "nxp,pca9685-pwm", },
+ { .compatible = "nxp,pca9685-pwm" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, pca9685_dt_ids);
diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c
index c206dbe9000e..5f06088f82d4 100644
--- a/drivers/pwm/pwm-pxa.c
+++ b/drivers/pwm/pwm-pxa.c
@@ -136,7 +136,6 @@ static const struct pwm_ops pxa_pwm_ops = {
.apply = pxa_pwm_apply,
};
-#ifdef CONFIG_OF
/*
* Device tree users must create one device instance for each PWM channel.
* Hence we dispense with the HAS_SECONDARY_PWM and "tell" the original driver
@@ -144,16 +143,13 @@ static const struct pwm_ops pxa_pwm_ops = {
* supported identically.
*/
static const struct of_device_id pwm_of_match[] = {
- { .compatible = "marvell,pxa250-pwm", .data = &pwm_id_table[0]},
- { .compatible = "marvell,pxa270-pwm", .data = &pwm_id_table[0]},
- { .compatible = "marvell,pxa168-pwm", .data = &pwm_id_table[0]},
- { .compatible = "marvell,pxa910-pwm", .data = &pwm_id_table[0]},
+ { .compatible = "marvell,pxa250-pwm", .data = &pwm_id_table[0] },
+ { .compatible = "marvell,pxa270-pwm", .data = &pwm_id_table[0] },
+ { .compatible = "marvell,pxa168-pwm", .data = &pwm_id_table[0] },
+ { .compatible = "marvell,pxa910-pwm", .data = &pwm_id_table[0] },
{ }
};
MODULE_DEVICE_TABLE(of, pwm_of_match);
-#else
-#define pwm_of_match NULL
-#endif
static int pwm_probe(struct platform_device *pdev)
{
@@ -165,7 +161,7 @@ static int pwm_probe(struct platform_device *pdev)
struct reset_control *rst;
int ret = 0;
- if (IS_ENABLED(CONFIG_OF) && id == NULL)
+ if (id == NULL)
id = of_device_get_match_data(dev);
if (id == NULL)
@@ -191,9 +187,7 @@ static int pwm_probe(struct platform_device *pdev)
return PTR_ERR(rst);
chip->ops = &pxa_pwm_ops;
-
- if (IS_ENABLED(CONFIG_OF))
- chip->of_xlate = of_pwm_single_xlate;
+ chip->of_xlate = of_pwm_single_xlate;
pc->mmio_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(pc->mmio_base))
diff --git a/drivers/pwm/pwm-raspberrypi-poe.c b/drivers/pwm/pwm-raspberrypi-poe.c
index 8921e7ea2cea..7cea6561c730 100644
--- a/drivers/pwm/pwm-raspberrypi-poe.c
+++ b/drivers/pwm/pwm-raspberrypi-poe.c
@@ -177,7 +177,7 @@ static int raspberrypi_pwm_probe(struct platform_device *pdev)
}
static const struct of_device_id raspberrypi_pwm_of_match[] = {
- { .compatible = "raspberrypi,firmware-poe-pwm", },
+ { .compatible = "raspberrypi,firmware-poe-pwm" },
{ }
};
MODULE_DEVICE_TABLE(of, raspberrypi_pwm_of_match);
diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c
index 578dbdd2d5a7..1733cd700693 100644
--- a/drivers/pwm/pwm-rcar.c
+++ b/drivers/pwm/pwm-rcar.c
@@ -248,8 +248,8 @@ static void rcar_pwm_remove(struct platform_device *pdev)
}
static const struct of_device_id rcar_pwm_of_table[] = {
- { .compatible = "renesas,pwm-rcar", },
- { },
+ { .compatible = "renesas,pwm-rcar" },
+ { }
};
MODULE_DEVICE_TABLE(of, rcar_pwm_of_table);
diff --git a/drivers/pwm/pwm-renesas-tpu.c b/drivers/pwm/pwm-renesas-tpu.c
index 2196080b4177..140fd0bcb93f 100644
--- a/drivers/pwm/pwm-renesas-tpu.c
+++ b/drivers/pwm/pwm-renesas-tpu.c
@@ -479,11 +479,11 @@ static int tpu_probe(struct platform_device *pdev)
#ifdef CONFIG_OF
static const struct of_device_id tpu_of_table[] = {
- { .compatible = "renesas,tpu-r8a73a4", },
- { .compatible = "renesas,tpu-r8a7740", },
- { .compatible = "renesas,tpu-r8a7790", },
- { .compatible = "renesas,tpu", },
- { },
+ { .compatible = "renesas,tpu-r8a73a4" },
+ { .compatible = "renesas,tpu-r8a7740" },
+ { .compatible = "renesas,tpu-r8a7790" },
+ { .compatible = "renesas,tpu" },
+ { }
};
MODULE_DEVICE_TABLE(of, tpu_of_table);
diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c
index 67b85bdb491b..050ca8aad0ca 100644
--- a/drivers/pwm/pwm-rockchip.c
+++ b/drivers/pwm/pwm-rockchip.c
@@ -292,10 +292,10 @@ static const struct rockchip_pwm_data pwm_data_v3 = {
};
static const struct of_device_id rockchip_pwm_dt_ids[] = {
- { .compatible = "rockchip,rk2928-pwm", .data = &pwm_data_v1},
- { .compatible = "rockchip,rk3288-pwm", .data = &pwm_data_v2},
- { .compatible = "rockchip,vop-pwm", .data = &pwm_data_vop},
- { .compatible = "rockchip,rk3328-pwm", .data = &pwm_data_v3},
+ { .compatible = "rockchip,rk2928-pwm", .data = &pwm_data_v1 },
+ { .compatible = "rockchip,rk3288-pwm", .data = &pwm_data_v2 },
+ { .compatible = "rockchip,vop-pwm", .data = &pwm_data_vop },
+ { .compatible = "rockchip,rk3328-pwm", .data = &pwm_data_v3 },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, rockchip_pwm_dt_ids);
diff --git a/drivers/pwm/pwm-rzg2l-gpt.c b/drivers/pwm/pwm-rzg2l-gpt.c
index dfa1d11a48a8..ac8399b96ad1 100644
--- a/drivers/pwm/pwm-rzg2l-gpt.c
+++ b/drivers/pwm/pwm-rzg2l-gpt.c
@@ -437,7 +437,7 @@ static int rzg2l_gpt_probe(struct platform_device *pdev)
}
static const struct of_device_id rzg2l_gpt_of_table[] = {
- { .compatible = "renesas,rzg2l-gpt", },
+ { .compatible = "renesas,rzg2l-gpt" },
{ /* Sentinel */ }
};
MODULE_DEVICE_TABLE(of, rzg2l_gpt_of_table);
diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c
index 951b38ff5f8e..331e81f1594a 100644
--- a/drivers/pwm/pwm-samsung.c
+++ b/drivers/pwm/pwm-samsung.c
@@ -501,7 +501,7 @@ static const struct of_device_id samsung_pwm_matches[] = {
{ .compatible = "samsung,s5p6440-pwm", .data = &s5p64x0_variant },
{ .compatible = "samsung,s5pc100-pwm", .data = &s5pc100_variant },
{ .compatible = "samsung,exynos4210-pwm", .data = &s5p64x0_variant },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, samsung_pwm_matches);
diff --git a/drivers/pwm/pwm-sifive.c b/drivers/pwm/pwm-sifive.c
index e11ecf1fa0f9..4d0e4512d8a5 100644
--- a/drivers/pwm/pwm-sifive.c
+++ b/drivers/pwm/pwm-sifive.c
@@ -355,7 +355,7 @@ static void pwm_sifive_remove(struct platform_device *dev)
static const struct of_device_id pwm_sifive_of_match[] = {
{ .compatible = "sifive,pwm0" },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, pwm_sifive_of_match);
diff --git a/drivers/pwm/pwm-sl28cpld.c b/drivers/pwm/pwm-sl28cpld.c
index 0dc2e3f809c3..0e25a05ea538 100644
--- a/drivers/pwm/pwm-sl28cpld.c
+++ b/drivers/pwm/pwm-sl28cpld.c
@@ -244,7 +244,7 @@ static int sl28cpld_pwm_probe(struct platform_device *pdev)
static const struct of_device_id sl28cpld_pwm_of_match[] = {
{ .compatible = "kontron,sl28cpld-pwm" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, sl28cpld_pwm_of_match);
diff --git a/drivers/pwm/pwm-sophgo-sg2042.c b/drivers/pwm/pwm-sophgo-sg2042.c
index 7d07b0ca7d29..0b6461172e6a 100644
--- a/drivers/pwm/pwm-sophgo-sg2042.c
+++ b/drivers/pwm/pwm-sophgo-sg2042.c
@@ -225,11 +225,10 @@ static const struct sg2042_chip_data sg2044_chip_data = {
static const struct of_device_id sg2042_pwm_ids[] = {
{
.compatible = "sophgo,sg2042-pwm",
- .data = &sg2042_chip_data
- },
- {
+ .data = &sg2042_chip_data,
+ }, {
.compatible = "sophgo,sg2044-pwm",
- .data = &sg2044_chip_data
+ .data = &sg2044_chip_data,
},
{ }
};
diff --git a/drivers/pwm/pwm-sprd.c b/drivers/pwm/pwm-sprd.c
index 438dbaa3a98f..51cab6a54fe2 100644
--- a/drivers/pwm/pwm-sprd.c
+++ b/drivers/pwm/pwm-sprd.c
@@ -276,8 +276,8 @@ static int sprd_pwm_probe(struct platform_device *pdev)
}
static const struct of_device_id sprd_pwm_of_match[] = {
- { .compatible = "sprd,ums512-pwm", },
- { },
+ { .compatible = "sprd,ums512-pwm" },
+ { }
};
MODULE_DEVICE_TABLE(of, sprd_pwm_of_match);
diff --git a/drivers/pwm/pwm-sti.c b/drivers/pwm/pwm-sti.c
index 3b702b8f0c7f..e5c3cf594571 100644
--- a/drivers/pwm/pwm-sti.c
+++ b/drivers/pwm/pwm-sti.c
@@ -625,7 +625,7 @@ static int sti_pwm_probe(struct platform_device *pdev)
}
static const struct of_device_id sti_pwm_of_match[] = {
- { .compatible = "st,sti-pwm", },
+ { .compatible = "st,sti-pwm" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sti_pwm_of_match);
diff --git a/drivers/pwm/pwm-stm32-lp.c b/drivers/pwm/pwm-stm32-lp.c
index 4789eafb8bac..2aa88f4985f5 100644
--- a/drivers/pwm/pwm-stm32-lp.c
+++ b/drivers/pwm/pwm-stm32-lp.c
@@ -412,8 +412,8 @@ static DEFINE_SIMPLE_DEV_PM_OPS(stm32_pwm_lp_pm_ops, stm32_pwm_lp_suspend,
stm32_pwm_lp_resume);
static const struct of_device_id stm32_pwm_lp_of_match[] = {
- { .compatible = "st,stm32-pwm-lp", },
- {},
+ { .compatible = "st,stm32-pwm-lp" },
+ { }
};
MODULE_DEVICE_TABLE(of, stm32_pwm_lp_of_match);
diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c
index c708e4a7ad70..ea5a51a2800f 100644
--- a/drivers/pwm/pwm-stm32.c
+++ b/drivers/pwm/pwm-stm32.c
@@ -918,9 +918,9 @@ static int stm32_pwm_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(stm32_pwm_pm_ops, stm32_pwm_suspend, stm32_pwm_resume);
static const struct of_device_id stm32_pwm_of_match[] = {
- { .compatible = "st,stm32-pwm", },
- { .compatible = "st,stm32mp25-pwm", },
- { /* end node */ },
+ { .compatible = "st,stm32-pwm" },
+ { .compatible = "st,stm32mp25-pwm" },
+ { /* end node */ }
};
MODULE_DEVICE_TABLE(of, stm32_pwm_of_match);
diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c
index 6c5591ca868b..0752152b1470 100644
--- a/drivers/pwm/pwm-sun4i.c
+++ b/drivers/pwm/pwm-sun4i.c
@@ -369,7 +369,7 @@ static const struct of_device_id sun4i_pwm_dt_ids[] = {
.data = &sun50i_h6_pwm_data,
}, {
/* sentinel */
- },
+ }
};
MODULE_DEVICE_TABLE(of, sun4i_pwm_dt_ids);
diff --git a/drivers/pwm/pwm-sunplus.c b/drivers/pwm/pwm-sunplus.c
index cc8137f108df..4c4a4b0f5f18 100644
--- a/drivers/pwm/pwm-sunplus.c
+++ b/drivers/pwm/pwm-sunplus.c
@@ -213,8 +213,8 @@ static int sunplus_pwm_probe(struct platform_device *pdev)
}
static const struct of_device_id sunplus_pwm_of_match[] = {
- { .compatible = "sunplus,sp7021-pwm", },
- {}
+ { .compatible = "sunplus,sp7021-pwm" },
+ { }
};
MODULE_DEVICE_TABLE(of, sunplus_pwm_of_match);
diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c
index 67cc5e8bdb0e..3751737ead43 100644
--- a/drivers/pwm/pwm-tiecap.c
+++ b/drivers/pwm/pwm-tiecap.c
@@ -211,9 +211,9 @@ static const struct pwm_ops ecap_pwm_ops = {
};
static const struct of_device_id ecap_of_match[] = {
- { .compatible = "ti,am3352-ecap" },
- { .compatible = "ti,am33xx-ecap" },
- {},
+ { .compatible = "ti,am3352-ecap" },
+ { .compatible = "ti,am33xx-ecap" },
+ { }
};
MODULE_DEVICE_TABLE(of, ecap_of_match);
diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c
index 2533c95b0ba9..3a53489f0b98 100644
--- a/drivers/pwm/pwm-tiehrpwm.c
+++ b/drivers/pwm/pwm-tiehrpwm.c
@@ -407,7 +407,7 @@ static const struct pwm_ops ehrpwm_pwm_ops = {
static const struct of_device_id ehrpwm_of_match[] = {
{ .compatible = "ti,am3352-ehrpwm" },
{ .compatible = "ti,am33xx-ehrpwm" },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, ehrpwm_of_match);
diff --git a/drivers/pwm/pwm-twl-led.c b/drivers/pwm/pwm-twl-led.c
index a555cc3be4b3..e1b6871af81e 100644
--- a/drivers/pwm/pwm-twl-led.c
+++ b/drivers/pwm/pwm-twl-led.c
@@ -338,7 +338,7 @@ static int twl_pwmled_probe(struct platform_device *pdev)
static const struct of_device_id twl_pwmled_of_match[] = {
{ .compatible = "ti,twl4030-pwmled" },
{ .compatible = "ti,twl6030-pwmled" },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, twl_pwmled_of_match);
#endif
diff --git a/drivers/pwm/pwm-twl.c b/drivers/pwm/pwm-twl.c
index 8f981ffff4b4..99c1caf4f19c 100644
--- a/drivers/pwm/pwm-twl.c
+++ b/drivers/pwm/pwm-twl.c
@@ -362,7 +362,7 @@ static int twl_pwm_probe(struct platform_device *pdev)
static const struct of_device_id twl_pwm_of_match[] = {
{ .compatible = "ti,twl4030-pwm" },
{ .compatible = "ti,twl6030-pwm" },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, twl_pwm_of_match);
#endif
diff --git a/drivers/pwm/pwm-visconti.c b/drivers/pwm/pwm-visconti.c
index 28fae4979e3f..830aef483bd0 100644
--- a/drivers/pwm/pwm-visconti.c
+++ b/drivers/pwm/pwm-visconti.c
@@ -156,7 +156,7 @@ static int visconti_pwm_probe(struct platform_device *pdev)
}
static const struct of_device_id visconti_pwm_of_match[] = {
- { .compatible = "toshiba,visconti-pwm", },
+ { .compatible = "toshiba,visconti-pwm" },
{ }
};
MODULE_DEVICE_TABLE(of, visconti_pwm_of_match);
diff --git a/drivers/pwm/pwm-vt8500.c b/drivers/pwm/pwm-vt8500.c
index 149d9e35b78c..8013e31b1147 100644
--- a/drivers/pwm/pwm-vt8500.c
+++ b/drivers/pwm/pwm-vt8500.c
@@ -226,7 +226,7 @@ static const struct pwm_ops vt8500_pwm_ops = {
};
static const struct of_device_id vt8500_pwm_dt_ids[] = {
- { .compatible = "via,vt8500-pwm", },
+ { .compatible = "via,vt8500-pwm" },
{ /* Sentinel */ }
};
MODULE_DEVICE_TABLE(of, vt8500_pwm_dt_ids);
diff --git a/drivers/pwm/pwm-xilinx.c b/drivers/pwm/pwm-xilinx.c
index 52c241982807..fa2d10e658dd 100644
--- a/drivers/pwm/pwm-xilinx.c
+++ b/drivers/pwm/pwm-xilinx.c
@@ -281,8 +281,8 @@ static int xilinx_pwm_probe(struct platform_device *pdev)
}
static const struct of_device_id xilinx_pwm_of_match[] = {
- { .compatible = "xlnx,xps-timer-1.00.a", },
- {},
+ { .compatible = "xlnx,xps-timer-1.00.a" },
+ { }
};
MODULE_DEVICE_TABLE(of, xilinx_pwm_of_match);
diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c
index dcd6619a4b02..3cc25d053451 100644
--- a/drivers/rapidio/rio-scan.c
+++ b/drivers/rapidio/rio-scan.c
@@ -874,6 +874,7 @@ static struct rio_net *rio_scan_alloc_net(struct rio_mport *mport,
net->dev.release = rio_scan_release_dev;
if (rio_add_net(net)) {
put_device(&net->dev);
+ mport->net = NULL;
net = NULL;
}
}
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index dc5d67767336..1797929dfe56 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -248,7 +248,7 @@ static void regulator_lock_two(struct regulator_dev *rdev1,
ret = regulator_lock_nested(rdev1, ww_ctx);
WARN_ON(ret);
ret = regulator_lock_nested(rdev2, ww_ctx);
- if (ret != -EDEADLOCK) {
+ if (ret != -EDEADLK) {
WARN_ON(ret);
goto exit;
}
@@ -264,7 +264,7 @@ static void regulator_lock_two(struct regulator_dev *rdev1,
swap(held, contended);
ret = regulator_lock_nested(contended, ww_ctx);
- if (ret != -EDEADLOCK) {
+ if (ret != -EDEADLK) {
WARN_ON(ret);
break;
}
diff --git a/drivers/regulator/db8500-prcmu.c b/drivers/regulator/db8500-prcmu.c
index 1ec2e1348891..751fe36580fa 100644
--- a/drivers/regulator/db8500-prcmu.c
+++ b/drivers/regulator/db8500-prcmu.c
@@ -13,7 +13,7 @@
#include <linux/err.h>
#include <linux/spinlock.h>
#include <linux/platform_device.h>
-#include <linux/mfd/dbx500-prcmu.h>
+#include <linux/mfd/db8500-prcmu.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/db8500-prcmu.h>
@@ -93,13 +93,13 @@ static int enable_epod(u16 epod_id, bool ramret)
if (ramret) {
if (!epod_on[epod_id]) {
- ret = prcmu_set_epod(epod_id, EPOD_STATE_RAMRET);
+ ret = db8500_prcmu_set_epod(epod_id, EPOD_STATE_RAMRET);
if (ret < 0)
return ret;
}
epod_ramret[epod_id] = true;
} else {
- ret = prcmu_set_epod(epod_id, EPOD_STATE_ON);
+ ret = db8500_prcmu_set_epod(epod_id, EPOD_STATE_ON);
if (ret < 0)
return ret;
epod_on[epod_id] = true;
@@ -114,18 +114,18 @@ static int disable_epod(u16 epod_id, bool ramret)
if (ramret) {
if (!epod_on[epod_id]) {
- ret = prcmu_set_epod(epod_id, EPOD_STATE_OFF);
+ ret = db8500_prcmu_set_epod(epod_id, EPOD_STATE_OFF);
if (ret < 0)
return ret;
}
epod_ramret[epod_id] = false;
} else {
if (epod_ramret[epod_id]) {
- ret = prcmu_set_epod(epod_id, EPOD_STATE_RAMRET);
+ ret = db8500_prcmu_set_epod(epod_id, EPOD_STATE_RAMRET);
if (ret < 0)
return ret;
} else {
- ret = prcmu_set_epod(epod_id, EPOD_STATE_OFF);
+ ret = db8500_prcmu_set_epod(epod_id, EPOD_STATE_OFF);
if (ret < 0)
return ret;
}
diff --git a/drivers/regulator/mt6316-regulator.c b/drivers/regulator/mt6316-regulator.c
index 952852bbe923..b170506eec57 100644
--- a/drivers/regulator/mt6316-regulator.c
+++ b/drivers/regulator/mt6316-regulator.c
@@ -329,6 +329,7 @@ static const struct of_device_id mt6316_regulator_match[] = {
{ .compatible = "mediatek,mt6316d-regulator", .data = (void *)MT6316_TYPE_4PHASE },
{ /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, mt6316_regulator_match);
static struct spmi_driver mt6316_regulator_driver = {
.driver = {
diff --git a/drivers/regulator/mt6363-regulator.c b/drivers/regulator/mt6363-regulator.c
index 0aebcbda0a19..aa6a8eb7ac4b 100644
--- a/drivers/regulator/mt6363-regulator.c
+++ b/drivers/regulator/mt6363-regulator.c
@@ -927,6 +927,7 @@ static const struct of_device_id mt6363_regulator_match[] = {
{ .compatible = "mediatek,mt6363-regulator" },
{ /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, mt6363_regulator_match);
static struct platform_driver mt6363_regulator_driver = {
.driver = {
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index c521c744e7db..65befdbfa5f7 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -210,6 +210,7 @@ config QCOM_Q6V5_MSS
select QCOM_Q6V5_COMMON
select QCOM_RPROC_COMMON
select QCOM_SCM
+ select QCOM_PAS
help
Say y here to support the Qualcomm self-authenticating modem
subsystem based on Hexagon V5. The TrustZone based system is
@@ -230,6 +231,7 @@ config QCOM_Q6V5_PAS
select QCOM_Q6V5_COMMON
select QCOM_RPROC_COMMON
select QCOM_SCM
+ select QCOM_PAS
help
Say y here to support the TrustZone based Peripheral Image Loader for
the Qualcomm remote processors. This is commonly used to control
@@ -282,7 +284,7 @@ config QCOM_WCNSS_PIL
select QCOM_MDT_LOADER
select QCOM_PIL_INFO
select QCOM_RPROC_COMMON
- select QCOM_SCM
+ select QCOM_PAS
help
Say y here to support the Peripheral Image Loader for loading WCNSS
firmware and boot the core on e.g. MSM8974, MSM8916. The firmware is
diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c
index 85a74c9ec521..436656bdfa8b 100644
--- a/drivers/remoteproc/mtk_scp.c
+++ b/drivers/remoteproc/mtk_scp.c
@@ -36,6 +36,7 @@ struct mtk_scp *scp_get(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct device_node *scp_node;
struct platform_device *scp_pdev;
+ struct mtk_scp *scp;
scp_node = of_parse_phandle(dev->of_node, "mediatek,scp", 0);
if (!scp_node) {
@@ -51,7 +52,13 @@ struct mtk_scp *scp_get(struct platform_device *pdev)
return NULL;
}
- return platform_get_drvdata(scp_pdev);
+ scp = platform_get_drvdata(scp_pdev);
+ if (!scp) {
+ put_device(&scp_pdev->dev);
+ return NULL;
+ }
+
+ return scp;
}
EXPORT_SYMBOL_GPL(scp_get);
diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c
index ae78f5c7c1b6..96888007faa8 100644
--- a/drivers/remoteproc/qcom_q6v5_mss.c
+++ b/drivers/remoteproc/qcom_q6v5_mss.c
@@ -34,6 +34,7 @@
#include "qcom_pil_info.h"
#include "qcom_q6v5.h"
+#include <linux/firmware/qcom/qcom_pas.h>
#include <linux/firmware/qcom/qcom_scm.h>
#define MPSS_CRASH_REASON_SMEM 421
@@ -1480,7 +1481,7 @@ static int q6v5_mpss_load(struct q6v5 *qproc)
}
if (qproc->need_pas_mem_setup) {
- ret = qcom_scm_pas_mem_setup(MPSS_PAS_ID, qproc->mpss_phys, qproc->mpss_size);
+ ret = qcom_pas_mem_setup(MPSS_PAS_ID, qproc->mpss_phys, qproc->mpss_size);
if (ret) {
dev_err(qproc->dev,
"setting up mpss memory failed: %d\n", ret);
@@ -2077,7 +2078,7 @@ static int q6v5_probe(struct platform_device *pdev)
if (!desc)
return -EINVAL;
- if (desc->need_mem_protection && !qcom_scm_is_available())
+ if (desc->need_mem_protection && !qcom_pas_is_available())
return -EPROBE_DEFER;
mba_image = desc->hexagon_mba_image;
diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
index 60a4337d9e51..4862c679cbe5 100644
--- a/drivers/remoteproc/qcom_q6v5_pas.c
+++ b/drivers/remoteproc/qcom_q6v5_pas.c
@@ -20,6 +20,7 @@
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
+#include <linux/firmware/qcom/qcom_pas.h>
#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/regulator/consumer.h>
#include <linux/remoteproc.h>
@@ -116,8 +117,8 @@ struct qcom_pas {
struct qcom_rproc_ssr ssr_subdev;
struct qcom_sysmon *sysmon;
- struct qcom_scm_pas_context *pas_ctx;
- struct qcom_scm_pas_context *dtb_pas_ctx;
+ struct qcom_pas_context *pas_ctx;
+ struct qcom_pas_context *dtb_pas_ctx;
};
static void qcom_pas_segment_dump(struct rproc *rproc,
@@ -194,7 +195,7 @@ static int qcom_pas_shutdown_poll_decrypt(struct qcom_pas *pas)
do {
msleep(QCOM_PAS_DECRYPT_SHUTDOWN_DELAY_MS);
- ret = qcom_scm_pas_shutdown(pas->pas_id);
+ ret = qcom_pas_shutdown(pas->pas_id);
} while (ret == -EINVAL && --retry_num);
return ret;
@@ -210,9 +211,9 @@ static int qcom_pas_unprepare(struct rproc *rproc)
* auth_and_reset() was successful, but in other cases clean it up
* here.
*/
- qcom_scm_pas_metadata_release(pas->pas_ctx);
+ qcom_pas_metadata_release(pas->pas_ctx);
if (pas->dtb_pas_id)
- qcom_scm_pas_metadata_release(pas->dtb_pas_ctx);
+ qcom_pas_metadata_release(pas->dtb_pas_ctx);
return 0;
}
@@ -226,9 +227,9 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw)
pas->firmware = fw;
if (pas->lite_pas_id)
- qcom_scm_pas_shutdown(pas->lite_pas_id);
+ qcom_pas_shutdown(pas->lite_pas_id);
if (pas->lite_dtb_pas_id)
- qcom_scm_pas_shutdown(pas->lite_dtb_pas_id);
+ qcom_pas_shutdown(pas->lite_dtb_pas_id);
if (pas->dtb_pas_id) {
ret = request_firmware(&pas->dtb_firmware, pas->dtb_firmware_name, pas->dev);
@@ -248,7 +249,7 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw)
return 0;
release_dtb_metadata:
- qcom_scm_pas_metadata_release(pas->dtb_pas_ctx);
+ qcom_pas_metadata_release(pas->dtb_pas_ctx);
release_firmware(pas->dtb_firmware);
return ret;
@@ -308,7 +309,7 @@ static int qcom_pas_start(struct rproc *rproc)
if (ret)
goto disable_px_supply;
- ret = qcom_scm_pas_prepare_and_auth_reset(pas->dtb_pas_ctx);
+ ret = qcom_pas_prepare_and_auth_reset(pas->dtb_pas_ctx);
if (ret) {
dev_err(pas->dev,
"failed to authenticate dtb image and release reset\n");
@@ -327,7 +328,7 @@ static int qcom_pas_start(struct rproc *rproc)
if (ret)
goto release_pas_metadata;
- ret = qcom_scm_pas_prepare_and_auth_reset(pas->pas_ctx);
+ ret = qcom_pas_prepare_and_auth_reset(pas->pas_ctx);
if (ret) {
dev_err(pas->dev,
"failed to authenticate image and release reset\n");
@@ -337,13 +338,13 @@ static int qcom_pas_start(struct rproc *rproc)
ret = qcom_q6v5_wait_for_start(&pas->q6v5, msecs_to_jiffies(5000));
if (ret == -ETIMEDOUT) {
dev_err(pas->dev, "start timed out\n");
- qcom_scm_pas_shutdown(pas->pas_id);
+ qcom_pas_shutdown(pas->pas_id);
goto unmap_carveout;
}
- qcom_scm_pas_metadata_release(pas->pas_ctx);
+ qcom_pas_metadata_release(pas->pas_ctx);
if (pas->dtb_pas_id)
- qcom_scm_pas_metadata_release(pas->dtb_pas_ctx);
+ qcom_pas_metadata_release(pas->dtb_pas_ctx);
/* firmware is used to pass reference from qcom_pas_start(), drop it now */
pas->firmware = NULL;
@@ -353,9 +354,9 @@ static int qcom_pas_start(struct rproc *rproc)
unmap_carveout:
qcom_pas_unmap_carveout(rproc, pas->mem_phys, pas->mem_size);
release_pas_metadata:
- qcom_scm_pas_metadata_release(pas->pas_ctx);
+ qcom_pas_metadata_release(pas->pas_ctx);
if (pas->dtb_pas_id)
- qcom_scm_pas_metadata_release(pas->dtb_pas_ctx);
+ qcom_pas_metadata_release(pas->dtb_pas_ctx);
unmap_dtb_carveout:
if (pas->dtb_pas_id)
@@ -404,7 +405,7 @@ static int qcom_pas_stop(struct rproc *rproc)
if (ret == -ETIMEDOUT)
dev_err(pas->dev, "timed out on wait\n");
- ret = qcom_scm_pas_shutdown(pas->pas_id);
+ ret = qcom_pas_shutdown(pas->pas_id);
if (ret && pas->decrypt_shutdown)
ret = qcom_pas_shutdown_poll_decrypt(pas);
@@ -412,7 +413,7 @@ static int qcom_pas_stop(struct rproc *rproc)
dev_err(pas->dev, "failed to shutdown: %d\n", ret);
if (pas->dtb_pas_id) {
- ret = qcom_scm_pas_shutdown(pas->dtb_pas_id);
+ ret = qcom_pas_shutdown(pas->dtb_pas_id);
if (ret)
dev_err(pas->dev, "failed to shutdown dtb: %d\n", ret);
@@ -482,11 +483,11 @@ static int qcom_pas_parse_firmware(struct rproc *rproc, const struct firmware *f
*
* Here, we call rproc_elf_load_rsc_table() to check firmware binary has resources
* or not and if it is not having then we pass NULL and zero as input resource
- * table pointer and size respectively to the argument of qcom_scm_pas_get_rsc_table()
+ * table pointer and size respectively to the argument of qcom_pas_get_rsc_table()
* and this is even true for Qualcomm remote processor who does follow remoteproc
* framework.
*/
- output_rt = qcom_scm_pas_get_rsc_table(pas->pas_ctx, table, table_sz, &output_rt_size);
+ output_rt = qcom_pas_get_rsc_table(pas->pas_ctx, table, table_sz, &output_rt_size);
ret = IS_ERR(output_rt) ? PTR_ERR(output_rt) : 0;
if (ret) {
dev_err(pas->dev, "Error in getting resource table: %d\n", ret);
@@ -807,7 +808,7 @@ static int qcom_pas_probe(struct platform_device *pdev)
if (!desc)
return -EINVAL;
- if (!qcom_scm_is_available())
+ if (!qcom_pas_is_available())
return -EPROBE_DEFER;
fw_name = desc->firmware_name;
@@ -899,16 +900,16 @@ static int qcom_pas_probe(struct platform_device *pdev)
qcom_add_ssr_subdev(rproc, &pas->ssr_subdev, desc->ssr_name);
- pas->pas_ctx = devm_qcom_scm_pas_context_alloc(pas->dev, pas->pas_id,
- pas->mem_phys, pas->mem_size);
+ pas->pas_ctx = devm_qcom_pas_context_alloc(pas->dev, pas->pas_id,
+ pas->mem_phys, pas->mem_size);
if (IS_ERR(pas->pas_ctx)) {
ret = PTR_ERR(pas->pas_ctx);
goto remove_ssr_sysmon;
}
- pas->dtb_pas_ctx = devm_qcom_scm_pas_context_alloc(pas->dev, pas->dtb_pas_id,
- pas->dtb_mem_phys,
- pas->dtb_mem_size);
+ pas->dtb_pas_ctx = devm_qcom_pas_context_alloc(pas->dev, pas->dtb_pas_id,
+ pas->dtb_mem_phys,
+ pas->dtb_mem_size);
if (IS_ERR(pas->dtb_pas_ctx)) {
ret = PTR_ERR(pas->dtb_pas_ctx);
goto remove_ssr_sysmon;
diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
index 4add9037dbd5..0dbdd18ab3dd 100644
--- a/drivers/remoteproc/qcom_wcnss.c
+++ b/drivers/remoteproc/qcom_wcnss.c
@@ -19,7 +19,7 @@
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
-#include <linux/firmware/qcom/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_pas.h>
#include <linux/regulator/consumer.h>
#include <linux/remoteproc.h>
#include <linux/soc/qcom/mdt_loader.h>
@@ -257,7 +257,7 @@ static int wcnss_start(struct rproc *rproc)
wcnss_indicate_nv_download(wcnss);
wcnss_configure_iris(wcnss);
- ret = qcom_scm_pas_auth_and_reset(WCNSS_PAS_ID);
+ ret = qcom_pas_auth_and_reset(WCNSS_PAS_ID);
if (ret) {
dev_err(wcnss->dev,
"failed to authenticate image and release reset\n");
@@ -269,7 +269,7 @@ static int wcnss_start(struct rproc *rproc)
if (wcnss->ready_irq > 0 && ret == 0) {
/* We have a ready_irq, but it didn't fire in time. */
dev_err(wcnss->dev, "start timed out\n");
- qcom_scm_pas_shutdown(WCNSS_PAS_ID);
+ qcom_pas_shutdown(WCNSS_PAS_ID);
ret = -ETIMEDOUT;
goto disable_iris;
}
@@ -311,7 +311,7 @@ static int wcnss_stop(struct rproc *rproc)
0);
}
- ret = qcom_scm_pas_shutdown(WCNSS_PAS_ID);
+ ret = qcom_pas_shutdown(WCNSS_PAS_ID);
if (ret)
dev_err(wcnss->dev, "failed to shutdown: %d\n", ret);
@@ -557,10 +557,10 @@ static int wcnss_probe(struct platform_device *pdev)
data = of_device_get_match_data(&pdev->dev);
- if (!qcom_scm_is_available())
+ if (!qcom_pas_is_available())
return -EPROBE_DEFER;
- if (!qcom_scm_pas_supported(WCNSS_PAS_ID)) {
+ if (!qcom_pas_supported(WCNSS_PAS_ID)) {
dev_err(&pdev->dev, "PAS is not available for WCNSS\n");
return -ENXIO;
}
diff --git a/drivers/remoteproc/ti_k3_r5_remoteproc.c b/drivers/remoteproc/ti_k3_r5_remoteproc.c
index 04f23295ffc1..b1d04d082e44 100644
--- a/drivers/remoteproc/ti_k3_r5_remoteproc.c
+++ b/drivers/remoteproc/ti_k3_r5_remoteproc.c
@@ -1074,11 +1074,9 @@ static int k3_r5_cluster_rproc_init(struct platform_device *pdev)
}
kproc->reset = devm_reset_control_get_exclusive(cdev, NULL);
- if (IS_ERR_OR_NULL(kproc->reset)) {
- ret = PTR_ERR_OR_ZERO(kproc->reset);
- if (!ret)
- ret = -ENODEV;
- dev_err_probe(cdev, ret, "failed to get reset handle\n");
+ if (IS_ERR(kproc->reset)) {
+ ret = dev_err_probe(cdev, PTR_ERR(kproc->reset),
+ "failed to get reset handle\n");
goto out;
}
diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/drivers/s390/crypto/zcrypt_cex2a.c
+++ /dev/null
diff --git a/drivers/s390/crypto/zcrypt_cex2a.h b/drivers/s390/crypto/zcrypt_cex2a.h
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/drivers/s390/crypto/zcrypt_cex2a.h
+++ /dev/null
diff --git a/drivers/s390/crypto/zcrypt_cex2c.c b/drivers/s390/crypto/zcrypt_cex2c.c
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/drivers/s390/crypto/zcrypt_cex2c.c
+++ /dev/null
diff --git a/drivers/s390/crypto/zcrypt_cex2c.h b/drivers/s390/crypto/zcrypt_cex2c.h
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/drivers/s390/crypto/zcrypt_cex2c.h
+++ /dev/null
diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c
index 8948b5fd42d2..22c8099cf6bb 100644
--- a/drivers/soc/qcom/llcc-qcom.c
+++ b/drivers/soc/qcom/llcc-qcom.c
@@ -2305,6 +2305,20 @@ static const struct llcc_slice_config sdm845_data[] = {{
},
};
+static const struct llcc_slice_config shikra_data[] = {
+ {
+ .usecase_id = LLCC_ECC,
+ .slice_id = 26,
+ .max_cap = 256,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0x3,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ .vict_prio = true,
+ },
+};
+
static const struct llcc_slice_config sm6350_data[] = {
{
.usecase_id = LLCC_CPUSS,
@@ -4575,6 +4589,15 @@ static const struct qcom_llcc_config sdm845_cfg[] = {
},
};
+static const struct qcom_llcc_config shikra_cfg[] = {
+ {
+ .sct_data = shikra_data,
+ .size = ARRAY_SIZE(shikra_data),
+ .reg_offset = llcc_v2_1_reg_offset,
+ .edac_reg_offset = &llcc_v2_1_edac_reg_offset,
+ },
+};
+
static const struct qcom_llcc_config sm6350_cfg[] = {
{
.sct_data = sm6350_data,
@@ -4752,6 +4775,11 @@ static const struct qcom_sct_config sdm845_cfgs = {
.num_config = ARRAY_SIZE(sdm845_cfg),
};
+static const struct qcom_sct_config shikra_cfgs = {
+ .llcc_config = shikra_cfg,
+ .num_config = ARRAY_SIZE(shikra_cfg),
+};
+
static const struct qcom_sct_config sm6350_cfgs = {
.llcc_config = sm6350_cfg,
.num_config = ARRAY_SIZE(sm6350_cfg),
@@ -5632,6 +5660,7 @@ static const struct of_device_id qcom_llcc_of_match[] = {
{ .compatible = "qcom,sc8280xp-llcc", .data = &sc8280xp_cfgs },
{ .compatible = "qcom,sdm670-llcc", .data = &sdm670_cfgs },
{ .compatible = "qcom,sdm845-llcc", .data = &sdm845_cfgs },
+ { .compatible = "qcom,shikra-llcc", .data = &shikra_cfgs },
{ .compatible = "qcom,sm6350-llcc", .data = &sm6350_cfgs },
{ .compatible = "qcom,sm7150-llcc", .data = &sm7150_cfgs },
{ .compatible = "qcom,sm8150-llcc", .data = &sm8150_cfgs },
diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c
index c004d444d698..137992456b71 100644
--- a/drivers/soc/qcom/mdt_loader.c
+++ b/drivers/soc/qcom/mdt_loader.c
@@ -13,7 +13,7 @@
#include <linux/firmware.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/firmware/qcom/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_pas.h>
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/soc/qcom/mdt_loader.h>
@@ -229,7 +229,7 @@ EXPORT_SYMBOL_GPL(qcom_mdt_read_metadata);
static int __qcom_mdt_pas_init(struct device *dev, const struct firmware *fw,
const char *fw_name, int pas_id, phys_addr_t mem_phys,
- struct qcom_scm_pas_context *ctx)
+ struct qcom_pas_context *ctx)
{
const struct elf32_phdr *phdrs;
const struct elf32_phdr *phdr;
@@ -271,7 +271,7 @@ static int __qcom_mdt_pas_init(struct device *dev, const struct firmware *fw,
goto out;
}
- ret = qcom_scm_pas_init_image(pas_id, metadata, metadata_len, ctx);
+ ret = qcom_pas_init_image(pas_id, metadata, metadata_len, ctx);
kfree(metadata);
if (ret) {
/* Invalid firmware metadata */
@@ -280,7 +280,7 @@ static int __qcom_mdt_pas_init(struct device *dev, const struct firmware *fw,
}
if (relocate) {
- ret = qcom_scm_pas_mem_setup(pas_id, mem_phys, max_addr - min_addr);
+ ret = qcom_pas_mem_setup(pas_id, mem_phys, max_addr - min_addr);
if (ret) {
/* Unable to set up relocation */
dev_err(dev, "error %d setting up firmware %s\n", ret, fw_name);
@@ -472,7 +472,7 @@ EXPORT_SYMBOL_GPL(qcom_mdt_load);
* firmware segments (e.g., .bXX files). Authentication of the segments done
* by a separate call.
*
- * The PAS context must be initialized using qcom_scm_pas_context_init()
+ * The PAS context must be initialized using devm_qcom_pas_context_alloc()
* prior to invoking this function.
*
* @ctx: Pointer to the PAS (Peripheral Authentication Service) context
@@ -483,7 +483,7 @@ EXPORT_SYMBOL_GPL(qcom_mdt_load);
*
* Return: 0 on success or a negative error code on failure.
*/
-int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx, const struct firmware *fw,
+int qcom_mdt_pas_load(struct qcom_pas_context *ctx, const struct firmware *fw,
const char *firmware, void *mem_region, phys_addr_t *reloc_base)
{
int ret;
diff --git a/drivers/soc/qcom/qcom_pd_mapper.c b/drivers/soc/qcom/qcom_pd_mapper.c
index 0dc1a7946050..64ca99d7fad9 100644
--- a/drivers/soc/qcom/qcom_pd_mapper.c
+++ b/drivers/soc/qcom/qcom_pd_mapper.c
@@ -310,6 +310,24 @@ static const struct qcom_pdm_domain_data cdsp_root_pd = {
.services = { NULL },
};
+static const struct qcom_pdm_domain_data cdsp1_root_pd = {
+ .domain = "msm/cdsp1/root_pd",
+ .instance_id = 125,
+ .services = { NULL },
+};
+
+static const struct qcom_pdm_domain_data gpdsp_root_pd = {
+ .domain = "msm/gpdsp/root_pd",
+ .instance_id = 192,
+ .services = { NULL },
+};
+
+static const struct qcom_pdm_domain_data gpdsp1_root_pd = {
+ .domain = "msm/gpdsp1/root_pd",
+ .instance_id = 241,
+ .services = { NULL },
+};
+
static const struct qcom_pdm_domain_data slpi_root_pd = {
.domain = "msm/slpi/root_pd",
.instance_id = 90,
@@ -425,6 +443,24 @@ static const struct qcom_pdm_domain_data *qcs615_domains[] = {
NULL,
};
+static const struct qcom_pdm_domain_data *qcs8300_domains[] = {
+ &adsp_audio_pd,
+ &adsp_root_pd,
+ &cdsp_root_pd,
+ &gpdsp_root_pd,
+ NULL,
+};
+
+static const struct qcom_pdm_domain_data *sa8775p_domains[] = {
+ &adsp_audio_pd,
+ &adsp_root_pd,
+ &cdsp_root_pd,
+ &cdsp1_root_pd,
+ &gpdsp_root_pd,
+ &gpdsp1_root_pd,
+ NULL,
+};
+
static const struct qcom_pdm_domain_data *sc7180_domains[] = {
&adsp_audio_pd,
&adsp_root_pd_pdr,
@@ -602,6 +638,8 @@ static const struct of_device_id qcom_pdm_domains[] __maybe_unused = {
{ .compatible = "qcom,qcm6490", .data = sc7280_domains, },
{ .compatible = "qcom,qcs404", .data = qcs404_domains, },
{ .compatible = "qcom,qcs615", .data = qcs615_domains, },
+ { .compatible = "qcom,qcs8300", .data = qcs8300_domains, },
+ { .compatible = "qcom,sa8775p", .data = sa8775p_domains, },
{ .compatible = "qcom,sc7180", .data = sc7180_domains, },
{ .compatible = "qcom,sc7280", .data = sc7280_domains, },
{ .compatible = "qcom,sc8180x", .data = sc8180x_domains, },
diff --git a/drivers/soc/qcom/qcom_stats.c b/drivers/soc/qcom/qcom_stats.c
index 2e380faf9080..e7122444f12a 100644
--- a/drivers/soc/qcom/qcom_stats.c
+++ b/drivers/soc/qcom/qcom_stats.c
@@ -54,6 +54,8 @@ static const struct subsystem_data subsystems[] = {
{ "cdsp1", 607, 12 },
{ "gpdsp0", 607, 17 },
{ "gpdsp1", 607, 18 },
+ { "soccp", 607, 19 },
+ { "dcp", 607, 22 },
{ "slpi", 608, 3 },
{ "gpu", 609, 0 },
{ "display", 610, 0 },
diff --git a/drivers/soc/qcom/ubwc_config.c b/drivers/soc/qcom/ubwc_config.c
index a3cb6d61bb65..0209a02c390f 100644
--- a/drivers/soc/qcom/ubwc_config.c
+++ b/drivers/soc/qcom/ubwc_config.c
@@ -145,6 +145,7 @@ static const struct of_device_id qcom_ubwc_configs[] __maybe_unused = {
{ .compatible = "qcom,sdm660", .data = &ubwc_1_0_hbb14 },
{ .compatible = "qcom,sdm670", .data = &ubwc_2_0_hbb14, },
{ .compatible = "qcom,sdm845", .data = &ubwc_2_0_hbb15, },
+ { .compatible = "qcom,shikra", .data = &ubwc_0_0_hbb15, },
{ .compatible = "qcom,sm4250", .data = &ubwc_1_0_hbb14, },
{ .compatible = "qcom,sm6115", .data = &ubwc_1_0_hbb14, },
{ .compatible = "qcom,sm6125", .data = &ubwc_1_0_hbb14, },
diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
index 88ac0833351c..2914d781dbf5 100644
--- a/drivers/spi/spi-geni-qcom.c
+++ b/drivers/spi/spi-geni-qcom.c
@@ -622,25 +622,30 @@ static int spi_geni_init(struct spi_geni_master *mas)
u32 spi_tx_cfg, fifo_disable;
int ret = -ENXIO;
- pm_runtime_get_sync(mas->dev);
+ PM_RUNTIME_ACQUIRE_IF_ENABLED(mas->dev, pm);
+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+ if (ret < 0) {
+ dev_err(mas->dev, "Failed to resume and get %d\n", ret);
+ return ret;
+ }
proto = geni_se_read_proto(se);
if (spi->target) {
if (proto != GENI_SE_SPI_SLAVE) {
dev_err(mas->dev, "Invalid proto %d\n", proto);
- goto out_pm;
+ return ret;
}
spi_slv_setup(mas);
} else if (proto == GENI_SE_INVALID_PROTO) {
ret = geni_load_se_firmware(se, GENI_SE_SPI);
if (ret) {
dev_err(mas->dev, "spi master firmware load failed ret: %d\n", ret);
- goto out_pm;
+ return ret;
}
} else if (proto != GENI_SE_SPI) {
dev_err(mas->dev, "Invalid proto %d\n", proto);
- goto out_pm;
+ return ret;
}
mas->tx_fifo_depth = geni_se_get_tx_fifo_depth(se);
@@ -673,7 +678,7 @@ static int spi_geni_init(struct spi_geni_master *mas)
dev_dbg(mas->dev, "Using GPI DMA mode for SPI\n");
break;
} else if (ret == -EPROBE_DEFER) {
- goto out_pm;
+ return ret;
}
/*
* in case of failure to get gpi dma channel, we can still do the
@@ -702,8 +707,6 @@ static int spi_geni_init(struct spi_geni_master *mas)
writel(spi_tx_cfg, se->base + SE_SPI_TRANS_CFG);
}
-out_pm:
- pm_runtime_put(mas->dev);
return ret;
}
diff --git a/drivers/staging/axis-fifo/axis-fifo.c b/drivers/staging/axis-fifo/axis-fifo.c
index 3aa2aa870ea9..1c34de020cf8 100644
--- a/drivers/staging/axis-fifo/axis-fifo.c
+++ b/drivers/staging/axis-fifo/axis-fifo.c
@@ -246,7 +246,8 @@ static ssize_t axis_fifo_write(struct file *f, const char __user *buf,
mutex_lock(&fifo->write_lock);
ret = wait_event_interruptible(fifo->write_queue,
- ioread32(fifo->base_addr + XLLF_TDFV_OFFSET) >= words_to_write);
+ ioread32(fifo->base_addr + XLLF_TDFV_OFFSET) >=
+ words_to_write);
if (ret)
goto end_unlock;
}
diff --git a/drivers/staging/iio/frequency/ad9832.c b/drivers/staging/iio/frequency/ad9832.c
index e2f39617e458..a78249812b26 100644
--- a/drivers/staging/iio/frequency/ad9832.c
+++ b/drivers/staging/iio/frequency/ad9832.c
@@ -252,22 +252,22 @@ error_ret:
* see dds.h for further information
*/
-static IIO_DEV_ATTR_FREQ(0, 0, 0200, NULL, ad9832_write, AD9832_FREQ0HM);
-static IIO_DEV_ATTR_FREQ(0, 1, 0200, NULL, ad9832_write, AD9832_FREQ1HM);
-static IIO_DEV_ATTR_FREQSYMBOL(0, 0200, NULL, ad9832_write, AD9832_FREQ_SYM);
+static IIO_DEV_ATTR_FREQ(0200, 0, 0, NULL, ad9832_write, AD9832_FREQ0HM);
+static IIO_DEV_ATTR_FREQ(0200, 0, 1, NULL, ad9832_write, AD9832_FREQ1HM);
+static IIO_DEV_ATTR_FREQSYMBOL(0200, 0, NULL, ad9832_write, AD9832_FREQ_SYM);
static IIO_CONST_ATTR_FREQ_SCALE(0, "1"); /* 1Hz */
-static IIO_DEV_ATTR_PHASE(0, 0, 0200, NULL, ad9832_write, AD9832_PHASE0H);
-static IIO_DEV_ATTR_PHASE(0, 1, 0200, NULL, ad9832_write, AD9832_PHASE1H);
-static IIO_DEV_ATTR_PHASE(0, 2, 0200, NULL, ad9832_write, AD9832_PHASE2H);
-static IIO_DEV_ATTR_PHASE(0, 3, 0200, NULL, ad9832_write, AD9832_PHASE3H);
-static IIO_DEV_ATTR_PHASESYMBOL(0, 0200, NULL,
+static IIO_DEV_ATTR_PHASE(0200, 0, 0, NULL, ad9832_write, AD9832_PHASE0H);
+static IIO_DEV_ATTR_PHASE(0200, 0, 1, NULL, ad9832_write, AD9832_PHASE1H);
+static IIO_DEV_ATTR_PHASE(0200, 0, 2, NULL, ad9832_write, AD9832_PHASE2H);
+static IIO_DEV_ATTR_PHASE(0200, 0, 3, NULL, ad9832_write, AD9832_PHASE3H);
+static IIO_DEV_ATTR_PHASESYMBOL(0200, 0, NULL,
ad9832_write, AD9832_PHASE_SYM);
static IIO_CONST_ATTR_PHASE_SCALE(0, "0.0015339808"); /* 2PI/2^12 rad*/
-static IIO_DEV_ATTR_PINCONTROL_EN(0, 0200, NULL,
+static IIO_DEV_ATTR_PINCONTROL_EN(0200, 0, NULL,
ad9832_write, AD9832_PINCTRL_EN);
-static IIO_DEV_ATTR_OUT_ENABLE(0, 0200, NULL,
+static IIO_DEV_ATTR_OUT_ENABLE(0200, 0, NULL,
ad9832_write, AD9832_OUTPUT_EN);
static struct attribute *ad9832_attributes[] = {
diff --git a/drivers/staging/iio/frequency/ad9834.c b/drivers/staging/iio/frequency/ad9834.c
index b039f3c074cd..0d20f796e0f0 100644
--- a/drivers/staging/iio/frequency/ad9834.c
+++ b/drivers/staging/iio/frequency/ad9834.c
@@ -314,21 +314,21 @@ static IIO_DEVICE_ATTR(out_altvoltage0_out1_wavetype_available, 0444,
* see dds.h for further information
*/
-static IIO_DEV_ATTR_FREQ(0, 0, 0200, NULL, ad9834_write, AD9834_REG_FREQ0);
-static IIO_DEV_ATTR_FREQ(0, 1, 0200, NULL, ad9834_write, AD9834_REG_FREQ1);
-static IIO_DEV_ATTR_FREQSYMBOL(0, 0200, NULL, ad9834_write, AD9834_FSEL);
+static IIO_DEV_ATTR_FREQ(0200, 0, 0, NULL, ad9834_write, AD9834_REG_FREQ0);
+static IIO_DEV_ATTR_FREQ(0200, 0, 1, NULL, ad9834_write, AD9834_REG_FREQ1);
+static IIO_DEV_ATTR_FREQSYMBOL(0200, 0, NULL, ad9834_write, AD9834_FSEL);
static IIO_CONST_ATTR_FREQ_SCALE(0, "1"); /* 1Hz */
-static IIO_DEV_ATTR_PHASE(0, 0, 0200, NULL, ad9834_write, AD9834_REG_PHASE0);
-static IIO_DEV_ATTR_PHASE(0, 1, 0200, NULL, ad9834_write, AD9834_REG_PHASE1);
-static IIO_DEV_ATTR_PHASESYMBOL(0, 0200, NULL, ad9834_write, AD9834_PSEL);
+static IIO_DEV_ATTR_PHASE(0200, 0, 0, NULL, ad9834_write, AD9834_REG_PHASE0);
+static IIO_DEV_ATTR_PHASE(0200, 0, 1, NULL, ad9834_write, AD9834_REG_PHASE1);
+static IIO_DEV_ATTR_PHASESYMBOL(0200, 0, NULL, ad9834_write, AD9834_PSEL);
static IIO_CONST_ATTR_PHASE_SCALE(0, "0.0015339808"); /* 2PI/2^12 rad*/
-static IIO_DEV_ATTR_PINCONTROL_EN(0, 0200, NULL, ad9834_write, AD9834_PIN_SW);
-static IIO_DEV_ATTR_OUT_ENABLE(0, 0200, NULL, ad9834_write, AD9834_RESET);
-static IIO_DEV_ATTR_OUTY_ENABLE(0, 1, 0200, NULL, ad9834_write, AD9834_OPBITEN);
-static IIO_DEV_ATTR_OUT_WAVETYPE(0, 0, ad9834_store_wavetype, 0);
-static IIO_DEV_ATTR_OUT_WAVETYPE(0, 1, ad9834_store_wavetype, 1);
+static IIO_DEV_ATTR_PINCONTROL_EN(0200, 0, NULL, ad9834_write, AD9834_PIN_SW);
+static IIO_DEV_ATTR_OUT_ENABLE(0200, 0, NULL, ad9834_write, AD9834_RESET);
+static IIO_DEV_ATTR_OUTY_ENABLE(0200, 0, 1, NULL, ad9834_write, AD9834_OPBITEN);
+static IIO_DEV_ATTR_OUT_WAVETYPE(0200, 0, 0, ad9834_store_wavetype, 0);
+static IIO_DEV_ATTR_OUT_WAVETYPE(0200, 0, 1, ad9834_store_wavetype, 1);
static struct attribute *ad9834_attributes[] = {
&iio_dev_attr_out_altvoltage0_frequency0.dev_attr.attr,
diff --git a/drivers/staging/iio/frequency/dds.h b/drivers/staging/iio/frequency/dds.h
index 2ebe68eb7398..b2ca8bb971e8 100644
--- a/drivers/staging/iio/frequency/dds.h
+++ b/drivers/staging/iio/frequency/dds.h
@@ -11,7 +11,7 @@
* /sys/bus/iio/devices/.../out_altvoltageX_frequencyY
*/
-#define IIO_DEV_ATTR_FREQ(_channel, _num, _mode, _show, _store, _addr) \
+#define IIO_DEV_ATTR_FREQ(_mode, _channel, _num, _show, _store, _addr) \
IIO_DEVICE_ATTR(out_altvoltage##_channel##_frequency##_num, \
_mode, _show, _store, _addr)
@@ -26,7 +26,7 @@
* /sys/bus/iio/devices/.../out_altvoltageX_frequencysymbol
*/
-#define IIO_DEV_ATTR_FREQSYMBOL(_channel, _mode, _show, _store, _addr) \
+#define IIO_DEV_ATTR_FREQSYMBOL(_mode, _channel, _show, _store, _addr) \
IIO_DEVICE_ATTR(out_altvoltage##_channel##_frequencysymbol, \
_mode, _show, _store, _addr)
@@ -34,7 +34,7 @@
* /sys/bus/iio/devices/.../out_altvoltageX_phaseY
*/
-#define IIO_DEV_ATTR_PHASE(_channel, _num, _mode, _show, _store, _addr) \
+#define IIO_DEV_ATTR_PHASE(_mode, _channel, _num, _show, _store, _addr) \
IIO_DEVICE_ATTR(out_altvoltage##_channel##_phase##_num, \
_mode, _show, _store, _addr)
@@ -49,7 +49,7 @@
* /sys/bus/iio/devices/.../out_altvoltageX_phasesymbol
*/
-#define IIO_DEV_ATTR_PHASESYMBOL(_channel, _mode, _show, _store, _addr) \
+#define IIO_DEV_ATTR_PHASESYMBOL(_mode, _channel, _show, _store, _addr) \
IIO_DEVICE_ATTR(out_altvoltage##_channel##_phasesymbol, \
_mode, _show, _store, _addr)
@@ -57,7 +57,7 @@
* /sys/bus/iio/devices/.../out_altvoltageX_pincontrol_en
*/
-#define IIO_DEV_ATTR_PINCONTROL_EN(_channel, _mode, _show, _store, _addr)\
+#define IIO_DEV_ATTR_PINCONTROL_EN(_mode, _channel, _show, _store, _addr)\
IIO_DEVICE_ATTR(out_altvoltage##_channel##_pincontrol_en, \
_mode, _show, _store, _addr)
@@ -65,7 +65,7 @@
* /sys/bus/iio/devices/.../out_altvoltageX_pincontrol_frequency_en
*/
-#define IIO_DEV_ATTR_PINCONTROL_FREQ_EN(_channel, _mode, _show, _store, _addr)\
+#define IIO_DEV_ATTR_PINCONTROL_FREQ_EN(_mode, _channel, _show, _store, _addr)\
IIO_DEVICE_ATTR(out_altvoltage##_channel##_pincontrol_frequency_en,\
_mode, _show, _store, _addr)
@@ -73,7 +73,7 @@
* /sys/bus/iio/devices/.../out_altvoltageX_pincontrol_phase_en
*/
-#define IIO_DEV_ATTR_PINCONTROL_PHASE_EN(_channel, _mode, _show, _store, _addr)\
+#define IIO_DEV_ATTR_PINCONTROL_PHASE_EN(_mode, _channel, _show, _store, _addr)\
IIO_DEVICE_ATTR(out_altvoltage##_channel##_pincontrol_phase_en, \
_mode, _show, _store, _addr)
@@ -81,7 +81,7 @@
* /sys/bus/iio/devices/.../out_altvoltageX_out_enable
*/
-#define IIO_DEV_ATTR_OUT_ENABLE(_channel, _mode, _show, _store, _addr) \
+#define IIO_DEV_ATTR_OUT_ENABLE(_mode, _channel, _show, _store, _addr) \
IIO_DEVICE_ATTR(out_altvoltage##_channel##_out_enable, \
_mode, _show, _store, _addr)
@@ -89,8 +89,8 @@
* /sys/bus/iio/devices/.../out_altvoltageX_outY_enable
*/
-#define IIO_DEV_ATTR_OUTY_ENABLE(_channel, _output, \
- _mode, _show, _store, _addr) \
+#define IIO_DEV_ATTR_OUTY_ENABLE(_mode, _channel, _output, \
+ _show, _store, _addr) \
IIO_DEVICE_ATTR(out_altvoltage##_channel##_out##_output##_enable,\
_mode, _show, _store, _addr)
@@ -98,9 +98,9 @@
* /sys/bus/iio/devices/.../out_altvoltageX_outY_wavetype
*/
-#define IIO_DEV_ATTR_OUT_WAVETYPE(_channel, _output, _store, _addr) \
+#define IIO_DEV_ATTR_OUT_WAVETYPE(_mode, _channel, _output, _store, _addr)\
IIO_DEVICE_ATTR(out_altvoltage##_channel##_out##_output##_wavetype,\
- 0200, NULL, _store, _addr)
+ _mode, NULL, _store, _addr)
/**
* /sys/bus/iio/devices/.../out_altvoltageX_outY_wavetype_available
diff --git a/drivers/staging/media/ipu7/ipu7.c b/drivers/staging/media/ipu7/ipu7.c
index 310e3f24e571..48a35bda4237 100644
--- a/drivers/staging/media/ipu7/ipu7.c
+++ b/drivers/staging/media/ipu7/ipu7.c
@@ -2343,7 +2343,7 @@ static int ipu7_init_fw_code_region_by_sys(struct ipu7_bus_device *sys,
return ret;
}
- ret = pm_runtime_get_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
if (ret < 0) {
dev_err(dev, "Failed to get runtime PM\n");
return ret;
@@ -2702,7 +2702,7 @@ static int ipu7_resume(struct device *dev)
if (ret)
dev_err(dev, "IPC reset protocol failed!\n");
- ret = pm_runtime_get_sync(&isp->psys->auxdev.dev);
+ ret = pm_runtime_resume_and_get(&isp->psys->auxdev.dev);
if (ret < 0) {
dev_err(dev, "Failed to get runtime PM\n");
return 0;
diff --git a/drivers/staging/rtl8723bs/core/rtw_ap.c b/drivers/staging/rtl8723bs/core/rtw_ap.c
index e1122d3f325d..1d429f16e01e 100644
--- a/drivers/staging/rtl8723bs/core/rtw_ap.c
+++ b/drivers/staging/rtl8723bs/core/rtw_ap.c
@@ -1165,7 +1165,7 @@ u8 rtw_ap_set_pairwise_key(struct adapter *padapter, struct sta_info *psta)
goto exit;
}
- init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_);
+ init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, SET_STA_KEY_CMD);
psetstakey_para->algorithm = (u8)psta->dot118021XPrivacy;
@@ -1228,7 +1228,7 @@ static int rtw_ap_set_key(struct adapter *padapter,
memcpy(&psetkeyparm->key[0], key, keylen);
- pcmd->cmdcode = _SetKey_CMD_;
+ pcmd->cmdcode = SET_KEY_CMD;
pcmd->parmbuf = (u8 *)psetkeyparm;
pcmd->cmdsz = (sizeof(struct setkey_parm));
pcmd->rsp = NULL;
diff --git a/drivers/staging/rtl8723bs/core/rtw_cmd.c b/drivers/staging/rtl8723bs/core/rtw_cmd.c
index 818226be783a..623ce064d395 100644
--- a/drivers/staging/rtl8723bs/core/rtw_cmd.c
+++ b/drivers/staging/rtl8723bs/core/rtw_cmd.c
@@ -11,78 +11,78 @@
#include <linux/delay.h>
static struct _cmd_callback rtw_cmd_callback[] = {
- {GEN_CMD_CODE(_Read_MACREG), NULL}, /*0*/
- {GEN_CMD_CODE(_Write_MACREG), NULL},
- {GEN_CMD_CODE(_Read_BBREG), &rtw_getbbrfreg_cmdrsp_callback},
- {GEN_CMD_CODE(_Write_BBREG), NULL},
- {GEN_CMD_CODE(_Read_RFREG), &rtw_getbbrfreg_cmdrsp_callback},
- {GEN_CMD_CODE(_Write_RFREG), NULL}, /*5*/
- {GEN_CMD_CODE(_Read_EEPROM), NULL},
- {GEN_CMD_CODE(_Write_EEPROM), NULL},
- {GEN_CMD_CODE(_Read_EFUSE), NULL},
- {GEN_CMD_CODE(_Write_EFUSE), NULL},
-
- {GEN_CMD_CODE(_Read_CAM), NULL}, /*10*/
- {GEN_CMD_CODE(_Write_CAM), NULL},
- {GEN_CMD_CODE(_setBCNITV), NULL},
- {GEN_CMD_CODE(_setMBIDCFG), NULL},
- {GEN_CMD_CODE(_JoinBss), &rtw_joinbss_cmd_callback}, /*14*/
- {GEN_CMD_CODE(_DisConnect), &rtw_disassoc_cmd_callback}, /*15*/
- {GEN_CMD_CODE(_CreateBss), &rtw_createbss_cmd_callback},
- {GEN_CMD_CODE(_SetOpMode), NULL},
- {GEN_CMD_CODE(_SiteSurvey), &rtw_survey_cmd_callback}, /*18*/
- {GEN_CMD_CODE(_SetAuth), NULL},
-
- {GEN_CMD_CODE(_SetKey), NULL}, /*20*/
- {GEN_CMD_CODE(_SetStaKey), &rtw_setstaKey_cmdrsp_callback},
- {GEN_CMD_CODE(_SetAssocSta), &rtw_setassocsta_cmdrsp_callback},
- {GEN_CMD_CODE(_DelAssocSta), NULL},
- {GEN_CMD_CODE(_SetStaPwrState), NULL},
- {GEN_CMD_CODE(_SetBasicRate), NULL}, /*25*/
- {GEN_CMD_CODE(_GetBasicRate), NULL},
- {GEN_CMD_CODE(_SetDataRate), NULL},
- {GEN_CMD_CODE(_GetDataRate), NULL},
- {GEN_CMD_CODE(_SetPhyInfo), NULL},
-
- {GEN_CMD_CODE(_GetPhyInfo), NULL}, /*30*/
- {GEN_CMD_CODE(_SetPhy), NULL},
- {GEN_CMD_CODE(_GetPhy), NULL},
- {GEN_CMD_CODE(_readRssi), NULL},
- {GEN_CMD_CODE(_readGain), NULL},
- {GEN_CMD_CODE(_SetAtim), NULL}, /*35*/
- {GEN_CMD_CODE(_SetPwrMode), NULL},
- {GEN_CMD_CODE(_JoinbssRpt), NULL},
- {GEN_CMD_CODE(_SetRaTable), NULL},
- {GEN_CMD_CODE(_GetRaTable), NULL},
-
- {GEN_CMD_CODE(_GetCCXReport), NULL}, /*40*/
- {GEN_CMD_CODE(_GetDTMReport), NULL},
- {GEN_CMD_CODE(_GetTXRateStatistics), NULL},
- {GEN_CMD_CODE(_SetUsbSuspend), NULL},
- {GEN_CMD_CODE(_SetH2cLbk), NULL},
- {GEN_CMD_CODE(_AddBAReq), NULL}, /*45*/
- {GEN_CMD_CODE(_SetChannel), NULL}, /*46*/
- {GEN_CMD_CODE(_SetTxPower), NULL},
- {GEN_CMD_CODE(_SwitchAntenna), NULL},
- {GEN_CMD_CODE(_SetCrystalCap), NULL},
- {GEN_CMD_CODE(_SetSingleCarrierTx), NULL}, /*50*/
-
- {GEN_CMD_CODE(_SetSingleToneTx), NULL}, /*51*/
- {GEN_CMD_CODE(_SetCarrierSuppressionTx), NULL},
- {GEN_CMD_CODE(_SetContinuousTx), NULL},
- {GEN_CMD_CODE(_SwitchBandwidth), NULL}, /*54*/
- {GEN_CMD_CODE(_TX_Beacon), NULL},/*55*/
-
- {GEN_CMD_CODE(_Set_MLME_EVT), NULL},/*56*/
- {GEN_CMD_CODE(_Set_Drv_Extra), NULL},/*57*/
- {GEN_CMD_CODE(_Set_H2C_MSG), NULL},/*58*/
- {GEN_CMD_CODE(_SetChannelPlan), NULL},/*59*/
-
- {GEN_CMD_CODE(_SetChannelSwitch), NULL},/*60*/
- {GEN_CMD_CODE(_TDLS), NULL},/*61*/
- {GEN_CMD_CODE(_ChkBMCSleepq), NULL}, /*62*/
-
- {GEN_CMD_CODE(_RunInThreadCMD), NULL},/*63*/
+ {READ_MACREG_CMD, NULL}, /*0*/
+ {WRITE_MACREG_CMD, NULL},
+ {READ_BBREG_CMD, &rtw_getbbrfreg_cmdrsp_callback},
+ {WRITE_BBREG_CMD, NULL},
+ {READ_RFREG_CMD, &rtw_getbbrfreg_cmdrsp_callback},
+ {WRITE_RFREG_CMD, NULL}, /*5*/
+ {READ_EEPROM_CMD, NULL},
+ {WRITE_EEPROM_CMD, NULL},
+ {READ_EFUSE_CMD, NULL},
+ {WRITE_EFUSE_CMD, NULL},
+
+ {READ_CAM_CMD, NULL}, /*10*/
+ {WRITE_CAM_CMD, NULL},
+ {SET_BCNITV_CMD, NULL},
+ {SET_MBIDCFG_CMD, NULL},
+ {JOIN_BSS_CMD, &rtw_joinbss_cmd_callback}, /*14*/
+ {DISCONNECT_CMD, &rtw_disassoc_cmd_callback}, /*15*/
+ {CREATE_BSS_CMD, &rtw_createbss_cmd_callback},
+ {SET_OP_MODE_CMD, NULL},
+ {SITE_SURVEY_CMD, &rtw_survey_cmd_callback}, /*18*/
+ {SET_AUTH_CMD, NULL},
+
+ {SET_KEY_CMD, NULL}, /*20*/
+ {SET_STA_KEY_CMD, &rtw_setstaKey_cmdrsp_callback},
+ {SET_ASSOC_STA_CMD, &rtw_setassocsta_cmdrsp_callback},
+ {DEL_ASSOC_STA_CMD, NULL},
+ {SET_STA_PWR_STATE_CMD, NULL},
+ {SET_BASIC_RATE_CMD, NULL}, /*25*/
+ {GET_BASIC_RATE_CMD, NULL},
+ {SET_DATA_RATE_CMD, NULL},
+ {GET_DATA_RATE_CMD, NULL},
+ {SET_PHY_INFO_CMD, NULL},
+
+ {GET_PHY_INFO_CMD, NULL}, /*30*/
+ {SET_PHY_CMD, NULL},
+ {GET_PHY_CMD, NULL},
+ {READ_RSSI_CMD, NULL},
+ {READ_GAIN_CMD, NULL},
+ {SET_ATIM_CMD, NULL}, /*35*/
+ {SET_PWR_MODE_CMD, NULL},
+ {JOIN_BSS_RPT_CMD, NULL},
+ {SET_RA_TABLE_CMD, NULL},
+ {GET_RA_TABLE_CMD, NULL},
+
+ {GET_CCX_REPORT_CMD, NULL}, /*40*/
+ {GET_DTM_REPORT_CMD, NULL},
+ {GET_TX_RATE_STATISTICS_CMD, NULL},
+ {SET_USB_SUSPEND_CMD, NULL},
+ {SET_H2C_LBK_CMD, NULL},
+ {ADD_BA_REQ_CMD, NULL}, /*45*/
+ {SET_CHANNEL_CMD, NULL}, /*46*/
+ {SET_TX_POWER_CMD, NULL},
+ {SWITCH_ANTENNA_CMD, NULL},
+ {SET_CRYSTAL_CAP_CMD, NULL},
+ {SET_SINGLE_CARRIER_TX_CMD, NULL}, /*50*/
+
+ {SET_SINGLE_TONE_TX_CMD, NULL}, /*51*/
+ {SET_CARRIER_SUPPRESSION_TX_CMD, NULL},
+ {SET_CONTINUOUS_TX_CMD, NULL},
+ {SWITCH_BANDWIDTH_CMD, NULL}, /*54*/
+ {TX_BEACON_CMD, NULL},/*55*/
+
+ {SET_MLME_EVT_CMD, NULL},/*56*/
+ {SET_DRV_EXTRA_CMD, NULL},/*57*/
+ {SET_H2C_MSG_CMD, NULL},/*58*/
+ {SET_CHANNEL_PLAN_CMD, NULL},/*59*/
+
+ {SET_CHANNEL_SWITCH_CMD, NULL},/*60*/
+ {TDLS_CMD, NULL},/*61*/
+ {CHK_BMC_SLEEPQ_CMD, NULL}, /*62*/
+
+ {RUN_IN_THREAD_CMD, NULL},/*63*/
};
static struct cmd_hdl wlancmds[] = {
@@ -296,12 +296,12 @@ void rtw_free_cmd_priv(struct cmd_priv *pcmdpriv)
int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj);
int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj)
{
- u8 bAllow = false; /* set to true to allow enqueuing cmd when hw_init_completed is false */
+ bool allow = false; /* set to true to allow enqueuing cmd when hw_init_completed is false */
- if (cmd_obj->cmdcode == GEN_CMD_CODE(_SetChannelPlan))
- bAllow = true;
+ if (cmd_obj->cmdcode == SET_CHANNEL_PLAN_CMD)
+ allow = true;
- if ((!pcmdpriv->padapter->hw_init_completed && !bAllow) ||
+ if ((!pcmdpriv->padapter->hw_init_completed && !allow) ||
!atomic_read(&pcmdpriv->cmdthd_running)) /* com_thread not running */
return _FAIL;
@@ -341,8 +341,8 @@ struct cmd_obj *rtw_dequeue_cmd(struct cmd_priv *pcmdpriv)
void rtw_free_cmd_obj(struct cmd_obj *pcmd)
{
- if ((pcmd->cmdcode != _JoinBss_CMD_) &&
- (pcmd->cmdcode != _CreateBss_CMD_)) {
+ if ((pcmd->cmdcode != JOIN_BSS_CMD) &&
+ (pcmd->cmdcode != CREATE_BSS_CMD)) {
/* free parmbuf in cmd_obj */
kfree(pcmd->parmbuf);
}
@@ -499,7 +499,7 @@ post_process:
break;
}
- if (pcmd->cmdcode == GEN_CMD_CODE(_Set_Drv_Extra)) {
+ if (pcmd->cmdcode == SET_DRV_EXTRA_CMD) {
extra_parm = (struct drvextra_cmd_parm *)pcmd->parmbuf;
if (extra_parm->pbuf && extra_parm->size > 0)
kfree(extra_parm->pbuf);
@@ -544,7 +544,7 @@ u8 rtw_sitesurvey_cmd(struct adapter *padapter, struct ndis_802_11_ssid *ssid,
rtw_free_network_queue(padapter, false);
- init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara, GEN_CMD_CODE(_SiteSurvey));
+ init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara, SITE_SURVEY_CMD);
/* psurveyPara->bsslimit = 48; */
psurveyPara->scan_mode = pmlmepriv->scan_mode;
@@ -607,7 +607,7 @@ u8 rtw_createbss_cmd(struct adapter *padapter)
}
INIT_LIST_HEAD(&pcmd->list);
- pcmd->cmdcode = _CreateBss_CMD_;
+ pcmd->cmdcode = CREATE_BSS_CMD;
pcmd->parmbuf = (unsigned char *)pdev_network;
pcmd->cmdsz = get_wlan_bssid_ex_sz((struct wlan_bssid_ex *)pdev_network);
pcmd->rsp = NULL;
@@ -640,7 +640,7 @@ int rtw_startbss_cmd(struct adapter *padapter, int flags)
}
INIT_LIST_HEAD(&pcmd->list);
- pcmd->cmdcode = GEN_CMD_CODE(_CreateBss);
+ pcmd->cmdcode = CREATE_BSS_CMD;
pcmd->parmbuf = NULL;
pcmd->cmdsz = 0;
pcmd->rsp = NULL;
@@ -780,7 +780,7 @@ u8 rtw_joinbss_cmd(struct adapter *padapter, struct wlan_network *pnetwork)
pcmd->cmdsz = get_wlan_bssid_ex_sz(psecnetwork);/* get cmdsz before endian conversion */
INIT_LIST_HEAD(&pcmd->list);
- pcmd->cmdcode = _JoinBss_CMD_;/* GEN_CMD_CODE(_JoinBss) */
+ pcmd->cmdcode = JOIN_BSS_CMD;
pcmd->parmbuf = (unsigned char *)psecnetwork;
pcmd->rsp = NULL;
pcmd->rspsz = 0;
@@ -814,7 +814,7 @@ u8 rtw_disassoc_cmd(struct adapter *padapter, u32 deauth_timeout_ms, bool enqueu
kfree(param);
goto exit;
}
- init_h2fwcmd_w_parm_no_rsp(cmdobj, param, _DisConnect_CMD_);
+ init_h2fwcmd_w_parm_no_rsp(cmdobj, param, DISCONNECT_CMD);
res = rtw_enqueue_cmd(cmdpriv, cmdobj);
} else {
/* no need to enqueue, do the cmd hdl directly and free cmd parameter */
@@ -850,7 +850,7 @@ u8 rtw_setopmode_cmd(struct adapter *padapter, enum nl80211_iftype networktype,
goto exit;
}
- init_h2fwcmd_w_parm_no_rsp(ph2c, psetop, _SetOpMode_CMD_);
+ init_h2fwcmd_w_parm_no_rsp(ph2c, psetop, SET_OP_MODE_CMD);
res = rtw_enqueue_cmd(pcmdpriv, ph2c);
} else {
setopmode_hdl(padapter, (u8 *)psetop);
@@ -907,7 +907,7 @@ u8 rtw_setstakey_cmd(struct adapter *padapter, struct sta_info *sta, u8 unicast_
goto exit;
}
- init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_);
+ init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, SET_STA_KEY_CMD);
ph2c->rsp = (u8 *)psetstakey_rsp;
ph2c->rspsz = sizeof(struct set_stakey_rsp);
res = rtw_enqueue_cmd(pcmdpriv, ph2c);
@@ -958,7 +958,7 @@ u8 rtw_clearstakey_cmd(struct adapter *padapter, struct sta_info *sta, u8 enqueu
goto exit;
}
- init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_);
+ init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, SET_STA_KEY_CMD);
ph2c->rsp = (u8 *)psetstakey_rsp;
ph2c->rspsz = sizeof(struct set_stakey_rsp);
@@ -996,7 +996,7 @@ u8 rtw_addbareq_cmd(struct adapter *padapter, u8 tid, u8 *addr)
paddbareq_parm->tid = tid;
memcpy(paddbareq_parm->addr, addr, ETH_ALEN);
- init_h2fwcmd_w_parm_no_rsp(ph2c, paddbareq_parm, GEN_CMD_CODE(_AddBAReq));
+ init_h2fwcmd_w_parm_no_rsp(ph2c, paddbareq_parm, ADD_BA_REQ_CMD);
/* rtw_enqueue_cmd(pcmdpriv, ph2c); */
res = rtw_enqueue_cmd(pcmdpriv, ph2c);
@@ -1030,7 +1030,7 @@ u8 rtw_reset_securitypriv_cmd(struct adapter *padapter)
pdrvextra_cmd_parm->size = 0;
pdrvextra_cmd_parm->pbuf = NULL;
- init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, SET_DRV_EXTRA_CMD);
/* rtw_enqueue_cmd(pcmdpriv, ph2c); */
res = rtw_enqueue_cmd(pcmdpriv, ph2c);
@@ -1063,7 +1063,7 @@ u8 rtw_free_assoc_resources_cmd(struct adapter *padapter)
pdrvextra_cmd_parm->size = 0;
pdrvextra_cmd_parm->pbuf = NULL;
- init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, SET_DRV_EXTRA_CMD);
/* rtw_enqueue_cmd(pcmdpriv, ph2c); */
res = rtw_enqueue_cmd(pcmdpriv, ph2c);
@@ -1096,7 +1096,7 @@ u8 rtw_dynamic_chk_wk_cmd(struct adapter *padapter)
pdrvextra_cmd_parm->type = 0;
pdrvextra_cmd_parm->size = 0;
pdrvextra_cmd_parm->pbuf = NULL;
- init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, SET_DRV_EXTRA_CMD);
/* rtw_enqueue_cmd(pcmdpriv, ph2c); */
res = rtw_enqueue_cmd(pcmdpriv, ph2c);
@@ -1345,7 +1345,7 @@ u8 rtw_lps_ctrl_wk_cmd(struct adapter *padapter, u8 lps_ctrl_type, u8 enqueue)
pdrvextra_cmd_parm->size = 0;
pdrvextra_cmd_parm->pbuf = NULL;
- init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, SET_DRV_EXTRA_CMD);
res = rtw_enqueue_cmd(pcmdpriv, ph2c);
} else {
@@ -1386,7 +1386,7 @@ u8 rtw_dm_in_lps_wk_cmd(struct adapter *padapter)
pdrvextra_cmd_parm->size = 0;
pdrvextra_cmd_parm->pbuf = NULL;
- init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, SET_DRV_EXTRA_CMD);
res = rtw_enqueue_cmd(pcmdpriv, ph2c);
@@ -1448,7 +1448,7 @@ u8 rtw_dm_ra_mask_wk_cmd(struct adapter *padapter, u8 *psta)
pdrvextra_cmd_parm->size = 0;
pdrvextra_cmd_parm->pbuf = psta;
- init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, SET_DRV_EXTRA_CMD);
res = rtw_enqueue_cmd(pcmdpriv, ph2c);
@@ -1481,7 +1481,7 @@ u8 rtw_ps_cmd(struct adapter *padapter)
pdrvextra_cmd_parm->type = 0;
pdrvextra_cmd_parm->size = 0;
pdrvextra_cmd_parm->pbuf = NULL;
- init_h2fwcmd_w_parm_no_rsp(ppscmd, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+ init_h2fwcmd_w_parm_no_rsp(ppscmd, pdrvextra_cmd_parm, SET_DRV_EXTRA_CMD);
res = rtw_enqueue_cmd(pcmdpriv, ppscmd);
@@ -1552,7 +1552,7 @@ u8 rtw_chk_hi_queue_cmd(struct adapter *padapter)
pdrvextra_cmd_parm->size = 0;
pdrvextra_cmd_parm->pbuf = NULL;
- init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, SET_DRV_EXTRA_CMD);
res = rtw_enqueue_cmd(pcmdpriv, ph2c);
@@ -1644,7 +1644,7 @@ u8 rtw_c2h_packet_wk_cmd(struct adapter *padapter, u8 *pbuf, u16 length)
pdrvextra_cmd_parm->size = length;
pdrvextra_cmd_parm->pbuf = pbuf;
- init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, SET_DRV_EXTRA_CMD);
res = rtw_enqueue_cmd(pcmdpriv, ph2c);
@@ -1679,7 +1679,7 @@ u8 rtw_c2h_wk_cmd(struct adapter *padapter, u8 *c2h_evt)
pdrvextra_cmd_parm->size = c2h_evt ? 16 : 0;
pdrvextra_cmd_parm->pbuf = c2h_evt;
- init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, SET_DRV_EXTRA_CMD);
res = rtw_enqueue_cmd(pcmdpriv, ph2c);
diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme.c b/drivers/staging/rtl8723bs/core/rtw_mlme.c
index 776ee3a90cca..849280edaacc 100644
--- a/drivers/staging/rtl8723bs/core/rtw_mlme.c
+++ b/drivers/staging/rtl8723bs/core/rtw_mlme.c
@@ -1859,7 +1859,7 @@ signed int rtw_set_auth(struct adapter *adapter, struct security_priv *psecurity
psetauthparm->mode = (unsigned char)psecuritypriv->dot11_auth_algrthm;
- pcmd->cmdcode = _SetAuth_CMD_;
+ pcmd->cmdcode = SET_AUTH_CMD;
pcmd->parmbuf = (unsigned char *)psetauthparm;
pcmd->cmdsz = (sizeof(struct setauth_parm));
pcmd->rsp = NULL;
@@ -1930,7 +1930,7 @@ signed int rtw_set_key(struct adapter *adapter, struct security_priv *psecurityp
goto exit;
}
- pcmd->cmdcode = _SetKey_CMD_;
+ pcmd->cmdcode = SET_KEY_CMD;
pcmd->parmbuf = (u8 *)psetkeyparm;
pcmd->cmdsz = (sizeof(struct setkey_parm));
pcmd->rsp = NULL;
diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c
index 76fc252177da..f3497b5871eb 100644
--- a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c
+++ b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c
@@ -4298,7 +4298,7 @@ void report_survey_event(struct adapter *padapter, union recv_frame *precv_frame
INIT_LIST_HEAD(&pcmd_obj->list);
- pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT);
+ pcmd_obj->cmdcode = SET_MLME_EVT_CMD;
pcmd_obj->cmdsz = cmdsz;
pcmd_obj->parmbuf = pevtcmd;
@@ -4307,7 +4307,7 @@ void report_survey_event(struct adapter *padapter, union recv_frame *precv_frame
pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd);
pc2h_evt_hdr->len = sizeof(struct survey_event);
- pc2h_evt_hdr->ID = GEN_EVT_CODE(_Survey);
+ pc2h_evt_hdr->ID = SURVEY_EVENT;
pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq);
psurvey_evt = (struct survey_event *)(pevtcmd + sizeof(struct C2HEvent_Header));
@@ -4348,7 +4348,7 @@ void report_surveydone_event(struct adapter *padapter)
INIT_LIST_HEAD(&pcmd_obj->list);
- pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT);
+ pcmd_obj->cmdcode = SET_MLME_EVT_CMD;
pcmd_obj->cmdsz = cmdsz;
pcmd_obj->parmbuf = pevtcmd;
@@ -4357,7 +4357,7 @@ void report_surveydone_event(struct adapter *padapter)
pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd);
pc2h_evt_hdr->len = sizeof(struct surveydone_event);
- pc2h_evt_hdr->ID = GEN_EVT_CODE(_SurveyDone);
+ pc2h_evt_hdr->ID = SURVEY_DONE_EVENT;
pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq);
psurveydone_evt = (struct surveydone_event *)(pevtcmd + sizeof(struct C2HEvent_Header));
@@ -4390,7 +4390,7 @@ void report_join_res(struct adapter *padapter, int res)
INIT_LIST_HEAD(&pcmd_obj->list);
- pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT);
+ pcmd_obj->cmdcode = SET_MLME_EVT_CMD;
pcmd_obj->cmdsz = cmdsz;
pcmd_obj->parmbuf = pevtcmd;
@@ -4399,7 +4399,7 @@ void report_join_res(struct adapter *padapter, int res)
pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd);
pc2h_evt_hdr->len = sizeof(struct joinbss_event);
- pc2h_evt_hdr->ID = GEN_EVT_CODE(_JoinBss);
+ pc2h_evt_hdr->ID = JOIN_BSS_EVENT;
pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq);
pjoinbss_evt = (struct joinbss_event *)(pevtcmd + sizeof(struct C2HEvent_Header));
@@ -4434,7 +4434,7 @@ void report_wmm_edca_update(struct adapter *padapter)
INIT_LIST_HEAD(&pcmd_obj->list);
- pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT);
+ pcmd_obj->cmdcode = SET_MLME_EVT_CMD;
pcmd_obj->cmdsz = cmdsz;
pcmd_obj->parmbuf = pevtcmd;
@@ -4443,7 +4443,7 @@ void report_wmm_edca_update(struct adapter *padapter)
pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd);
pc2h_evt_hdr->len = sizeof(struct wmm_event);
- pc2h_evt_hdr->ID = GEN_EVT_CODE(_WMM);
+ pc2h_evt_hdr->ID = WMM_EVENT;
pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq);
pwmm_event = (struct wmm_event *)(pevtcmd + sizeof(struct C2HEvent_Header));
@@ -4477,7 +4477,7 @@ void report_del_sta_event(struct adapter *padapter, unsigned char *MacAddr, unsi
INIT_LIST_HEAD(&pcmd_obj->list);
- pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT);
+ pcmd_obj->cmdcode = SET_MLME_EVT_CMD;
pcmd_obj->cmdsz = cmdsz;
pcmd_obj->parmbuf = pevtcmd;
@@ -4486,7 +4486,7 @@ void report_del_sta_event(struct adapter *padapter, unsigned char *MacAddr, unsi
pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd);
pc2h_evt_hdr->len = sizeof(struct stadel_event);
- pc2h_evt_hdr->ID = GEN_EVT_CODE(_DelSTA);
+ pc2h_evt_hdr->ID = DEL_STA_EVENT;
pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq);
pdel_sta_evt = (struct stadel_event *)(pevtcmd + sizeof(struct C2HEvent_Header));
@@ -4527,7 +4527,7 @@ void report_add_sta_event(struct adapter *padapter, unsigned char *MacAddr, int
INIT_LIST_HEAD(&pcmd_obj->list);
- pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT);
+ pcmd_obj->cmdcode = SET_MLME_EVT_CMD;
pcmd_obj->cmdsz = cmdsz;
pcmd_obj->parmbuf = pevtcmd;
@@ -4536,7 +4536,7 @@ void report_add_sta_event(struct adapter *padapter, unsigned char *MacAddr, int
pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd);
pc2h_evt_hdr->len = sizeof(struct stassoc_event);
- pc2h_evt_hdr->ID = GEN_EVT_CODE(_AddSTA);
+ pc2h_evt_hdr->ID = ADD_STA_EVENT;
pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq);
padd_sta_evt = (struct stassoc_event *)(pevtcmd + sizeof(struct C2HEvent_Header));
@@ -4971,7 +4971,7 @@ void survey_timer_hdl(struct timer_list *t)
return;
}
- init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara, GEN_CMD_CODE(_SiteSurvey));
+ init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara, SITE_SURVEY_CMD);
rtw_enqueue_cmd(pcmdpriv, ph2c);
}
}
@@ -5578,7 +5578,7 @@ u8 chk_bmc_sleepq_cmd(struct adapter *padapter)
goto exit;
}
- init_h2fwcmd_w_parm_no_parm_rsp(ph2c, GEN_CMD_CODE(_ChkBMCSleepq));
+ init_h2fwcmd_w_parm_no_parm_rsp(ph2c, CHK_BMC_SLEEPQ_CMD);
res = rtw_enqueue_cmd(pcmdpriv, ph2c);
@@ -5616,7 +5616,7 @@ u8 set_tx_beacon_cmd(struct adapter *padapter)
pmlmeinfo->hidden_ssid_mode);
ptxBeacon_parm->network.ie_length += len_diff;
- init_h2fwcmd_w_parm_no_rsp(ph2c, ptxBeacon_parm, GEN_CMD_CODE(_TX_Beacon));
+ init_h2fwcmd_w_parm_no_rsp(ph2c, ptxBeacon_parm, TX_BEACON_CMD);
res = rtw_enqueue_cmd(pcmdpriv, ph2c);
diff --git a/drivers/staging/rtl8723bs/include/rtw_cmd.h b/drivers/staging/rtl8723bs/include/rtw_cmd.h
index 1f822c1784eb..2e791da7e815 100644
--- a/drivers/staging/rtl8723bs/include/rtw_cmd.h
+++ b/drivers/staging/rtl8723bs/include/rtw_cmd.h
@@ -550,9 +550,6 @@ struct RunInThread_param {
};
-#define GEN_CMD_CODE(cmd) cmd ## _CMD_
-
-
/*
Result:
@@ -628,86 +625,81 @@ struct _cmd_callback {
};
enum {
- GEN_CMD_CODE(_Read_MACREG), /*0*/
- GEN_CMD_CODE(_Write_MACREG),
- GEN_CMD_CODE(_Read_BBREG),
- GEN_CMD_CODE(_Write_BBREG),
- GEN_CMD_CODE(_Read_RFREG),
- GEN_CMD_CODE(_Write_RFREG), /*5*/
- GEN_CMD_CODE(_Read_EEPROM),
- GEN_CMD_CODE(_Write_EEPROM),
- GEN_CMD_CODE(_Read_EFUSE),
- GEN_CMD_CODE(_Write_EFUSE),
-
- GEN_CMD_CODE(_Read_CAM), /*10*/
- GEN_CMD_CODE(_Write_CAM),
- GEN_CMD_CODE(_setBCNITV),
- GEN_CMD_CODE(_setMBIDCFG),
- GEN_CMD_CODE(_JoinBss), /*14*/
- GEN_CMD_CODE(_DisConnect), /*15*/
- GEN_CMD_CODE(_CreateBss),
- GEN_CMD_CODE(_SetOpMode),
- GEN_CMD_CODE(_SiteSurvey), /*18*/
- GEN_CMD_CODE(_SetAuth),
-
- GEN_CMD_CODE(_SetKey), /*20*/
- GEN_CMD_CODE(_SetStaKey),
- GEN_CMD_CODE(_SetAssocSta),
- GEN_CMD_CODE(_DelAssocSta),
- GEN_CMD_CODE(_SetStaPwrState),
- GEN_CMD_CODE(_SetBasicRate), /*25*/
- GEN_CMD_CODE(_GetBasicRate),
- GEN_CMD_CODE(_SetDataRate),
- GEN_CMD_CODE(_GetDataRate),
- GEN_CMD_CODE(_SetPhyInfo),
-
- GEN_CMD_CODE(_GetPhyInfo), /*30*/
- GEN_CMD_CODE(_SetPhy),
- GEN_CMD_CODE(_GetPhy),
- GEN_CMD_CODE(_readRssi),
- GEN_CMD_CODE(_readGain),
- GEN_CMD_CODE(_SetAtim), /*35*/
- GEN_CMD_CODE(_SetPwrMode),
- GEN_CMD_CODE(_JoinbssRpt),
- GEN_CMD_CODE(_SetRaTable),
- GEN_CMD_CODE(_GetRaTable),
-
- GEN_CMD_CODE(_GetCCXReport), /*40*/
- GEN_CMD_CODE(_GetDTMReport),
- GEN_CMD_CODE(_GetTXRateStatistics),
- GEN_CMD_CODE(_SetUsbSuspend),
- GEN_CMD_CODE(_SetH2cLbk),
- GEN_CMD_CODE(_AddBAReq), /*45*/
- GEN_CMD_CODE(_SetChannel), /*46*/
- GEN_CMD_CODE(_SetTxPower),
- GEN_CMD_CODE(_SwitchAntenna),
- GEN_CMD_CODE(_SetCrystalCap),
- GEN_CMD_CODE(_SetSingleCarrierTx), /*50*/
-
- GEN_CMD_CODE(_SetSingleToneTx),/*51*/
- GEN_CMD_CODE(_SetCarrierSuppressionTx),
- GEN_CMD_CODE(_SetContinuousTx),
- GEN_CMD_CODE(_SwitchBandwidth), /*54*/
- GEN_CMD_CODE(_TX_Beacon), /*55*/
-
- GEN_CMD_CODE(_Set_MLME_EVT), /*56*/
- GEN_CMD_CODE(_Set_Drv_Extra), /*57*/
- GEN_CMD_CODE(_Set_H2C_MSG), /*58*/
-
- GEN_CMD_CODE(_SetChannelPlan), /*59*/
-
- GEN_CMD_CODE(_SetChannelSwitch), /*60*/
- GEN_CMD_CODE(_TDLS), /*61*/
- GEN_CMD_CODE(_ChkBMCSleepq), /*62*/
-
- GEN_CMD_CODE(_RunInThreadCMD), /*63*/
+ READ_MACREG_CMD, /*0*/
+ WRITE_MACREG_CMD,
+ READ_BBREG_CMD,
+ WRITE_BBREG_CMD,
+ READ_RFREG_CMD,
+ WRITE_RFREG_CMD, /*5*/
+ READ_EEPROM_CMD,
+ WRITE_EEPROM_CMD,
+ READ_EFUSE_CMD,
+ WRITE_EFUSE_CMD,
+
+ READ_CAM_CMD, /*10*/
+ WRITE_CAM_CMD,
+ SET_BCNITV_CMD,
+ SET_MBIDCFG_CMD,
+ JOIN_BSS_CMD, /*14*/
+ DISCONNECT_CMD, /*15*/
+ CREATE_BSS_CMD,
+ SET_OP_MODE_CMD,
+ SITE_SURVEY_CMD, /*18*/
+ SET_AUTH_CMD,
+
+ SET_KEY_CMD, /*20*/
+ SET_STA_KEY_CMD,
+ SET_ASSOC_STA_CMD,
+ DEL_ASSOC_STA_CMD,
+ SET_STA_PWR_STATE_CMD,
+ SET_BASIC_RATE_CMD, /*25*/
+ GET_BASIC_RATE_CMD,
+ SET_DATA_RATE_CMD,
+ GET_DATA_RATE_CMD,
+ SET_PHY_INFO_CMD,
+
+ GET_PHY_INFO_CMD, /*30*/
+ SET_PHY_CMD,
+ GET_PHY_CMD,
+ READ_RSSI_CMD,
+ READ_GAIN_CMD,
+ SET_ATIM_CMD, /*35*/
+ SET_PWR_MODE_CMD,
+ JOIN_BSS_RPT_CMD,
+ SET_RA_TABLE_CMD,
+ GET_RA_TABLE_CMD,
+
+ GET_CCX_REPORT_CMD, /*40*/
+ GET_DTM_REPORT_CMD,
+ GET_TX_RATE_STATISTICS_CMD,
+ SET_USB_SUSPEND_CMD,
+ SET_H2C_LBK_CMD,
+ ADD_BA_REQ_CMD, /*45*/
+ SET_CHANNEL_CMD, /*46*/
+ SET_TX_POWER_CMD,
+ SWITCH_ANTENNA_CMD,
+ SET_CRYSTAL_CAP_CMD,
+ SET_SINGLE_CARRIER_TX_CMD, /*50*/
+
+ SET_SINGLE_TONE_TX_CMD, /*51*/
+ SET_CARRIER_SUPPRESSION_TX_CMD,
+ SET_CONTINUOUS_TX_CMD,
+ SWITCH_BANDWIDTH_CMD, /*54*/
+ TX_BEACON_CMD, /*55*/
+
+ SET_MLME_EVT_CMD, /*56*/
+ SET_DRV_EXTRA_CMD, /*57*/
+ SET_H2C_MSG_CMD, /*58*/
+
+ SET_CHANNEL_PLAN_CMD, /*59*/
+
+ SET_CHANNEL_SWITCH_CMD, /*60*/
+ TDLS_CMD, /*61*/
+ CHK_BMC_SLEEPQ_CMD, /*62*/
+
+ RUN_IN_THREAD_CMD, /*63*/
MAX_H2CCMD
};
-#define _GetBBReg_CMD_ _Read_BBREG_CMD_
-#define _SetBBReg_CMD_ _Write_BBREG_CMD_
-#define _GetRFReg_CMD_ _Read_RFREG_CMD_
-#define _SetRFReg_CMD_ _Write_RFREG_CMD_
-
#endif /* __RTW_CMD_H_ */
diff --git a/drivers/staging/rtl8723bs/include/rtw_event.h b/drivers/staging/rtl8723bs/include/rtw_event.h
index 62e0dec249ad..e5cb46c2a731 100644
--- a/drivers/staging/rtl8723bs/include/rtw_event.h
+++ b/drivers/staging/rtl8723bs/include/rtw_event.h
@@ -64,10 +64,6 @@ struct wmm_event {
unsigned char wmm;
};
-#define GEN_EVT_CODE(event) event ## _EVT_
-
-
-
struct fwevent {
u32 parmsize;
void (*event_callback)(struct adapter *dev, u8 *pbuf);
diff --git a/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h b/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h
index 786dc805516e..bf5a7e9dbe0e 100644
--- a/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h
+++ b/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h
@@ -675,33 +675,33 @@ void rtw_dummy_event_callback(struct adapter *adapter, u8 *pbuf);
void rtw_fwdbg_event_callback(struct adapter *adapter, u8 *pbuf);
enum {
- GEN_EVT_CODE(_Read_MACREG) = 0, /*0*/
- GEN_EVT_CODE(_Read_BBREG),
- GEN_EVT_CODE(_Read_RFREG),
- GEN_EVT_CODE(_Read_EEPROM),
- GEN_EVT_CODE(_Read_EFUSE),
- GEN_EVT_CODE(_Read_CAM), /*5*/
- GEN_EVT_CODE(_Get_BasicRate),
- GEN_EVT_CODE(_Get_DataRate),
- GEN_EVT_CODE(_Survey), /*8*/
- GEN_EVT_CODE(_SurveyDone), /*9*/
-
- GEN_EVT_CODE(_JoinBss), /*10*/
- GEN_EVT_CODE(_AddSTA),
- GEN_EVT_CODE(_DelSTA),
- GEN_EVT_CODE(_AtimDone),
- GEN_EVT_CODE(_TX_Report),
- GEN_EVT_CODE(_CCX_Report), /*15*/
- GEN_EVT_CODE(_DTM_Report),
- GEN_EVT_CODE(_TX_Rate_Statistics),
- GEN_EVT_CODE(_C2HLBK),
- GEN_EVT_CODE(_FWDBG),
- GEN_EVT_CODE(_C2HFEEDBACK), /*20*/
- GEN_EVT_CODE(_ADDBA),
- GEN_EVT_CODE(_C2HBCN),
- GEN_EVT_CODE(_ReportPwrState), /* filen: only for PCIE, USB */
- GEN_EVT_CODE(_CloseRF), /* filen: only for PCIE, work around ASPM */
- GEN_EVT_CODE(_WMM), /*25*/
+ READ_MACREG_EVENT = 0, /*0*/
+ READ_BBREG_EVENT,
+ READ_RFREG_EVENT,
+ READ_EEPROM_EVENT,
+ READ_EFUSE_EVENT,
+ READ_CAM_EVENT, /*5*/
+ GET_BASICRATE_EVENT,
+ GET_DATARATE_EVENT,
+ SURVEY_EVENT, /*8*/
+ SURVEY_DONE_EVENT, /*9*/
+
+ JOIN_BSS_EVENT, /*10*/
+ ADD_STA_EVENT,
+ DEL_STA_EVENT,
+ ATIM_DONE_EVENT,
+ TX_REPORT_EVENT,
+ CCX_REPORT_EVENT, /*15*/
+ DTM_REPORT_EVENT,
+ TX_RATE_STATISTICS_EVENT,
+ C2HLBK_EVENT,
+ FWDBG_EVENT,
+ C2HFEEDBACK_EVENT, /*20*/
+ ADDBA_EVENT,
+ C2HBCN_EVENT,
+ REPORT_PWR_STATE_EVENT, /* filen: only for PCIE, USB */
+ CLOSE_RF_EVENT, /* filen: only for PCIE, work around ASPM */
+ WMM_EVENT, /*25*/
MAX_C2HEVT
};
diff --git a/drivers/staging/rtl8723bs/include/wifi.h b/drivers/staging/rtl8723bs/include/wifi.h
index c8844e2bf7b4..d5132bc4280a 100644
--- a/drivers/staging/rtl8723bs/include/wifi.h
+++ b/drivers/staging/rtl8723bs/include/wifi.h
@@ -329,21 +329,21 @@ static inline int IsFrameTypeCtrl(unsigned char *pframe)
*/
struct ieee80211_ht_addt_info {
unsigned char control_chan;
- unsigned char ht_param;
- __le16 operation_mode;
- __le16 stbc_param;
- unsigned char basic_set[16];
+ unsigned char ht_param;
+ __le16 operation_mode;
+ __le16 stbc_param;
+ unsigned char basic_set[16];
} __packed;
struct HT_caps_element {
union {
struct {
- __le16 HT_caps_info;
+ __le16 HT_caps_info;
unsigned char AMPDU_para;
unsigned char MCS_rate[16];
- __le16 HT_ext_caps;
- __le16 Beamforming_caps;
+ __le16 HT_ext_caps;
+ __le16 Beamforming_caps;
unsigned char ASEL_caps;
} HT_cap_element;
unsigned char HT_cap[26];
@@ -357,22 +357,22 @@ struct HT_info_element {
} __packed;
struct AC_param {
- unsigned char ACI_AIFSN;
- unsigned char CW;
- __le16 TXOP_limit;
+ unsigned char ACI_AIFSN;
+ unsigned char CW;
+ __le16 TXOP_limit;
} __packed;
struct WMM_para_element {
- unsigned char QoS_info;
- unsigned char reserved;
- struct AC_param ac_param[4];
+ unsigned char QoS_info;
+ unsigned char reserved;
+ struct AC_param ac_param[4];
} __packed;
struct ADDBA_request {
- unsigned char dialog_token;
- __le16 BA_para_set;
- __le16 BA_timeout_value;
- __le16 BA_starting_seqctrl;
+ unsigned char dialog_token;
+ __le16 BA_para_set;
+ __le16 BA_timeout_value;
+ __le16 BA_starting_seqctrl;
} __packed;
/* 802.11n HT capabilities masks */
diff --git a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c
index a2e49b38ab5a..7c8d912dd462 100644
--- a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c
+++ b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c
@@ -334,9 +334,8 @@ static void rtw_sdio_if1_deinit(struct adapter *if1)
* notes: drv_init() is called when the bus driver has located a card for us to support.
* We accept the new device by returning 0.
*/
-static int rtw_drv_init(
- struct sdio_func *func,
- const struct sdio_device_id *id)
+static int rtw_drv_init(struct sdio_func *func,
+ const struct sdio_device_id *id)
{
int status = _FAIL;
struct adapter *if1 = NULL;
diff --git a/drivers/thermal/db8500_thermal.c b/drivers/thermal/db8500_thermal.c
index 576f88b6a1b3..cf1706569e6d 100644
--- a/drivers/thermal/db8500_thermal.c
+++ b/drivers/thermal/db8500_thermal.c
@@ -10,7 +10,7 @@
#include <linux/cpu_cooling.h>
#include <linux/interrupt.h>
-#include <linux/mfd/dbx500-prcmu.h>
+#include <linux/mfd/db8500-prcmu.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
@@ -82,7 +82,7 @@ static void db8500_thermal_update_config(struct db8500_thermal_zone *th,
unsigned long next_low,
unsigned long next_high)
{
- prcmu_stop_temp_sense();
+ db8500_prcmu_stop_temp_sense();
th->cur_index = idx;
th->interpolated_temp = (next_low + next_high)/2;
@@ -91,8 +91,8 @@ static void db8500_thermal_update_config(struct db8500_thermal_zone *th,
* The PRCMU accept absolute temperatures in celsius so divide
* down the millicelsius with 1000
*/
- prcmu_config_hotmon((u8)(next_low/1000), (u8)(next_high/1000));
- prcmu_start_temp_sense(PRCMU_DEFAULT_MEASURE_TIME);
+ db8500_prcmu_config_hotmon((u8)(next_low / 1000), (u8)(next_high / 1000));
+ db8500_prcmu_start_temp_sense(PRCMU_DEFAULT_MEASURE_TIME);
}
static irqreturn_t prcmu_low_irq_handler(int irq, void *irq_data)
@@ -204,7 +204,7 @@ static int db8500_thermal_probe(struct platform_device *pdev)
static int db8500_thermal_suspend(struct platform_device *pdev,
pm_message_t state)
{
- prcmu_stop_temp_sense();
+ db8500_prcmu_stop_temp_sense();
return 0;
}
diff --git a/drivers/thermal/qcom/qcom-spmi-adc-tm5.c b/drivers/thermal/qcom/qcom-spmi-adc-tm5.c
index d7f2e6ca92c2..bb6222c8cc5f 100644
--- a/drivers/thermal/qcom/qcom-spmi-adc-tm5.c
+++ b/drivers/thermal/qcom/qcom-spmi-adc-tm5.c
@@ -1069,3 +1069,4 @@ module_platform_driver(adc_tm5_driver);
MODULE_DESCRIPTION("SPMI PMIC Thermal Monitor ADC driver");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/thermal/qcom/qcom-spmi-temp-alarm.c b/drivers/thermal/qcom/qcom-spmi-temp-alarm.c
index f39ca0ddd17b..fb003ca96454 100644
--- a/drivers/thermal/qcom/qcom-spmi-temp-alarm.c
+++ b/drivers/thermal/qcom/qcom-spmi-temp-alarm.c
@@ -904,3 +904,4 @@ module_platform_driver(qpnp_tm_driver);
MODULE_ALIAS("platform:spmi-temp-alarm");
MODULE_DESCRIPTION("QPNP PMIC Temperature Alarm driver");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/thermal/renesas/rzg3s_thermal.c b/drivers/thermal/renesas/rzg3s_thermal.c
index e25e36c99a88..7ced8f76a0ec 100644
--- a/drivers/thermal/renesas/rzg3s_thermal.c
+++ b/drivers/thermal/renesas/rzg3s_thermal.c
@@ -270,3 +270,4 @@ module_platform_driver(rzg3s_thermal_driver);
MODULE_DESCRIPTION("Renesas RZ/G3S Thermal Sensor Unit Driver");
MODULE_AUTHOR("Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/thermal/thermal-generic-adc.c b/drivers/thermal/thermal-generic-adc.c
index 7c844589b153..cfdb8e674dd2 100644
--- a/drivers/thermal/thermal-generic-adc.c
+++ b/drivers/thermal/thermal-generic-adc.c
@@ -228,3 +228,4 @@ module_platform_driver(gadc_thermal_driver);
MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
MODULE_DESCRIPTION("Generic ADC thermal driver using IIO framework with DT");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c
index 81eaca751541..28af0fd98181 100644
--- a/drivers/tty/amiserial.c
+++ b/drivers/tty/amiserial.c
@@ -443,23 +443,23 @@ static int rs_startup(struct tty_struct *tty, struct serial_state *info)
struct tty_port *port = &info->tport;
unsigned long flags;
int retval=0;
- unsigned long page;
+ void *buffer;
- page = get_zeroed_page(GFP_KERNEL);
- if (!page)
+ buffer = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buffer)
return -ENOMEM;
local_irq_save(flags);
if (tty_port_initialized(port)) {
- free_page(page);
+ kfree(buffer);
goto errout;
}
if (info->xmit.buf)
- free_page(page);
+ kfree(buffer);
else
- info->xmit.buf = (unsigned char *) page;
+ info->xmit.buf = buffer;
#ifdef SERIAL_DEBUG_OPEN
printk("starting up ttys%d ...", info->line);
@@ -537,7 +537,7 @@ static void rs_shutdown(struct tty_struct *tty, struct serial_state *info)
*/
free_irq(IRQ_AMIGA_VERTB, info);
- free_page((unsigned long)info->xmit.buf);
+ kfree(info->xmit.buf);
info->xmit.buf = NULL;
info->IER = 0;
diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c
index c682c0d0dffa..f9a14eaa13cb 100644
--- a/drivers/tty/serial/8250/8250_exar.c
+++ b/drivers/tty/serial/8250/8250_exar.c
@@ -1642,14 +1642,14 @@ static const struct exar8250_board pbn_exar_XR17V8358 = {
.exit = pci_xr17v35x_exit,
};
-#define CTI_EXAR_DEVICE(devid, bd) { \
- PCI_DEVICE_SUB( \
- PCI_VENDOR_ID_EXAR, \
- PCI_DEVICE_ID_EXAR_##devid, \
- PCI_SUBVENDOR_ID_CONNECT_TECH, \
- PCI_ANY_ID), 0, 0, \
- (kernel_ulong_t)&bd \
- }
+#define CTI_EXAR_DEVICE(devid, bd) { \
+ PCI_DEVICE_SUB( \
+ PCI_VENDOR_ID_EXAR, \
+ PCI_DEVICE_ID_EXAR_##devid, \
+ PCI_SUBVENDOR_ID_CONNECT_TECH, \
+ PCI_ANY_ID), \
+ .driver_data = (kernel_ulong_t)&bd \
+}
#define EXAR_DEVICE(vend, devid, bd) { PCI_DEVICE_DATA(vend, devid, &bd) }
@@ -1658,18 +1658,18 @@ static const struct exar8250_board pbn_exar_XR17V8358 = {
PCI_VENDOR_ID_EXAR, \
PCI_DEVICE_ID_EXAR_##devid, \
PCI_SUBVENDOR_ID_IBM, \
- PCI_SUBDEVICE_ID_IBM_##sdevid), 0, 0, \
- (kernel_ulong_t)&bd \
- }
+ PCI_SUBDEVICE_ID_IBM_##sdevid), \
+ .driver_data = (kernel_ulong_t)&bd \
+}
#define USR_DEVICE(devid, sdevid, bd) { \
PCI_DEVICE_SUB( \
PCI_VENDOR_ID_USR, \
PCI_DEVICE_ID_EXAR_##devid, \
PCI_VENDOR_ID_EXAR, \
- PCI_SUBDEVICE_ID_USR_##sdevid), 0, 0, \
- (kernel_ulong_t)&bd \
- }
+ PCI_SUBDEVICE_ID_USR_##sdevid), \
+ .driver_data = (kernel_ulong_t)&bd \
+}
static const struct pci_device_id exar_pci_tbl[] = {
EXAR_DEVICE(ACCESSIO, COM_2S, pbn_exar_XR17C15x),
@@ -1726,7 +1726,7 @@ static const struct pci_device_id exar_pci_tbl[] = {
EXAR_DEVICE(COMMTECH, 4224PCI335, pbn_fastcom335_4),
EXAR_DEVICE(COMMTECH, 2324PCI335, pbn_fastcom335_4),
EXAR_DEVICE(COMMTECH, 2328PCI335, pbn_fastcom335_8),
- { 0, }
+ { }
};
MODULE_DEVICE_TABLE(pci, exar_pci_tbl);
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index 5fe12577ce8b..6bda58f74acf 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -1400,17 +1400,12 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
dev_dbg(dev, "Reference clock set to %i Hz\n", uartclk);
+ /*
+ * Set up each port's state before registering the gpiochip,
+ * since the gpiochip callbacks will read s->p[i].regmap as
+ * soon as gpiolib exposes the controller.
+ */
for (i = 0; i < devtype->nr; i++) {
- unsigned int line;
-
- line = find_first_zero_bit(max310x_lines, MAX310X_UART_NRMAX);
- if (line == MAX310X_UART_NRMAX) {
- ret = -ERANGE;
- goto out_uart;
- }
-
- /* Initialize port data */
- s->p[i].port.line = line;
s->p[i].port.dev = dev;
s->p[i].port.irq = irq;
s->p[i].port.type = PORT_MAX310X;
@@ -1440,20 +1435,16 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
INIT_WORK(&s->p[i].md_work, max310x_md_proc);
/* Initialize queue for changing RS485 mode */
INIT_WORK(&s->p[i].rs_work, max310x_rs_proc);
-
- /* Register port */
- ret = uart_add_one_port(&max310x_uart, &s->p[i].port);
- if (ret)
- goto out_uart;
-
- set_bit(line, max310x_lines);
-
- /* Go to suspend mode */
- max310x_power(&s->p[i].port, 0);
}
#ifdef CONFIG_GPIOLIB
- /* Setup GPIO controller */
+ /*
+ * Register the GPIO controller before adding the UART ports so
+ * that consumers referencing the chip's own GPIOs from device
+ * tree (for example rs485-term-gpios = <&max310x ...>) can
+ * resolve them at uart_add_one_port() time instead of receiving
+ * -EPROBE_DEFER from their own provider.
+ */
s->gpio.owner = THIS_MODULE;
s->gpio.parent = dev;
s->gpio.label = devtype->name;
@@ -1471,6 +1462,64 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
goto out_uart;
#endif
+ for (i = 0; i < devtype->nr; i++) {
+ struct fwnode_handle *saved_fwnode = dev_fwnode(dev);
+ struct device_node *port_np = NULL;
+ struct device_node *child;
+ unsigned int line;
+
+ line = find_first_zero_bit(max310x_lines, MAX310X_UART_NRMAX);
+ if (line == MAX310X_UART_NRMAX) {
+ ret = -ERANGE;
+ goto out_uart;
+ }
+ s->p[i].port.line = line;
+
+ /* Locate the matching "serial@i" DT subnode, if any. */
+ for_each_available_child_of_node(dev->of_node, child) {
+ u32 reg;
+
+ if (!of_node_name_eq(child, "serial"))
+ continue;
+ if (of_property_read_u32(child, "reg", &reg))
+ continue;
+ if (reg == i) {
+ port_np = child;
+ break;
+ }
+ }
+
+ /*
+ * Temporarily retarget dev's fwnode to the per-port subnode
+ * so uart_get_rs485_mode() picks up the per-port properties.
+ * For single-port variants, fall back to the chip's own
+ * fwnode so legacy DTs that declare rs485 properties at the
+ * top level keep working.
+ */
+ if (port_np) {
+ device_set_node(dev, of_fwnode_handle(port_np));
+ ret = uart_get_rs485_mode(&s->p[i].port);
+ device_set_node(dev, saved_fwnode);
+ of_node_put(port_np);
+ if (ret)
+ goto out_uart;
+ } else if (devtype->nr == 1) {
+ ret = uart_get_rs485_mode(&s->p[i].port);
+ if (ret)
+ goto out_uart;
+ }
+
+ /* Register port */
+ ret = uart_add_one_port(&max310x_uart, &s->p[i].port);
+ if (ret)
+ goto out_uart;
+
+ set_bit(line, max310x_lines);
+
+ /* Go to suspend mode */
+ max310x_power(&s->p[i].port, 0);
+ }
+
/* Setup interrupt */
ret = devm_request_threaded_irq(dev, irq, NULL, max310x_ist,
IRQF_ONESHOT | IRQF_SHARED, dev_name(dev), s);
diff --git a/drivers/tty/serial/men_z135_uart.c b/drivers/tty/serial/men_z135_uart.c
index 6fad57fee912..9138fa29d301 100644
--- a/drivers/tty/serial/men_z135_uart.c
+++ b/drivers/tty/serial/men_z135_uart.c
@@ -16,6 +16,7 @@
#include <linux/tty_flip.h>
#include <linux/bitops.h>
#include <linux/mcb.h>
+#include <linux/slab.h>
#define MEN_Z135_MAX_PORTS 12
#define MEN_Z135_BASECLK 29491200
@@ -811,7 +812,7 @@ static int men_z135_probe(struct mcb_device *mdev,
if (!uart)
return -ENOMEM;
- uart->rxbuf = (unsigned char *)__get_free_page(GFP_KERNEL);
+ uart->rxbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!uart->rxbuf)
return -ENOMEM;
@@ -841,7 +842,7 @@ static int men_z135_probe(struct mcb_device *mdev,
return 0;
err:
- free_page((unsigned long) uart->rxbuf);
+ kfree(uart->rxbuf);
dev_err(dev, "Failed to add UART: %d\n", err);
return err;
@@ -858,7 +859,7 @@ static void men_z135_remove(struct mcb_device *mdev)
line--;
uart_remove_one_port(&men_z135_driver, &uart->port);
- free_page((unsigned long) uart->rxbuf);
+ kfree(uart->rxbuf);
}
static const struct mcb_device_id men_z135_ids[] = {
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index 80e31c4d9536..5f7f073f285e 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -1662,7 +1662,7 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
if (priv == NULL)
goto init_port_alloc_err;
- rxbuf = (unsigned char *)__get_free_page(GFP_KERNEL);
+ rxbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!rxbuf)
goto init_port_free_txbuf;
@@ -1735,7 +1735,7 @@ init_port_hal_free:
#ifdef CONFIG_SERIAL_PCH_UART_CONSOLE
pch_uart_ports[board->line_no] = NULL;
#endif
- free_page((unsigned long)rxbuf);
+ kfree(rxbuf);
init_port_free_txbuf:
kfree(priv);
init_port_alloc_err:
@@ -1750,7 +1750,7 @@ static void pch_uart_exit_port(struct eg20t_port *priv)
snprintf(name, sizeof(name), "uart%d_regs", priv->port.line);
debugfs_lookup_and_remove(name, NULL);
uart_remove_one_port(&pch_uart_driver, &priv->port);
- free_page((unsigned long)priv->rxbuf.buf);
+ kfree(priv->rxbuf.buf);
}
static void pch_uart_pci_remove(struct pci_dev *pdev)
diff --git a/drivers/tty/serial/rp2.c b/drivers/tty/serial/rp2.c
index 6d99a02dd439..51e81ec0ffdb 100644
--- a/drivers/tty/serial/rp2.c
+++ b/drivers/tty/serial/rp2.c
@@ -197,7 +197,7 @@ struct rp2_card {
};
#define RP_ID(prod) PCI_VDEVICE(RP, (prod))
-#define RP_CAP(ports, smpte) (((ports) << 8) | ((smpte) << 0))
+#define RP_CAP(ports, smpte) .driver_data = (((ports) << 8) | ((smpte) << 0))
static inline void rp2_decode_cap(const struct pci_device_id *id,
int *ports, int *smpte)
diff --git a/drivers/tty/tty_jobctrl.c b/drivers/tty/tty_jobctrl.c
index ef8741c3e662..37929fb56174 100644
--- a/drivers/tty/tty_jobctrl.c
+++ b/drivers/tty/tty_jobctrl.c
@@ -506,29 +506,23 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
if (pgrp_nr < 0)
return -EINVAL;
- spin_lock_irq(&real_tty->ctrl.lock);
+ guard(spinlock_irq)(&real_tty->ctrl.lock);
if (!current->signal->tty ||
(current->signal->tty != real_tty) ||
- (real_tty->ctrl.session != task_session(current))) {
- retval = -ENOTTY;
- goto out_unlock_ctrl;
- }
- rcu_read_lock();
+ (real_tty->ctrl.session != task_session(current)))
+ return -ENOTTY;
+
+ guard(rcu)();
pgrp = find_vpid(pgrp_nr);
- retval = -ESRCH;
if (!pgrp)
- goto out_unlock;
- retval = -EPERM;
+ return -ESRCH;
if (session_of_pgrp(pgrp) != task_session(current))
- goto out_unlock;
- retval = 0;
+ return -EPERM;
+
put_pid(real_tty->ctrl.pgrp);
real_tty->ctrl.pgrp = get_pid(pgrp);
-out_unlock:
- rcu_read_unlock();
-out_unlock_ctrl:
- spin_unlock_irq(&real_tty->ctrl.lock);
- return retval;
+
+ return 0;
}
/**
@@ -542,7 +536,6 @@ out_unlock_ctrl:
*/
static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
{
- unsigned long flags;
pid_t sid;
/*
@@ -552,17 +545,13 @@ static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t _
if (tty == real_tty && current->signal->tty != real_tty)
return -ENOTTY;
- spin_lock_irqsave(&real_tty->ctrl.lock, flags);
- if (!real_tty->ctrl.session)
- goto err;
- sid = pid_vnr(real_tty->ctrl.session);
- spin_unlock_irqrestore(&real_tty->ctrl.lock, flags);
+ scoped_guard(spinlock_irqsave, &real_tty->ctrl.lock) {
+ if (!real_tty->ctrl.session)
+ return -ENOTTY;
+ sid = pid_vnr(real_tty->ctrl.session);
+ }
return put_user(sid, p);
-
-err:
- spin_unlock_irqrestore(&real_tty->ctrl.lock, flags);
- return -ENOTTY;
}
/*
diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c
index 7d40eacc21b3..bf1502fd5bd4 100644
--- a/drivers/tty/vt/vc_screen.c
+++ b/drivers/tty/vt/vc_screen.c
@@ -53,8 +53,6 @@
#define HEADER_SIZE 4u
#define CON_BUF_SIZE (IS_ENABLED(CONFIG_BASE_SMALL) ? 256 : PAGE_SIZE)
-DEFINE_FREE(free_page_ptr, void *, if (_T) free_page((unsigned long)_T));
-
/*
* Our minor space:
*
@@ -371,7 +369,7 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
loff_t pos;
bool viewed, attr, uni_mode;
- char *con_buf __free(free_page_ptr) = (char *)__get_free_page(GFP_KERNEL);
+ char *con_buf __free(kfree) = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!con_buf)
return -ENOMEM;
@@ -596,7 +594,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
if (use_unicode(inode))
return -EOPNOTSUPP;
- char *con_buf __free(free_page_ptr) = (char *)__get_free_page(GFP_KERNEL);
+ char *con_buf __free(kfree) = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!con_buf)
return -ENOMEM;
diff --git a/drivers/usb/cdns3/cdns3-plat.c b/drivers/usb/cdns3/cdns3-plat.c
index bb5405460035..e3f32c3e9535 100644
--- a/drivers/usb/cdns3/cdns3-plat.c
+++ b/drivers/usb/cdns3/cdns3-plat.c
@@ -147,12 +147,12 @@ static int cdns3_plat_probe(struct platform_device *pdev)
cdns->usb2_phy = devm_phy_optional_get(dev, "cdns3,usb2-phy");
if (IS_ERR(cdns->usb2_phy))
return dev_err_probe(dev, PTR_ERR(cdns->usb2_phy),
- "Failed to get cdn3,usb2-phy\n");
+ "Failed to get cdns3,usb2-phy\n");
cdns->usb3_phy = devm_phy_optional_get(dev, "cdns3,usb3-phy");
if (IS_ERR(cdns->usb3_phy))
return dev_err_probe(dev, PTR_ERR(cdns->usb3_phy),
- "Failed to get cdn3,usb3-phy\n");
+ "Failed to get cdns3,usb3-phy\n");
ret = phy_init(cdns->usb2_phy);
if (ret)
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
index a247da73f34d..6f0354aba38b 100644
--- a/drivers/usb/core/devices.c
+++ b/drivers/usb/core/devices.c
@@ -37,6 +37,7 @@
*/
#include <linux/fs.h>
+#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/gfp.h>
#include <linux/usb.h>
@@ -408,7 +409,7 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes,
return 0;
/* allocate 2^1 pages = 8K (on i386);
* should be more than enough for one device */
- pages_start = (char *)__get_free_pages(GFP_NOIO, 1);
+ pages_start = kmalloc(PAGE_SIZE << 1, GFP_NOIO);
if (!pages_start)
return -ENOMEM;
@@ -479,7 +480,7 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes,
if (length > *nbytes)
length = *nbytes;
if (copy_to_user(*buffer, pages_start + *skip_bytes, length)) {
- free_pages((unsigned long)pages_start, 1);
+ kfree(pages_start);
return -EFAULT;
}
*nbytes -= length;
@@ -490,7 +491,7 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes,
} else
*skip_bytes -= length;
- free_pages((unsigned long)pages_start, 1);
+ kfree(pages_start);
/* Now look at all of this device's children. */
usb_hub_for_each_child(usbdev, chix, childdev) {
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 24960ba9caa9..5262e11c12cd 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -3148,7 +3148,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
delay = HUB_LONG_RESET_TIME;
}
- dev_err(&port_dev->dev, "Cannot enable. Maybe the USB cable is bad?\n");
+ dev_err_ratelimited(&port_dev->dev, "Cannot enable. Maybe the USB cable is bad?\n");
done:
if (status == 0) {
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 517aa7f1486d..fd5c2cd36c59 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -789,9 +789,9 @@ static void dwc3_ulpi_setup(struct dwc3 *dwc)
if (dwc->enable_usb2_transceiver_delay) {
for (index = 0; index < dwc->num_usb2_ports; index++) {
- reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(index));
+ reg = dwc3_readl(dwc, DWC3_GUSB2PHYCFG(index));
reg |= DWC3_GUSB2PHYCFG_XCVRDLY;
- dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(index), reg);
+ dwc3_writel(dwc, DWC3_GUSB2PHYCFG(index), reg);
}
}
}
@@ -2188,22 +2188,89 @@ static void dwc3_vbus_draw_work(struct work_struct *work)
ret, dwc->current_limit);
}
-static struct power_supply *dwc3_get_usb_power_supply(struct dwc3 *dwc)
+static int dwc3_psy_notifier(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ struct dwc3 *dwc = container_of(nb, struct dwc3, psy_nb);
+ struct power_supply *psy = data;
+ unsigned long flags;
+
+ if (dwc->usb_psy)
+ return NOTIFY_DONE;
+
+ if (strcmp(psy->desc->name, dwc->usb_psy_name) != 0)
+ return NOTIFY_DONE;
+
+ /* Explicitly get the reference for this psy */
+ psy = power_supply_get_by_name(dwc->usb_psy_name);
+ if (!psy)
+ return NOTIFY_DONE;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+ /*
+ * The USB power_supply may already be set. This can happen if notifier
+ * callbacks for the USB power_supply race, or if a previous notifier
+ * callback has already successfully fetched and associated the instance.
+ * In such cases, release the newly acquired reference and ignore
+ * subsequent notifications until the notifier is unregistered.
+ */
+ if (dwc->usb_psy) {
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ power_supply_put(psy);
+ return NOTIFY_DONE;
+ }
+
+ dwc->usb_psy = psy;
+ if (dwc->current_limit != DWC3_CURRENT_UNSPECIFIED)
+ schedule_work(&dwc->vbus_draw_work);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return NOTIFY_OK;
+}
+
+static void dwc3_get_usb_power_supply(struct dwc3 *dwc)
{
- struct power_supply *usb_psy;
- const char *usb_psy_name;
+ struct power_supply *psy;
+ unsigned long flags;
int ret;
- ret = device_property_read_string(dwc->dev, "usb-psy-name", &usb_psy_name);
+ ret = device_property_read_string(dwc->dev, "usb-psy-name", &dwc->usb_psy_name);
if (ret < 0)
- return NULL;
-
- usb_psy = power_supply_get_by_name(usb_psy_name);
- if (!usb_psy)
- return ERR_PTR(-EPROBE_DEFER);
+ return;
INIT_WORK(&dwc->vbus_draw_work, dwc3_vbus_draw_work);
- return usb_psy;
+
+ dwc->current_limit = DWC3_CURRENT_UNSPECIFIED;
+ dwc->psy_nb.notifier_call = dwc3_psy_notifier;
+ ret = power_supply_reg_notifier(&dwc->psy_nb);
+ if (ret) {
+ dev_err(dwc->dev, "Failed to register power supply notifier: %d\n", ret);
+ dwc->psy_nb.notifier_call = NULL;
+ return;
+ }
+
+ psy = power_supply_get_by_name(dwc->usb_psy_name);
+ if (!psy)
+ return;
+
+ /* Unregister the notifier now that we have the power supply */
+ power_supply_unreg_notifier(&dwc->psy_nb);
+ dwc->psy_nb.notifier_call = NULL;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+ /*
+ * It is possible that the notifier callback ran before we reached here
+ * and successfully fetched the power supply. In that case we need to
+ * release the above reference.
+ */
+ if (dwc->usb_psy) {
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ power_supply_put(psy);
+ return;
+ }
+
+ dwc->usb_psy = psy;
+ spin_unlock_irqrestore(&dwc->lock, flags);
}
int dwc3_core_probe(const struct dwc3_probe_data *data)
@@ -2251,9 +2318,9 @@ int dwc3_core_probe(const struct dwc3_probe_data *data)
dwc3_get_software_properties(dwc, &data->properties);
- dwc->usb_psy = dwc3_get_usb_power_supply(dwc);
- if (IS_ERR(dwc->usb_psy))
- return dev_err_probe(dev, PTR_ERR(dwc->usb_psy), "couldn't get usb power supply\n");
+ spin_lock_init(&dwc->lock);
+
+ dwc3_get_usb_power_supply(dwc);
if (!data->ignore_clocks_and_resets) {
dwc->reset = devm_reset_control_array_get_optional_shared(dev);
@@ -2305,7 +2372,6 @@ int dwc3_core_probe(const struct dwc3_probe_data *data)
dwc->num_usb3_ports = 1;
}
- spin_lock_init(&dwc->lock);
mutex_init(&dwc->mutex);
pm_runtime_get_noresume(dev);
@@ -2373,6 +2439,8 @@ err_disable_clks:
err_assert_reset:
reset_control_assert(dwc->reset);
err_put_psy:
+ if (dwc->psy_nb.notifier_call)
+ power_supply_unreg_notifier(&dwc->psy_nb);
if (dwc->usb_psy)
power_supply_put(dwc->usb_psy);
@@ -2429,6 +2497,9 @@ void dwc3_core_remove(struct dwc3 *dwc)
dwc3_free_event_buffers(dwc);
+ if (dwc->psy_nb.notifier_call)
+ power_supply_unreg_notifier(&dwc->psy_nb);
+
if (dwc->usb_psy) {
cancel_work_sync(&dwc->vbus_draw_work);
power_supply_put(dwc->usb_psy);
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index e0dee9d28740..608daeb7ef10 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -722,7 +722,6 @@ struct dwc3_event_buffer {
* @cancelled_list: list of cancelled requests for this endpoint
* @pending_list: list of pending requests for this endpoint
* @started_list: list of started requests on this endpoint
- * @regs: pointer to first endpoint register
* @trb_pool: array of transaction buffers
* @trb_pool_dma: dma address of @trb_pool
* @trb_enqueue: enqueue 'pointer' into TRB array
@@ -1059,6 +1058,8 @@ struct dwc3_glue_ops {
* @role_switch_default_mode: default operation mode of controller while
* usb role is USB_ROLE_NONE.
* @usb_psy: pointer to power supply interface.
+ * @usb_psy_name: name of the USB power supply
+ * @psy_nb: power supply notifier block
* @vbus_draw_work: Work to set the vbus drawing limit
* @current_limit: How much current to draw from vbus, in milliAmperes.
* @usb2_phy: pointer to USB2 PHY
@@ -1251,9 +1252,13 @@ struct dwc3 {
enum usb_dr_mode role_switch_default_mode;
struct power_supply *usb_psy;
+ const char *usb_psy_name;
+ struct notifier_block psy_nb;
struct work_struct vbus_draw_work;
unsigned int current_limit;
+#define DWC3_CURRENT_UNSPECIFIED UINT_MAX
+
u32 fladj;
u32 ref_clk_per;
u32 irq_gadget;
diff --git a/drivers/usb/dwc3/dwc3-am62.c b/drivers/usb/dwc3/dwc3-am62.c
index e11d7643f966..632634d6e81e 100644
--- a/drivers/usb/dwc3/dwc3-am62.c
+++ b/drivers/usb/dwc3/dwc3-am62.c
@@ -205,7 +205,9 @@ static int dwc3_ti_init(struct dwc3_am62 *am62)
dwc3_ti_writel(am62, USBSS_PHY_CONFIG, reg);
- clk_prepare_enable(am62->usb2_refclk);
+ ret = clk_prepare_enable(am62->usb2_refclk);
+ if (ret)
+ return ret;
/* Set mode valid bit to indicate role is valid */
reg = dwc3_ti_readl(am62, USBSS_MODE_CONTROL);
@@ -361,14 +363,19 @@ static int dwc3_ti_resume_common(struct device *dev)
{
struct dwc3_am62 *am62 = dev_get_drvdata(dev);
u32 reg;
+ int ret;
reg = dwc3_ti_readl(am62, USBSS_DEBUG_CFG);
if (reg != USBSS_DEBUG_CFG_DISABLED) {
/* lost power/context */
- dwc3_ti_init(am62);
+ ret = dwc3_ti_init(am62);
+ if (ret)
+ return ret;
} else {
dwc3_ti_writel(am62, USBSS_DEBUG_CFG, USBSS_DEBUG_CFG_OFF);
- clk_prepare_enable(am62->usb2_refclk);
+ ret = clk_prepare_enable(am62->usb2_refclk);
+ if (ret)
+ return ret;
}
if (device_may_wakeup(dev)) {
diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c
index f43f73ac36ff..ac68b4218b56 100644
--- a/drivers/usb/dwc3/dwc3-qcom.c
+++ b/drivers/usb/dwc3/dwc3-qcom.c
@@ -602,7 +602,7 @@ static void dwc3_qcom_run_stop_notifier(struct dwc3 *dwc, bool is_on)
pm_runtime_mark_last_busy(qcom->dev);
}
-struct dwc3_glue_ops dwc3_qcom_glue_ops = {
+static struct dwc3_glue_ops dwc3_qcom_glue_ops = {
.pre_set_role = dwc3_qcom_set_role_notifier,
.pre_run_stop = dwc3_qcom_run_stop_notifier,
};
diff --git a/drivers/usb/dwc3/dwc3-xilinx.c b/drivers/usb/dwc3/dwc3-xilinx.c
index 9b9525592a85..b832505e1b04 100644
--- a/drivers/usb/dwc3/dwc3-xilinx.c
+++ b/drivers/usb/dwc3/dwc3-xilinx.c
@@ -98,18 +98,10 @@ static int dwc3_xlnx_init_versal(struct dwc3_xlnx *priv_data)
dwc3_xlnx_mask_phy_rst(priv_data, false);
- /* Assert and De-assert reset */
- ret = reset_control_assert(crst);
- if (ret < 0) {
- dev_err_probe(dev, ret, "failed to assert Reset\n");
- return ret;
- }
-
- ret = reset_control_deassert(crst);
- if (ret < 0) {
- dev_err_probe(dev, ret, "failed to De-assert Reset\n");
- return ret;
- }
+ /* assert and deassert reset */
+ ret = reset_control_reset(crst);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to assert and deassert reset\n");
dwc3_xlnx_mask_phy_rst(priv_data, true);
dwc3_xlnx_set_coherency(priv_data, XLNX_USB2_TRAFFIC_ROUTE_CONFIG);
@@ -194,7 +186,7 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data)
}
if (priv_data->usb3_phy) {
- /* Set PIPE Power Present signal in FPD Power Present Register*/
+ /* Set PIPE Power Present signal in FPD Power Present Register */
writel(FPD_POWER_PRSNT_OPTION, priv_data->regs + XLNX_USB_FPD_POWER_PRSNT);
/* Set the PIPE Clock Select bit in FPD PIPE Clock register */
writel(PIPE_CLK_SELECT, priv_data->regs + XLNX_USB_FPD_PIPE_CLK);
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 3d4ca68e584c..fa0f16ffafef 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -3124,15 +3124,26 @@ static void dwc3_gadget_set_ssp_rate(struct usb_gadget *g,
static int dwc3_gadget_vbus_draw(struct usb_gadget *g, unsigned int mA)
{
struct dwc3 *dwc = gadget_to_dwc(g);
+ unsigned long flags;
if (dwc->usb2_phy)
return usb_phy_set_power(dwc->usb2_phy, mA);
- if (!dwc->usb_psy)
- return -EOPNOTSUPP;
+ spin_lock_irqsave(&dwc->lock, flags);
+ if (!dwc->usb_psy) {
+ if (!dwc->psy_nb.notifier_call) {
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ return -EOPNOTSUPP;
+ }
+ dwc->current_limit = mA;
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ dev_dbg(dwc->dev, "Stored VBUS draw: %u mA (power supply not ready)\n", mA);
+ return 0;
+ }
dwc->current_limit = mA;
schedule_work(&dwc->vbus_draw_work);
+ spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
}
@@ -3934,15 +3945,48 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
}
}
+static bool dwc3_prepare_disconnect_gadget(struct dwc3 *dwc,
+ struct usb_gadget_driver **driver,
+ struct usb_gadget **gadget)
+{
+ if (!dwc->async_callbacks || !dwc->gadget_driver ||
+ !dwc->gadget_driver->disconnect)
+ return false;
+
+ *driver = dwc->gadget_driver;
+ *gadget = dwc->gadget;
+
+ return true;
+}
+
static void dwc3_disconnect_gadget(struct dwc3 *dwc)
{
- if (dwc->async_callbacks && dwc->gadget_driver->disconnect) {
+ struct usb_gadget_driver *driver;
+ struct usb_gadget *gadget;
+
+ if (dwc3_prepare_disconnect_gadget(dwc, &driver, &gadget)) {
spin_unlock(&dwc->lock);
- dwc->gadget_driver->disconnect(dwc->gadget);
+ driver->disconnect(gadget);
spin_lock(&dwc->lock);
}
}
+static void dwc3_disconnect_gadget_sleepable(struct dwc3 *dwc)
+{
+ struct usb_gadget_driver *driver;
+ struct usb_gadget *gadget;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+ if (!dwc3_prepare_disconnect_gadget(dwc, &driver, &gadget)) {
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ return;
+ }
+
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ driver->disconnect(gadget);
+}
+
static void dwc3_suspend_gadget(struct dwc3 *dwc)
{
if (dwc->async_callbacks && dwc->gadget_driver->suspend) {
@@ -4838,7 +4882,6 @@ EXPORT_SYMBOL_GPL(dwc3_gadget_exit);
int dwc3_gadget_suspend(struct dwc3 *dwc)
{
- unsigned long flags;
int ret;
ret = dwc3_gadget_soft_disconnect(dwc);
@@ -4852,10 +4895,7 @@ int dwc3_gadget_suspend(struct dwc3 *dwc)
return -EAGAIN;
}
- spin_lock_irqsave(&dwc->lock, flags);
- if (dwc->gadget_driver)
- dwc3_disconnect_gadget(dwc);
- spin_unlock_irqrestore(&dwc->lock, flags);
+ dwc3_disconnect_gadget_sleepable(dwc);
return 0;
}
diff --git a/drivers/usb/fotg210/fotg210-hcd.c b/drivers/usb/fotg210/fotg210-hcd.c
index 1a48329a4e08..956be5b56510 100644
--- a/drivers/usb/fotg210/fotg210-hcd.c
+++ b/drivers/usb/fotg210/fotg210-hcd.c
@@ -4267,8 +4267,6 @@ static int iso_stream_schedule(struct fotg210_hcd *fotg210, struct urb *urb,
return 0;
fail:
- iso_sched_free(stream, sched);
- urb->hcpriv = NULL;
return status;
}
@@ -4562,6 +4560,10 @@ static int itd_submit(struct fotg210_hcd *fotg210, struct urb *urb,
else
usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb);
done_not_linked:
+ if (status < 0) {
+ iso_sched_free(stream, urb->hcpriv);
+ urb->hcpriv = NULL;
+ }
spin_unlock_irqrestore(&fotg210->lock, flags);
done:
return status;
diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c
index e4f7828ae75d..837f753d0cae 100644
--- a/drivers/usb/gadget/function/f_printer.c
+++ b/drivers/usb/gadget/function/f_printer.c
@@ -363,12 +363,11 @@ printer_open(struct inode *inode, struct file *fd)
ret = 0;
/* Change the printer status to show that it's on-line. */
dev->printer_status |= PRINTER_SELECTED;
+ kref_get(&dev->kref);
}
spin_unlock_irqrestore(&dev->lock, flags);
- kref_get(&dev->kref);
-
return ret;
}
diff --git a/drivers/usb/gadget/function/rndis.c b/drivers/usb/gadget/function/rndis.c
index 3da54a7d7aba..a2fd239b7ad3 100644
--- a/drivers/usb/gadget/function/rndis.c
+++ b/drivers/usb/gadget/function/rndis.c
@@ -591,6 +591,7 @@ static int rndis_init_response(struct rndis_params *params,
static int rndis_query_response(struct rndis_params *params,
rndis_query_msg_type *buf)
{
+ u32 BufLength, BufOffset;
rndis_query_cmplt_type *resp;
rndis_resp_t *r;
@@ -598,6 +599,13 @@ static int rndis_query_response(struct rndis_params *params,
if (!params->dev)
return -ENOTSUPP;
+ BufLength = le32_to_cpu(buf->InformationBufferLength);
+ BufOffset = le32_to_cpu(buf->InformationBufferOffset);
+ if ((BufLength > RNDIS_MAX_TOTAL_SIZE) ||
+ (BufOffset > RNDIS_MAX_TOTAL_SIZE) ||
+ (BufOffset + 8 >= RNDIS_MAX_TOTAL_SIZE))
+ return -EINVAL;
+
/*
* we need more memory:
* gen_ndis_query_resp expects enough space for
@@ -614,10 +622,8 @@ static int rndis_query_response(struct rndis_params *params,
resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
if (gen_ndis_query_resp(params, le32_to_cpu(buf->OID),
- le32_to_cpu(buf->InformationBufferOffset)
- + 8 + (u8 *)buf,
- le32_to_cpu(buf->InformationBufferLength),
- r)) {
+ BufOffset + 8 + (u8 *)buf,
+ BufLength, r)) {
/* OID not supported */
resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED);
resp->MessageLength = cpu_to_le32(sizeof *resp);
@@ -1074,6 +1080,12 @@ int rndis_rm_hdr(struct gether *port,
/* tmp points to a struct rndis_packet_msg_type */
__le32 *tmp = (void *)skb->data;
+ /* Need at least MessageType, MessageLength, DataOffset, DataLength */
+ if (skb->len < 16) {
+ dev_kfree_skb_any(skb);
+ return -EINVAL;
+ }
+
/* MessageType, MessageLength */
if (cpu_to_le32(RNDIS_MSG_PACKET)
!= get_unaligned(tmp++)) {
diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
index 60340ff9edbf..f6da12b553a0 100644
--- a/drivers/usb/gadget/udc/core.c
+++ b/drivers/usb/gadget/udc/core.c
@@ -31,8 +31,9 @@ static const struct bus_type gadget_bus_type;
/**
* struct usb_udc - describes one usb device controller
* @driver: the gadget driver pointer. For use by the class code
- * @dev: the child device to the actual controller
* @gadget: the gadget. For use by the class code
+ * @gadget_release: the gadget's release routine
+ * @dev: the child device to the actual controller
* @list: for use by the udc class driver
* @vbus: for udcs who care about vbus status, this value is real vbus status;
* for udcs who do not care about vbus status, this value is always true
@@ -53,6 +54,7 @@ static const struct bus_type gadget_bus_type;
struct usb_udc {
struct usb_gadget_driver *driver;
struct usb_gadget *gadget;
+ void (*gadget_release)(struct device *dev);
struct device dev;
struct list_head list;
bool vbus;
@@ -1362,6 +1364,17 @@ static void usb_udc_nop_release(struct device *dev)
dev_vdbg(dev, "%s\n", __func__);
}
+static void usb_gadget_release(struct device *dev)
+{
+ struct usb_gadget *gadget = dev_to_usb_gadget(dev);
+ struct usb_udc *udc = gadget->udc;
+ /* Cache the gadget's release routine to prevent UAF */
+ void (*release)(struct device *dev) = udc->gadget_release;
+
+ put_device(&udc->dev);
+ release(dev);
+}
+
/**
* usb_initialize_gadget - initialize a gadget and its embedded struct device
* @parent: the parent device to this udc. Usually the controller driver's
@@ -1418,6 +1431,14 @@ int usb_add_gadget(struct usb_gadget *gadget)
mutex_init(&udc->connect_lock);
udc->started = false;
+ /*
+ * Align decoupled lifecycles: take a UDC reference to ensure it
+ * remains allocated until the gadget is released, requiring an
+ * override of the gadget's release routine to drop it.
+ */
+ udc->gadget_release = gadget->dev.release;
+ gadget->dev.release = usb_gadget_release;
+ get_device(&udc->dev);
mutex_lock(&udc_lock);
list_add_tail(&udc->list, &udc_list);
@@ -1462,6 +1483,12 @@ int usb_add_gadget(struct usb_gadget *gadget)
mutex_lock(&udc_lock);
list_del(&udc->list);
mutex_unlock(&udc_lock);
+ /*
+ * Revert the override and drop the UDC reference to prevent
+ * leaking the UDC if the gadget was statically allocated.
+ */
+ gadget->dev.release = udc->gadget_release;
+ put_device(&udc->dev);
err_put_udc:
put_device(&udc->dev);
diff --git a/drivers/usb/gadget/udc/r8a66597-udc.c b/drivers/usb/gadget/udc/r8a66597-udc.c
index e7a5d8553c0e..d190e16d43fc 100644
--- a/drivers/usb/gadget/udc/r8a66597-udc.c
+++ b/drivers/usb/gadget/udc/r8a66597-udc.c
@@ -1951,7 +1951,6 @@ static int r8a66597_probe(struct platform_device *pdev)
return 0;
err_add_udc:
- r8a66597_free_request(&r8a66597->ep[0].ep, r8a66597->ep0_req);
clean_up2:
if (r8a66597->pdata->on_chip)
clk_disable_unprepare(r8a66597->clk);
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index a241337c9af8..57d07d1c2dfa 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -1623,6 +1623,7 @@ iso_stream_schedule(
status = 1; /* and give it back immediately */
iso_sched_free(stream, sched);
sched = NULL;
+ urb->hcpriv = NULL;
}
}
urb->error_count = skip / period;
@@ -1653,8 +1654,6 @@ iso_stream_schedule(
return status;
fail:
- iso_sched_free(stream, sched);
- urb->hcpriv = NULL;
return status;
}
@@ -1966,6 +1965,10 @@ static int itd_submit(struct ehci_hcd *ehci, struct urb *urb,
usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
}
done_not_linked:
+ if (status < 0) {
+ iso_sched_free(stream, urb->hcpriv);
+ urb->hcpriv = NULL;
+ }
spin_unlock_irqrestore(&ehci->lock, flags);
done:
return status;
@@ -2343,6 +2346,10 @@ static int sitd_submit(struct ehci_hcd *ehci, struct urb *urb,
usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
}
done_not_linked:
+ if (status < 0) {
+ iso_sched_free(stream, urb->hcpriv);
+ urb->hcpriv = NULL;
+ }
spin_unlock_irqrestore(&ehci->lock, flags);
done:
return status;
diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
index 9e0e06bbc570..23dc9eddc06c 100644
--- a/drivers/usb/host/ohci-dbg.c
+++ b/drivers/usb/host/ohci-dbg.c
@@ -683,7 +683,7 @@ static int fill_buffer(struct debug_buffer *buf)
int ret;
if (!buf->page)
- buf->page = (char *)get_zeroed_page(GFP_KERNEL);
+ buf->page = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!buf->page) {
ret = -ENOMEM;
@@ -729,11 +729,8 @@ static int debug_close(struct inode *inode, struct file *file)
{
struct debug_buffer *buf = file->private_data;
- if (buf) {
- if (buf->page)
- free_page((unsigned long)buf->page);
- kfree(buf);
- }
+ kfree(buf->page);
+ kfree(buf);
return 0;
}
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index 4ae47edd4b8b..b044977f6f56 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -1591,6 +1591,7 @@ sl811h_remove(struct platform_device *dev)
remove_debug_file(sl811);
usb_remove_hcd(hcd);
+ device_wakeup_disable(hcd->self.controller);
/* some platforms may use IORESOURCE_IO */
res = platform_get_resource(dev, IORESOURCE_MEM, 1);
diff --git a/drivers/usb/host/xhci-sideband.c b/drivers/usb/host/xhci-sideband.c
index 23153e136d4b..a5deeee4d5dc 100644
--- a/drivers/usb/host/xhci-sideband.c
+++ b/drivers/usb/host/xhci-sideband.c
@@ -58,6 +58,8 @@ xhci_ring_to_sgtable(struct xhci_sideband *sb, struct xhci_ring *ring)
if (sg_alloc_table_from_pages(sgt, pages, n_pages, 0, sz, GFP_KERNEL))
goto err;
+ kvfree(pages);
+
/*
* Save first segment dma address to sg dma_address field for the sideband
* client to have access to the IOVA of the ring.
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 6922cc5496c1..f44ccee5fa07 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -3785,6 +3785,7 @@ static int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
struct xhci_virt_device *vdev;
struct xhci_command *command;
struct xhci_input_control_ctx *ctrl_ctx;
+ struct xhci_stream_info *stream_info[EP_CTX_PER_DEV];
unsigned int ep_index;
unsigned long flags;
u32 changed_ep_bitmask;
@@ -3845,10 +3846,15 @@ static int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
if (ret < 0)
return ret;
+ /*
+ * dma_free_coherent() called by xhci_free_stream_info() may sleep,
+ * so save stream_info pointers and clear references under lock,
+ * then free the memory outside lock.
+ */
spin_lock_irqsave(&xhci->lock, flags);
for (i = 0; i < num_eps; i++) {
ep_index = xhci_get_endpoint_index(&eps[i]->desc);
- xhci_free_stream_info(xhci, vdev->eps[ep_index].stream_info);
+ stream_info[i] = vdev->eps[ep_index].stream_info;
vdev->eps[ep_index].stream_info = NULL;
/* FIXME Unset maxPstreams in endpoint context and
* update deq ptr to point to normal string ring.
@@ -3858,6 +3864,9 @@ static int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
}
spin_unlock_irqrestore(&xhci->lock, flags);
+ for (i = 0; i < num_eps; i++)
+ xhci_free_stream_info(xhci, stream_info[i]);
+
return 0;
}
diff --git a/drivers/usb/misc/chaoskey.c b/drivers/usb/misc/chaoskey.c
index d8016540953f..9c06f7775301 100644
--- a/drivers/usb/misc/chaoskey.c
+++ b/drivers/usb/misc/chaoskey.c
@@ -320,7 +320,6 @@ bail:
mutex_unlock(&dev->lock);
destruction:
mutex_unlock(&chaoskey_list_lock);
- usb_dbg(interface, "release success");
return rv;
}
diff --git a/drivers/usb/misc/usbio.c b/drivers/usb/misc/usbio.c
index 24c4cd0df829..3c2474dca810 100644
--- a/drivers/usb/misc/usbio.c
+++ b/drivers/usb/misc/usbio.c
@@ -522,7 +522,7 @@ static int usbio_resume(struct usb_interface *intf)
static void usbio_disconnect(struct usb_interface *intf)
{
struct usbio_device *usbio = usb_get_intfdata(intf);
- struct usbio_client *client;
+ struct usbio_client *client, *next;
/* Wakeup any clients waiting for a reply */
usbio->rxdat_len = 0;
@@ -539,7 +539,7 @@ static void usbio_disconnect(struct usb_interface *intf)
usb_kill_urb(usbio->urb);
usb_free_urb(usbio->urb);
- list_for_each_entry_reverse(client, &usbio->cli_list, link) {
+ list_for_each_entry_safe_reverse(client, next, &usbio->cli_list, link) {
auxiliary_device_delete(&client->auxdev);
auxiliary_device_uninit(&client->auxdev);
}
diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
index b7d3c44b970e..1ce48f5832d7 100644
--- a/drivers/usb/misc/uss720.c
+++ b/drivers/usb/misc/uss720.c
@@ -732,8 +732,11 @@ static int uss720_probe(struct usb_interface *intf,
* here. */
ret = get_1284_register(pp, 0, &reg, GFP_KERNEL);
dev_dbg(&intf->dev, "reg: %7ph\n", priv->reg);
- if (ret < 0)
+ if (ret < 0) {
+ priv->pp = NULL;
+ parport_del_port(pp);
goto probe_abort;
+ }
ret = usb_find_last_int_in_endpoint(interface, &epd);
if (!ret) {
diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c
index 8770de01a384..ed49a3bc859c 100644
--- a/drivers/usb/storage/ene_ub6250.c
+++ b/drivers/usb/storage/ene_ub6250.c
@@ -2305,7 +2305,8 @@ static int ene_transport(struct scsi_cmnd *srb, struct us_data *us)
/*US_DEBUG(usb_stor_show_command(us, srb)); */
scsi_set_resid(srb, 0);
- if (unlikely(!(info->SD_Status & SD_Ready) || (info->MS_Status & MS_Ready)))
+ if (unlikely(!(info->SD_Status & SD_Ready) &&
+ !(info->MS_Status & MS_Ready)))
result = ene_init(us);
if (result == USB_STOR_XFER_GOOD) {
result = USB_STOR_TRANSPORT_ERROR;
diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c
index 263a89c5f324..51c92dd887ab 100644
--- a/drivers/usb/typec/altmodes/displayport.c
+++ b/drivers/usb/typec/altmodes/displayport.c
@@ -764,6 +764,7 @@ int dp_altmode_probe(struct typec_altmode *alt)
struct typec_altmode *plug = typec_altmode_get_plug(alt, TYPEC_PLUG_SOP_P);
struct fwnode_handle *fwnode;
struct dp_altmode *dp;
+ u32 cap = DP_CAP_CAPABILITY(alt->vdo);
/* Port can only be DFP_U. */
if (typec_altmode_get_data_role(alt) != TYPEC_HOST)
@@ -778,6 +779,18 @@ int dp_altmode_probe(struct typec_altmode *alt)
return -ENODEV;
}
+ /*
+ * Make sure the DisplayPort VDO is valid (VESA DPAM v2.1a, Section
+ * 5.4.1, Table 5-6, DP Capabilities VDO). A device exposing DP on a
+ * USB-C receptacle must advertise at least one pin assignment for the
+ * capability it claims, otherwise Alt Mode can never be configured.
+ */
+ if ((cap == DP_CAP_DFP_D && !DP_CAP_PIN_ASSIGN_DFP_D(alt->vdo)) ||
+ (cap == DP_CAP_UFP_D && !DP_CAP_PIN_ASSIGN_UFP_D(alt->vdo))) {
+ typec_altmode_put_plug(plug);
+ return -ENODEV;
+ }
+
dp = devm_kzalloc(&alt->dev, sizeof(*dp), GFP_KERNEL);
if (!dp) {
typec_altmode_put_plug(plug);
@@ -790,7 +803,6 @@ int dp_altmode_probe(struct typec_altmode *alt)
dp->alt = alt;
alt->desc = "DisplayPort";
- typec_altmode_set_ops(alt, &dp_altmode_ops);
if (plug) {
plug->desc = "Displayport";
@@ -811,6 +823,10 @@ int dp_altmode_probe(struct typec_altmode *alt)
if (plug)
typec_altmode_set_drvdata(plug, dp);
+ if ((alt->vdo & DP_CAP_RECEPTACLE) && typec_cable_altmode_unsupported(alt))
+ return 0;
+
+ typec_altmode_set_ops(alt, &dp_altmode_ops);
if (!alt->mode_selection) {
dp->state = plug ? DP_STATE_ENTER_PRIME : DP_STATE_ENTER;
schedule_work(&dp->work);
diff --git a/drivers/usb/typec/altmodes/thunderbolt.c b/drivers/usb/typec/altmodes/thunderbolt.c
index 32250b94262a..2eccdddf1b1f 100644
--- a/drivers/usb/typec/altmodes/thunderbolt.c
+++ b/drivers/usb/typec/altmodes/thunderbolt.c
@@ -284,6 +284,10 @@ static int tbt_altmode_probe(struct typec_altmode *alt)
alt->desc = "Thunderbolt3";
typec_altmode_set_drvdata(alt, tbt);
+
+ if (typec_cable_altmode_unsupported(alt))
+ return 0;
+
typec_altmode_set_ops(alt, &tbt_altmode_ops);
if (!alt->mode_selection && tbt_ready(alt)) {
diff --git a/drivers/usb/typec/anx7411.c b/drivers/usb/typec/anx7411.c
index 604868ebf422..41df115912b9 100644
--- a/drivers/usb/typec/anx7411.c
+++ b/drivers/usb/typec/anx7411.c
@@ -1537,7 +1537,9 @@ static int anx7411_i2c_probe(struct i2c_client *client)
if (anx7411_typec_check_connection(plat))
dev_err(dev, "check status\n");
- pm_runtime_enable(dev);
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ goto free_wq;
return 0;
diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
index 0977581ad1b6..54c7810b563b 100644
--- a/drivers/usb/typec/class.c
+++ b/drivers/usb/typec/class.c
@@ -1429,6 +1429,77 @@ int typec_cable_is_active(struct typec_cable *cable)
}
EXPORT_SYMBOL_GPL(typec_cable_is_active);
+enum typec_cable_altmode_support {
+ CABLE_SUPPORT_UNKNOWN,
+ CABLE_SUPPORTED,
+ CABLE_NOT_SUPPORTED,
+};
+
+static enum typec_cable_altmode_support
+typec_cable_check_altmode_support(struct typec_cable *cable,
+ struct typec_altmode *alt)
+{
+ struct typec_altmode *plug;
+ u32 speed;
+
+ /*
+ * Check if the cable has an e-marker, supports modal operation, and the
+ * SOP' altmode nodes are created.
+ */
+ plug = typec_altmode_get_plug(alt, TYPEC_PLUG_SOP_P);
+ if (plug) {
+ typec_altmode_put_plug(plug);
+ return CABLE_SUPPORTED;
+ }
+
+ /* The identity is not specified */
+ if (!cable->identity)
+ return CABLE_SUPPORT_UNKNOWN;
+
+ /* Non-e-marked cable */
+ if (!cable->identity->id_header)
+ return CABLE_NOT_SUPPORTED;
+
+ switch (PD_IDH_PTYPE(cable->identity->id_header)) {
+ case IDH_PTYPE_PCABLE:
+ speed = VDO_TYPEC_CABLE_SPEED(cable->identity->vdo[0]);
+ if (speed == CABLE_USB2_ONLY)
+ return CABLE_NOT_SUPPORTED;
+ return CABLE_SUPPORTED;
+ case IDH_PTYPE_ACABLE:
+ /*
+ * Active cables must establish an SOP' communication
+ * node. Since that check failed at the beginning of
+ * this function, this active cable does not support
+ * this specific altmode.
+ */
+ return CABLE_NOT_SUPPORTED;
+ }
+
+ return CABLE_SUPPORT_UNKNOWN;
+}
+
+/**
+ * typec_cable_altmode_unsupported - Check if a cable restricts altmode
+ * @alt: The Alternate Mode to evaluate
+ *
+ * Returns true if the connected cable is incapable of handling the altmode.
+ */
+bool typec_cable_altmode_unsupported(struct typec_altmode *alt)
+{
+ enum typec_cable_altmode_support support = CABLE_SUPPORT_UNKNOWN;
+ struct typec_cable *cable;
+
+ cable = typec_cable_get(typec_altmode2port(alt));
+ if (cable) {
+ support = typec_cable_check_altmode_support(cable, alt);
+ typec_cable_put(cable);
+ }
+
+ return support == CABLE_NOT_SUPPORTED;
+}
+EXPORT_SYMBOL_GPL(typec_cable_altmode_unsupported);
+
/**
* typec_cable_set_identity - Report result from Discover Identity command
* @cable: The cable updated identity values
@@ -1619,6 +1690,7 @@ static ssize_t select_usb_power_delivery_store(struct device *dev,
return -EINVAL;
ret = port->ops->pd_set(port, pd);
+ put_device(&pd->dev);
if (ret)
return ret;
diff --git a/drivers/usb/typec/mux.c b/drivers/usb/typec/mux.c
index db5e4a4c0a99..9b908c46bd7d 100644
--- a/drivers/usb/typec/mux.c
+++ b/drivers/usb/typec/mux.c
@@ -275,9 +275,7 @@ static int mux_fwnode_match(struct device *dev, const void *fwnode)
static void *typec_mux_match(const struct fwnode_handle *fwnode,
const char *id, void *data)
{
- struct typec_mux_dev **mux_devs = data;
struct device *dev;
- int i;
/*
* Device graph (OF graph) does not give any means to identify the
@@ -293,14 +291,6 @@ static void *typec_mux_match(const struct fwnode_handle *fwnode,
dev = class_find_device(&typec_mux_class, NULL, fwnode,
mux_fwnode_match);
- /* Skip duplicates */
- for (i = 0; i < TYPEC_MUX_MAX_DEVS; i++)
- if (to_typec_mux_dev(dev) == mux_devs[i]) {
- put_device(dev);
- return NULL;
- }
-
-
return dev ? to_typec_mux_dev(dev) : ERR_PTR(-EPROBE_DEFER);
}
@@ -326,8 +316,7 @@ struct typec_mux *fwnode_typec_mux_get(struct fwnode_handle *fwnode)
return ERR_PTR(-ENOMEM);
count = fwnode_connection_find_matches(fwnode, "mode-switch",
- (void **)mux_devs,
- typec_mux_match,
+ NULL, typec_mux_match,
(void **)mux_devs,
ARRAY_SIZE(mux_devs));
if (count <= 0) {
diff --git a/drivers/usb/typec/mux/ps883x.c b/drivers/usb/typec/mux/ps883x.c
index f52443638ee2..64e0a61b776a 100644
--- a/drivers/usb/typec/mux/ps883x.c
+++ b/drivers/usb/typec/mux/ps883x.c
@@ -206,12 +206,12 @@ static int ps883x_set(struct ps883x_retimer *retimer, struct typec_retimer_state
CONN_STATUS_1_DP_HPD_LEVEL;
switch (state->mode) {
+ case TYPEC_DP_STATE_D:
+ cfg0 |= CONN_STATUS_0_USB_3_1_CONNECTED;
+ fallthrough;
case TYPEC_DP_STATE_C:
cfg1 |= CONN_STATUS_1_DP_SINK_REQUESTED |
CONN_STATUS_1_DP_PIN_ASSIGNMENT_C_D;
- fallthrough;
- case TYPEC_DP_STATE_D:
- cfg1 |= CONN_STATUS_0_USB_3_1_CONNECTED;
break;
default: /* MODE_E */
break;
diff --git a/drivers/usb/typec/mux/tusb1046.c b/drivers/usb/typec/mux/tusb1046.c
index d6e1289a4945..34ef81f75693 100644
--- a/drivers/usb/typec/mux/tusb1046.c
+++ b/drivers/usb/typec/mux/tusb1046.c
@@ -178,6 +178,7 @@ static const struct of_device_id tusb1046_match_table[] = {
{.compatible = "ti,tusb1046"},
{},
};
+MODULE_DEVICE_TABLE(of, tusb1046_match_table);
static struct i2c_driver tusb1046_driver = {
.driver = {
diff --git a/drivers/usb/typec/tcpm/tcpci_rt1711h.c b/drivers/usb/typec/tcpm/tcpci_rt1711h.c
index 9d3b1fcf7e27..af8356df6b98 100644
--- a/drivers/usb/typec/tcpm/tcpci_rt1711h.c
+++ b/drivers/usb/typec/tcpm/tcpci_rt1711h.c
@@ -294,6 +294,8 @@ static int rt1711h_sw_reset(struct rt1711h_chip *chip)
return 0;
}
+static void rt1711h_unregister_tcpci_port(void *tcpci);
+
static int rt1711h_probe(struct i2c_client *client)
{
int ret;
@@ -339,6 +341,10 @@ static int rt1711h_probe(struct i2c_client *client)
if (IS_ERR_OR_NULL(chip->tcpci))
return PTR_ERR(chip->tcpci);
+ ret = devm_add_action_or_reset(chip->dev, rt1711h_unregister_tcpci_port, chip->tcpci);
+ if (ret)
+ return ret;
+
ret = devm_request_threaded_irq(chip->dev, client->irq, NULL,
rt1711h_irq,
IRQF_ONESHOT | IRQF_TRIGGER_LOW,
@@ -356,11 +362,9 @@ static int rt1711h_probe(struct i2c_client *client)
return 0;
}
-static void rt1711h_remove(struct i2c_client *client)
+static void rt1711h_unregister_tcpci_port(void *tcpci)
{
- struct rt1711h_chip *chip = i2c_get_clientdata(client);
-
- tcpci_unregister_port(chip->tcpci);
+ tcpci_unregister_port(tcpci);
}
static const struct rt1711h_chip_info rt1711h = {
@@ -393,7 +397,6 @@ static struct i2c_driver rt1711h_i2c_driver = {
.of_match_table = rt1711h_of_match,
},
.probe = rt1711h_probe,
- .remove = rt1711h_remove,
.id_table = rt1711h_id,
};
module_i2c_driver(rt1711h_i2c_driver);
diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index bc531923b1ca..5e652f3d449b 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -2034,7 +2034,7 @@ static void tcpm_register_partner_altmodes(struct tcpm_port *port)
if (!port->partner)
return;
- for (i = 0; i < modep->altmodes; i++) {
+ for (i = 0; i < modep->altmodes && i < ALTMODE_DISCOVERY_MAX; i++) {
altmode = typec_partner_register_altmode(port->partner,
&modep->altmode_desc[i]);
if (IS_ERR(altmode)) {
@@ -2052,9 +2052,10 @@ static void tcpm_register_plug_altmodes(struct tcpm_port *port)
struct typec_altmode *altmode;
int i;
- typec_plug_set_num_altmodes(port->plug_prime, modep->altmodes);
+ typec_plug_set_num_altmodes(port->plug_prime,
+ min(modep->altmodes, ALTMODE_DISCOVERY_MAX));
- for (i = 0; i < modep->altmodes; i++) {
+ for (i = 0; i < modep->altmodes && i < ALTMODE_DISCOVERY_MAX; i++) {
altmode = typec_plug_register_altmode(port->plug_prime,
&modep->altmode_desc[i]);
if (IS_ERR(altmode)) {
@@ -3093,7 +3094,7 @@ static int tcpm_altmode_enter(struct typec_altmode *altmode, u32 *vdo)
if (svdm_version < 0)
return svdm_version;
- header = VDO(altmode->svid, vdo ? 2 : 1, svdm_version, CMD_ENTER_MODE);
+ header = VDO(altmode->svid, 1, svdm_version, CMD_ENTER_MODE);
header |= VDO_OPOS(altmode->mode);
return tcpm_queue_vdm_unlocked(port, header, vdo, vdo ? 1 : 0, TCPC_TX_SOP);
@@ -3141,7 +3142,7 @@ static int tcpm_cable_altmode_enter(struct typec_altmode *altmode, enum typec_pl
if (svdm_version < 0)
return svdm_version;
- header = VDO(altmode->svid, vdo ? 2 : 1, svdm_version, CMD_ENTER_MODE);
+ header = VDO(altmode->svid, 1, svdm_version, CMD_ENTER_MODE);
header |= VDO_OPOS(altmode->mode);
return tcpm_queue_vdm_unlocked(port, header, vdo, vdo ? 1 : 0, TCPC_TX_SOP_PRIME);
@@ -4896,11 +4897,11 @@ static void tcpm_unregister_altmodes(struct tcpm_port *port)
struct pd_mode_data *modep_prime = &port->mode_data_prime;
int i;
- for (i = 0; i < modep->altmodes; i++) {
+ for (i = 0; i < modep->altmodes && i < ALTMODE_DISCOVERY_MAX; i++) {
typec_unregister_altmode(port->partner_altmode[i]);
port->partner_altmode[i] = NULL;
}
- for (i = 0; i < modep_prime->altmodes; i++) {
+ for (i = 0; i < modep_prime->altmodes && i < ALTMODE_DISCOVERY_MAX; i++) {
typec_unregister_altmode(port->plug_prime_altmode[i]);
port->plug_prime_altmode[i] = NULL;
}
diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c
index d5ee0af9058b..b6335b36d384 100644
--- a/drivers/usb/typec/tipd/core.c
+++ b/drivers/usb/typec/tipd/core.c
@@ -1744,7 +1744,7 @@ static int tps6598x_probe(struct i2c_client *client)
struct tps6598x *tps;
struct fwnode_handle *fwnode;
u32 status;
- u32 vid;
+ u32 vid = 0;
int ret;
data = i2c_get_match_data(client);
@@ -1772,8 +1772,11 @@ static int tps6598x_probe(struct i2c_client *client)
if (!device_is_compatible(tps->dev, "ti,tps25750")) {
ret = tps6598x_read32(tps, TPS_REG_VID, &vid);
- if (ret < 0 || !vid)
+ if (ret < 0 || !vid) {
+ dev_err(tps->dev, "failed to read vendor ID: %d, vid: %#x\n",
+ ret, vid);
return -ENODEV;
+ }
}
/*
@@ -1851,7 +1854,7 @@ static int tps6598x_probe(struct i2c_client *client)
IRQF_SHARED | IRQF_ONESHOT,
dev_name(&client->dev), tps);
} else {
- dev_warn(tps->dev, "Unable to find the interrupt, switching to polling\n");
+ dev_dbg(tps->dev, "no IRQ specified, using polling mode\n");
INIT_DELAYED_WORK(&tps->wq_poll, tps6598x_poll_work);
queue_delayed_work(system_power_efficient_wq, &tps->wq_poll,
msecs_to_jiffies(POLL_INTERVAL));
diff --git a/drivers/usb/typec/tipd/tps6598x.h b/drivers/usb/typec/tipd/tps6598x.h
index 03edbb77bbd6..d4140f4da5bb 100644
--- a/drivers/usb/typec/tipd/tps6598x.h
+++ b/drivers/usb/typec/tipd/tps6598x.h
@@ -142,9 +142,13 @@
#define TPS_SYSTEM_POWER_STATE_S4 0x04
#define TPS_SYSTEM_POWER_STATE_S5 0x05
-/* TPS_REG_POWER_STATUS bits */
-#define TPS_POWER_STATUS_CONNECTION(x) TPS_FIELD_GET(BIT(0), (x))
-#define TPS_POWER_STATUS_SOURCESINK(x) TPS_FIELD_GET(BIT(1), (x))
+/* TPS_REG_POWER_STATUS bits (masks shared by TPS_FIELD_GET accessors and FIELD_PREP) */
+#define TPS_POWER_STATUS_CONNECTION_MASK BIT(0)
+#define TPS_POWER_STATUS_SOURCESINK_MASK BIT(1)
+#define TPS_POWER_STATUS_CONNECTION(x) \
+ TPS_FIELD_GET(TPS_POWER_STATUS_CONNECTION_MASK, (x))
+#define TPS_POWER_STATUS_SOURCESINK(x) \
+ TPS_FIELD_GET(TPS_POWER_STATUS_SOURCESINK_MASK, (x))
#define TPS_POWER_STATUS_BC12_DET(x) TPS_FIELD_GET(BIT(2), (x))
#define TPS_POWER_STATUS_TYPEC_CURRENT_MASK GENMASK(3, 2)
diff --git a/drivers/usb/typec/ucsi/debugfs.c b/drivers/usb/typec/ucsi/debugfs.c
index ff33a5e7c6b0..77a0dd75edd3 100644
--- a/drivers/usb/typec/ucsi/debugfs.c
+++ b/drivers/usb/typec/ucsi/debugfs.c
@@ -82,8 +82,8 @@ static int ucsi_resp_show(struct seq_file *s, void *not_used)
if (ucsi->debugfs->status)
return ucsi->debugfs->status;
- seq_printf(s, "0x%016llx%016llx\n", ucsi->debugfs->response.high,
- ucsi->debugfs->response.low);
+ seq_printf(s, "0x%016llx%016llx%016llx\n", ucsi->debugfs->response.ext,
+ ucsi->debugfs->response.high, ucsi->debugfs->response.low);
return 0;
}
DEFINE_SHOW_ATTRIBUTE(ucsi_resp);
@@ -162,6 +162,7 @@ void ucsi_debugfs_unregister(struct ucsi *ucsi)
debugfs_remove_recursive(ucsi->debugfs->dentry);
kfree(ucsi->debugfs);
+ ucsi->debugfs = NULL;
}
void ucsi_debugfs_init(void)
diff --git a/drivers/usb/typec/ucsi/displayport.c b/drivers/usb/typec/ucsi/displayport.c
index c44da2fae81f..7067f2561b84 100644
--- a/drivers/usb/typec/ucsi/displayport.c
+++ b/drivers/usb/typec/ucsi/displayport.c
@@ -185,13 +185,12 @@ static int ucsi_displayport_status_update(struct ucsi_dp *dp)
static int ucsi_displayport_configure(struct ucsi_dp *dp)
{
- u32 pins = DP_CONF_GET_PIN_ASSIGN(dp->data.conf);
u64 command;
if (!dp->override)
return 0;
- command = UCSI_CMD_SET_NEW_CAM(dp->con->num, 1, dp->offset, pins);
+ command = UCSI_CMD_SET_NEW_CAM(dp->con->num, 1, dp->offset, dp->data.conf);
return ucsi_send_command(dp->con->ucsi, command, NULL, 0);
}
diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
index 92166a3725b1..acc2144c2d3b 100644
--- a/drivers/usb/typec/ucsi/ucsi.c
+++ b/drivers/usb/typec/ucsi/ucsi.c
@@ -2017,6 +2017,26 @@ static void ucsi_resume_work(struct work_struct *work)
}
}
+int ucsi_suspend(struct ucsi *ucsi)
+{
+ int i;
+
+ /*
+ * Cancel pending work so it cannot access the firmware after the ACPI
+ * EC is stopped for suspend; state is re-read on resume.
+ */
+ cancel_delayed_work_sync(&ucsi->work);
+
+ if (!ucsi->connector)
+ return 0;
+
+ for (i = 0; i < ucsi->cap.num_connectors; i++)
+ cancel_work_sync(&ucsi->connector[i].work);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ucsi_suspend);
+
int ucsi_resume(struct ucsi *ucsi)
{
if (ucsi->connector)
@@ -2040,7 +2060,7 @@ static void ucsi_init_work(struct work_struct *work)
return;
}
- queue_delayed_work(system_long_wq, &ucsi->work,
+ queue_delayed_work(system_dfl_long_wq, &ucsi->work,
UCSI_ROLE_SWITCH_INTERVAL);
}
}
@@ -2164,7 +2184,7 @@ int ucsi_register(struct ucsi *ucsi)
UCSI_BCD_GET_MINOR(ucsi->version),
UCSI_BCD_GET_SUBMINOR(ucsi->version));
- queue_delayed_work(system_long_wq, &ucsi->work, 0);
+ queue_delayed_work(system_dfl_long_wq, &ucsi->work, 0);
ucsi_debugfs_register(ucsi);
return 0;
@@ -2186,6 +2206,8 @@ void ucsi_unregister(struct ucsi *ucsi)
cancel_delayed_work_sync(&ucsi->work);
cancel_work_sync(&ucsi->resume_work);
+ ucsi_debugfs_unregister(ucsi);
+
/* Disable notifications */
ucsi->ops->async_control(ucsi, cmd);
diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h
index 325ed1e5ca80..dc594388dcd0 100644
--- a/drivers/usb/typec/ucsi/ucsi.h
+++ b/drivers/usb/typec/ucsi/ucsi.h
@@ -466,6 +466,7 @@ struct ucsi_debugfs_entry {
struct ucsi_data {
u64 low;
u64 high;
+ u64 ext;
} response;
int status;
u8 message_out[MESSAGE_OUT_MAX_LEN];
@@ -582,6 +583,7 @@ int ucsi_write_message_out_command(struct ucsi *ucsi, u64 command,
void *msg_out, size_t msg_out_size);
void ucsi_altmode_update_active(struct ucsi_connector *con);
+int ucsi_suspend(struct ucsi *ucsi);
int ucsi_resume(struct ucsi *ucsi);
void ucsi_notify_common(struct ucsi *ucsi, u32 cci);
diff --git a/drivers/usb/typec/ucsi/ucsi_acpi.c b/drivers/usb/typec/ucsi/ucsi_acpi.c
index 60b12961e1a4..18286d3e9cc5 100644
--- a/drivers/usb/typec/ucsi/ucsi_acpi.c
+++ b/drivers/usb/typec/ucsi/ucsi_acpi.c
@@ -263,6 +263,13 @@ static void ucsi_acpi_remove(struct platform_device *pdev)
ucsi_acpi_notify);
}
+static int ucsi_acpi_suspend(struct device *dev)
+{
+ struct ucsi_acpi *ua = dev_get_drvdata(dev);
+
+ return ucsi_suspend(ua->ucsi);
+}
+
static int ucsi_acpi_resume(struct device *dev)
{
struct ucsi_acpi *ua = dev_get_drvdata(dev);
@@ -270,7 +277,8 @@ static int ucsi_acpi_resume(struct device *dev)
return ucsi_resume(ua->ucsi);
}
-static DEFINE_SIMPLE_DEV_PM_OPS(ucsi_acpi_pm_ops, NULL, ucsi_acpi_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(ucsi_acpi_pm_ops, ucsi_acpi_suspend,
+ ucsi_acpi_resume);
static const struct acpi_device_id ucsi_acpi_match[] = {
{ "PNP0CA0", 0 },
diff --git a/drivers/usb/typec/ucsi/ucsi_huawei_gaokun.c b/drivers/usb/typec/ucsi/ucsi_huawei_gaokun.c
index ad669d2f8b9c..ca1b534cb183 100644
--- a/drivers/usb/typec/ucsi/ucsi_huawei_gaokun.c
+++ b/drivers/usb/typec/ucsi/ucsi_huawei_gaokun.c
@@ -84,6 +84,8 @@ struct gaokun_ucsi_port {
struct auxiliary_device *bridge;
struct typec_mux *typec_mux;
+ struct typec_mux_state state;
+ struct typec_altmode dp_alt;
int idx;
enum gaokun_ucsi_ccx ccx;
@@ -292,24 +294,22 @@ static int gaokun_ucsi_refresh(struct gaokun_ucsi *uec)
static void gaokun_ucsi_handle_usb_mode(struct gaokun_ucsi_port *port)
{
struct gaokun_ucsi *uec = port->ucsi;
- struct typec_mux_state state = {};
- struct typec_altmode dp_alt = {};
int idx = port->idx, ret;
/*
* For every typec port on this platform, the only mode-switch is
* controlled by its qmp combo phy which consumes svid and mode only.
*/
- dp_alt.svid = port->svid;
- state.mode = port->mode;
- state.alt = &dp_alt;
+ port->dp_alt.svid = port->svid;
+ port->state.mode = port->mode;
+ port->state.alt = &port->dp_alt;
if (idx >= uec->num_ports) {
dev_warn(uec->dev, "altmode port out of range: %d\n", idx);
return;
}
- ret = typec_mux_set(port->typec_mux, &state);
+ ret = typec_mux_set(port->typec_mux, &port->state);
if (ret)
dev_err(uec->dev, "failed to set mux %d\n", ret);
diff --git a/drivers/usb/usbip/vudc.h b/drivers/usb/usbip/vudc.h
index faf61c9c6a98..5ef0e7d9b23a 100644
--- a/drivers/usb/usbip/vudc.h
+++ b/drivers/usb/usbip/vudc.h
@@ -38,7 +38,6 @@ struct vep {
struct vrequest {
struct usb_request req;
- struct vudc *udc;
struct list_head req_entry; /* Request queue */
};
diff --git a/drivers/usb/usbip/vudc_dev.c b/drivers/usb/usbip/vudc_dev.c
index c5f079c5a1ea..5ef88117965d 100644
--- a/drivers/usb/usbip/vudc_dev.c
+++ b/drivers/usb/usbip/vudc_dev.c
@@ -333,7 +333,6 @@ static int vep_queue(struct usb_ep *_ep, struct usb_request *_req,
static int vep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
{
struct vep *ep;
- struct vrequest *req;
struct vudc *udc;
struct vrequest *lst;
unsigned long flags;
@@ -343,8 +342,7 @@ static int vep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
return ret;
ep = to_vep(_ep);
- req = to_vrequest(_req);
- udc = req->udc;
+ udc = ep_to_vudc(ep);
if (!udc->driver)
return -ESHUTDOWN;
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 7aa1c4b21111..7c66b8840d88 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -207,6 +207,14 @@ config BACKLIGHT_KTZ8866
Say Y to enable the backlight driver for the Kinetic KTZ8866
found in Xiaomi Mi Pad 5 series.
+config BACKLIGHT_SY7758
+ tristate "Backlight Driver for Silergy SY7758"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Say Y to enable the backlight driver for the Silergy SY7758
+ backlight controller found in Ayaneo Pocket S2.
+
config BACKLIGHT_LM3533
tristate "Backlight Driver for LM3533"
depends on MFD_LM3533
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 21c8313cfb12..34469711c6cd 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -57,6 +57,7 @@ obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o
obj-$(CONFIG_BACKLIGHT_QCOM_WLED) += qcom-wled.o
obj-$(CONFIG_BACKLIGHT_RT4831) += rt4831-backlight.o
obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o
+obj-$(CONFIG_BACKLIGHT_SY7758) += sy7758.o
obj-$(CONFIG_BACKLIGHT_SKY81452) += sky81452-backlight.o
obj-$(CONFIG_BACKLIGHT_TPS65217) += tps65217_bl.o
obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o
diff --git a/drivers/video/backlight/sy7758.c b/drivers/video/backlight/sy7758.c
new file mode 100644
index 000000000000..786589cb8df9
--- /dev/null
+++ b/drivers/video/backlight/sy7758.c
@@ -0,0 +1,259 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Silergy SY7758 6-channel High Efficiency LED Driver
+ *
+ * Copyright (C) 2025 Kancy Joe <kancy2333@outlook.com>
+ * Copyright (C) 2026 Linaro Limited
+ * Author: Neil Armstrong <neil.armstrong@linaro.org>
+ */
+#include <linux/backlight.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/of.h>
+#include <linux/err.h>
+#include <linux/bits.h>
+#include <linux/delay.h>
+#include <linux/regmap.h>
+#include <linux/bitfield.h>
+#include <linux/gpio/consumer.h>
+#include <linux/regulator/consumer.h>
+
+#define DEFAULT_BRIGHTNESS 1024
+#define MAX_BRIGHTNESS 4080
+#define REG_MAX 0xAE
+
+/* Registers */
+#define REG_DEV_CTL 0x01
+#define REG_DEV_ID 0x03
+#define REG_BRT_12BIT_L 0x10
+#define REG_BRT_12BIT_H 0x11
+
+/* OTP memory */
+#define REG_OTP_CFG0 0xA0
+#define REG_OTP_CFG1 0xA1
+#define REG_OTP_CFG2 0xA2
+#define REG_OTP_CFG5 0xA5
+#define REG_OTP_CFG9 0xA9
+
+/* Fields */
+#define BIT_DEV_CTL_FAST BIT(7)
+#define MSK_DEV_CTL_BRT_MODE GENMASK(2, 1)
+#define BIT_DEV_CTL_BL_CTLB BIT(0)
+
+#define MSK_BRT_12BIT_L GENMASK(7, 0)
+#define MSK_BRT_12BIT_H GENMASK(3, 0)
+
+#define MSK_CFG0_CURRENT_LOW GENMASK(7, 0)
+
+#define BIT_CFG1_PDET_STDBY BIT(7)
+#define MSK_CFG1_CURRENT_MAX GENMASK(6, 4)
+#define MSK_CFG1_CURRENT_HIGH GENMASK(3, 0)
+
+#define BIT_CFG2_UVLO_EN BIT(5)
+#define BIT_CFG2_UVLO_TH BIT(4)
+#define BIT_CFG2_BL_ON BIT(3)
+#define BIT_CFG2_ISET_EN BIT(2)
+#define BIT_CFG2_BST_ESET_EN BIT(1)
+
+#define BIT_CFG5_PWM_DIRECT BIT(7)
+#define MSK_CFG5_PS_MODE GENMASK(6, 4)
+#define MSK_CFG5_PWM_FREQ GENMASK(3, 0)
+
+#define MSK_CFG9_VBST_MAX GENMASK(7, 5)
+#define BIT_CFG9_JUMP_EN BIT(4)
+#define MSK_CFG9_JUMP_TH GENMASK(3, 2)
+#define MSK_CFG9_JUMP_VOLTAGE GENMASK(1, 0)
+
+struct sy7758 {
+ struct i2c_client *client;
+ struct regmap *regmap;
+ struct gpio_desc *gpio;
+ struct backlight_device *bl;
+};
+
+static const struct regmap_config sy7758_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = REG_MAX,
+};
+
+static int sy7758_backlight_update_status(struct backlight_device *backlight_dev)
+{
+ struct sy7758 *sydev = bl_get_data(backlight_dev);
+ unsigned int brightness = backlight_get_brightness(backlight_dev);
+ int ret;
+
+ ret = regmap_write(sydev->regmap, REG_BRT_12BIT_L,
+ FIELD_PREP(MSK_BRT_12BIT_L,
+ brightness & 0xff));
+ if (ret)
+ return ret;
+
+ ret = regmap_write(sydev->regmap, REG_BRT_12BIT_H,
+ FIELD_PREP(MSK_BRT_12BIT_H,
+ (brightness >> 8) & 0xf));
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static const struct backlight_ops sy7758_backlight_ops = {
+ .options = BL_CORE_SUSPENDRESUME,
+ .update_status = sy7758_backlight_update_status,
+};
+
+static int sy7758_init(struct sy7758 *sydev)
+{
+ int ret = 0;
+
+ ret = regmap_write(sydev->regmap, REG_DEV_CTL,
+ BIT_DEV_CTL_FAST | BIT_DEV_CTL_BL_CTLB |
+ FIELD_PREP(MSK_DEV_CTL_BRT_MODE, 2));
+ if (ret)
+ return ret;
+
+ ret = regmap_write(sydev->regmap, REG_BRT_12BIT_L,
+ FIELD_PREP(MSK_BRT_12BIT_L,
+ DEFAULT_BRIGHTNESS & 0xff));
+ if (ret)
+ return ret;
+
+ ret = regmap_write(sydev->regmap, REG_BRT_12BIT_H,
+ FIELD_PREP(MSK_BRT_12BIT_H,
+ (DEFAULT_BRIGHTNESS >> 8)));
+ if (ret)
+ return ret;
+
+ ret = regmap_write(sydev->regmap, REG_OTP_CFG5,
+ FIELD_PREP(MSK_CFG5_PS_MODE, 6) |
+ FIELD_PREP(MSK_CFG5_PWM_FREQ, 4));
+ if (ret)
+ return ret;
+
+ ret = regmap_write(sydev->regmap, REG_OTP_CFG0,
+ FIELD_PREP(MSK_CFG0_CURRENT_LOW, 85));
+ if (ret)
+ return ret;
+
+ ret = regmap_write(sydev->regmap, REG_OTP_CFG1,
+ BIT_CFG1_PDET_STDBY |
+ FIELD_PREP(MSK_CFG1_CURRENT_MAX, 1) |
+ FIELD_PREP(MSK_CFG1_CURRENT_HIGH, 10));
+ if (ret)
+ return ret;
+
+ ret = regmap_write(sydev->regmap, REG_OTP_CFG9,
+ FIELD_PREP(MSK_CFG9_VBST_MAX, 4));
+ if (ret)
+ return ret;
+
+ ret = regmap_write(sydev->regmap, REG_OTP_CFG2,
+ BIT_CFG2_BL_ON | BIT_CFG2_UVLO_EN);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int sy7758_probe(struct i2c_client *client)
+{
+ struct backlight_properties props = { };
+ struct device *dev = &client->dev;
+ struct sy7758 *sydev;
+ unsigned int dev_id;
+ int ret;
+
+ sydev = devm_kzalloc(dev, sizeof(*sydev), GFP_KERNEL);
+ if (!sydev)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, sydev);
+
+ /* Initialize regmap */
+ sydev->client = client;
+ sydev->regmap = devm_regmap_init_i2c(client, &sy7758_regmap_config);
+ if (IS_ERR(sydev->regmap))
+ return dev_err_probe(dev, PTR_ERR(sydev->regmap),
+ "failed to init regmap\n");
+
+ /* Get and enable regulator */
+ ret = devm_regulator_get_enable(dev, "vdd");
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to get regulator\n");
+
+ fsleep(100);
+
+ /* Get enable GPIO and set to high */
+ sydev->gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH);
+ if (IS_ERR(sydev->gpio))
+ return dev_err_probe(dev, PTR_ERR(sydev->gpio),
+ "failed to get enable GPIO\n");
+
+ /* Let some time for HW to settle */
+ fsleep(10000);
+
+ /* try read and check device id */
+ ret = regmap_read(sydev->regmap, REG_DEV_ID, &dev_id);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to read device id\n");
+ if (dev_id != 0x63) {
+ dev_err(dev, "unexpected device id: 0x%02x\n", dev_id);
+ return -ENODEV;
+ }
+
+ /* Initialize and set default brightness */
+ ret = sy7758_init(sydev);
+ if (ret)
+ return ret;
+
+ props.type = BACKLIGHT_RAW;
+ props.max_brightness = MAX_BRIGHTNESS;
+ props.brightness = DEFAULT_BRIGHTNESS;
+ props.scale = BACKLIGHT_SCALE_LINEAR;
+
+ sydev->bl = devm_backlight_device_register(dev, "sy7758-backlight",
+ dev, sydev, &sy7758_backlight_ops,
+ &props);
+ if (IS_ERR(sydev->bl))
+ return dev_err_probe(dev, PTR_ERR(sydev->bl),
+ "failed to register backlight device\n");
+
+ return backlight_update_status(sydev->bl);
+}
+
+static void sy7758_remove(struct i2c_client *client)
+{
+ struct sy7758 *sydev = i2c_get_clientdata(client);
+
+ backlight_disable(sydev->bl);
+}
+
+static const struct i2c_device_id sy7758_ids[] = {
+ { "sy7758" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, sy7758_ids);
+
+static const struct of_device_id sy7758_match_table[] = {
+ { .compatible = "silergy,sy7758", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, sy7758_match_table);
+
+static struct i2c_driver sy7758_driver = {
+ .driver = {
+ .name = "sy7758",
+ .of_match_table = sy7758_match_table,
+ },
+ .probe = sy7758_probe,
+ .remove = sy7758_remove,
+ .id_table = sy7758_ids,
+};
+
+module_i2c_driver(sy7758_driver);
+
+MODULE_DESCRIPTION("Silergy SY7758 Backlight Driver");
+MODULE_AUTHOR("Kancy Joe <kancy2333@outlook.com>");
+MODULE_AUTHOR("Neil Armstrong <neil.armstrong@linaro.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 08cb8612d41f..c93bc0d285f0 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -93,10 +93,19 @@ config WATCHDOG_PRETIMEOUT_GOV_SEL
tristate
depends on WATCHDOG_PRETIMEOUT_GOV
default m
- select WATCHDOG_PRETIMEOUT_GOV_PANIC if WATCHDOG_PRETIMEOUT_GOV_NOOP=n
+ select WATCHDOG_PRETIMEOUT_GOV_PANIC if \
+ WATCHDOG_PRETIMEOUT_GOV_NOOP=n && WATCHDOG_PRETIMEOUT_GOV_DUMP=n
if WATCHDOG_PRETIMEOUT_GOV
+config WATCHDOG_PRETIMEOUT_GOV_DUMP
+ bool "Dump watchdog pretimeout governor"
+ depends on WATCHDOG_CORE=y
+ default WATCHDOG_CORE
+ help
+ Dump watchdog pretimeout governor, all cpu backtrace is
+ added to kernel log buffer.
+
config WATCHDOG_PRETIMEOUT_GOV_NOOP
tristate "Noop watchdog pretimeout governor"
depends on WATCHDOG_CORE
@@ -121,6 +130,14 @@ choice
The governor takes its action, if a watchdog is capable
to report a pretimeout event.
+config WATCHDOG_PRETIMEOUT_DEFAULT_GOV_DUMP
+ bool "dump"
+ depends on WATCHDOG_PRETIMEOUT_GOV_DUMP
+ help
+ Use dump watchdog pretimeout governor by default. If dump
+ governor is selected by a user, dump all cpu backtrace to
+ the kernel log buffer and don't do any system changes.
+
config WATCHDOG_PRETIMEOUT_DEFAULT_GOV_NOOP
bool "noop"
depends on WATCHDOG_PRETIMEOUT_GOV_NOOP
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index bc1d52220f22..598556f03bc3 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -11,6 +11,7 @@ watchdog-objs += watchdog_core.o watchdog_dev.o
watchdog-$(CONFIG_WATCHDOG_PRETIMEOUT_GOV) += watchdog_pretimeout.o
watchdog-$(CONFIG_WATCHDOG_HRTIMER_PRETIMEOUT) += watchdog_hrtimer_pretimeout.o
+obj-$(CONFIG_WATCHDOG_PRETIMEOUT_GOV_DUMP) += pretimeout_dump.o
obj-$(CONFIG_WATCHDOG_PRETIMEOUT_GOV_NOOP) += pretimeout_noop.o
obj-$(CONFIG_WATCHDOG_PRETIMEOUT_GOV_PANIC) += pretimeout_panic.o
diff --git a/drivers/watchdog/db8500_wdt.c b/drivers/watchdog/db8500_wdt.c
index 97148ac0aa54..70ccea13288d 100644
--- a/drivers/watchdog/db8500_wdt.c
+++ b/drivers/watchdog/db8500_wdt.c
@@ -16,7 +16,7 @@
#include <linux/watchdog.h>
#include <linux/platform_device.h>
-#include <linux/mfd/dbx500-prcmu.h>
+#include <linux/mfd/db8500-prcmu.h>
#define WATCHDOG_TIMEOUT 600 /* 10 minutes */
@@ -37,24 +37,24 @@ MODULE_PARM_DESC(nowayout,
static int db8500_wdt_start(struct watchdog_device *wdd)
{
- return prcmu_enable_a9wdog(PRCMU_WDOG_ALL);
+ return db8500_prcmu_enable_a9wdog(PRCMU_WDOG_ALL);
}
static int db8500_wdt_stop(struct watchdog_device *wdd)
{
- return prcmu_disable_a9wdog(PRCMU_WDOG_ALL);
+ return db8500_prcmu_disable_a9wdog(PRCMU_WDOG_ALL);
}
static int db8500_wdt_keepalive(struct watchdog_device *wdd)
{
- return prcmu_kick_a9wdog(PRCMU_WDOG_ALL);
+ return db8500_prcmu_kick_a9wdog(PRCMU_WDOG_ALL);
}
static int db8500_wdt_set_timeout(struct watchdog_device *wdd,
unsigned int timeout)
{
db8500_wdt_stop(wdd);
- prcmu_load_a9wdog(PRCMU_WDOG_ALL, timeout * 1000);
+ db8500_prcmu_load_a9wdog(PRCMU_WDOG_ALL, timeout * 1000);
db8500_wdt_start(wdd);
return 0;
@@ -91,10 +91,10 @@ static int db8500_wdt_probe(struct platform_device *pdev)
watchdog_set_nowayout(&db8500_wdt, nowayout);
/* disable auto off on sleep */
- prcmu_config_a9wdog(PRCMU_WDOG_CPU1, false);
+ db8500_prcmu_config_a9wdog(PRCMU_WDOG_CPU1, false);
/* set HW initial value */
- prcmu_load_a9wdog(PRCMU_WDOG_ALL, timeout * 1000);
+ db8500_prcmu_load_a9wdog(PRCMU_WDOG_ALL, timeout * 1000);
ret = devm_watchdog_register_device(dev, &db8500_wdt);
if (ret)
@@ -110,9 +110,9 @@ static int db8500_wdt_suspend(struct platform_device *pdev,
{
if (watchdog_active(&db8500_wdt)) {
db8500_wdt_stop(&db8500_wdt);
- prcmu_config_a9wdog(PRCMU_WDOG_CPU1, true);
+ db8500_prcmu_config_a9wdog(PRCMU_WDOG_CPU1, true);
- prcmu_load_a9wdog(PRCMU_WDOG_ALL, timeout * 1000);
+ db8500_prcmu_load_a9wdog(PRCMU_WDOG_ALL, timeout * 1000);
db8500_wdt_start(&db8500_wdt);
}
return 0;
@@ -122,9 +122,9 @@ static int db8500_wdt_resume(struct platform_device *pdev)
{
if (watchdog_active(&db8500_wdt)) {
db8500_wdt_stop(&db8500_wdt);
- prcmu_config_a9wdog(PRCMU_WDOG_CPU1, false);
+ db8500_prcmu_config_a9wdog(PRCMU_WDOG_CPU1, false);
- prcmu_load_a9wdog(PRCMU_WDOG_ALL, timeout * 1000);
+ db8500_prcmu_load_a9wdog(PRCMU_WDOG_ALL, timeout * 1000);
db8500_wdt_start(&db8500_wdt);
}
return 0;
diff --git a/drivers/watchdog/pretimeout_dump.c b/drivers/watchdog/pretimeout_dump.c
new file mode 100644
index 000000000000..c5d3dac2606c
--- /dev/null
+++ b/drivers/watchdog/pretimeout_dump.c
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2026 Google LLC
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/nmi.h>
+#include <linux/watchdog.h>
+
+#include "watchdog_pretimeout.h"
+
+/**
+ * pretimeout_dump - Dump on watchdog pretimeout event
+ * @wdd: watchdog_device
+ *
+ * Dump all cpu backtrace on pretimeout event.
+ */
+static void pretimeout_dump(struct watchdog_device *wdd)
+{
+ pr_alert("watchdog%d: pretimeout event\n", wdd->id);
+ if (!trigger_all_cpu_backtrace())
+ pr_alert("trigger_all_cpu_backtrace() isn't available\n");
+}
+
+static struct watchdog_governor watchdog_gov_dump = {
+ .name = "dump",
+ .pretimeout = pretimeout_dump,
+};
+
+static int __init watchdog_gov_dump_register(void)
+{
+ return watchdog_register_governor(&watchdog_gov_dump);
+}
+
+static void __exit watchdog_gov_dump_unregister(void)
+{
+ watchdog_unregister_governor(&watchdog_gov_dump);
+}
+module_init(watchdog_gov_dump_register);
+module_exit(watchdog_gov_dump_unregister);
+
+MODULE_AUTHOR("Tzung-Bi Shih <tzungbi@kernel.org>");
+MODULE_DESCRIPTION("Dump watchdog pretimeout governor");
+MODULE_LICENSE("GPL");
diff --git a/drivers/watchdog/watchdog_pretimeout.c b/drivers/watchdog/watchdog_pretimeout.c
index 19eb2ed2c7cb..02e09b9e396d 100644
--- a/drivers/watchdog/watchdog_pretimeout.c
+++ b/drivers/watchdog/watchdog_pretimeout.c
@@ -167,6 +167,8 @@ void watchdog_unregister_governor(struct watchdog_governor *gov)
}
spin_lock_irq(&pretimeout_lock);
+ if (default_gov == gov)
+ default_gov = NULL;
list_for_each_entry(p, &pretimeout_list, entry)
if (p->wdd->gov == gov)
p->wdd->gov = default_gov;
diff --git a/drivers/watchdog/watchdog_pretimeout.h b/drivers/watchdog/watchdog_pretimeout.h
index a3f1abc68839..57aa790e2669 100644
--- a/drivers/watchdog/watchdog_pretimeout.h
+++ b/drivers/watchdog/watchdog_pretimeout.h
@@ -24,7 +24,9 @@ int watchdog_pretimeout_governor_get(struct watchdog_device *wdd, char *buf);
int watchdog_pretimeout_governor_set(struct watchdog_device *wdd,
const char *buf);
-#if IS_ENABLED(CONFIG_WATCHDOG_PRETIMEOUT_DEFAULT_GOV_NOOP)
+#if IS_ENABLED(CONFIG_WATCHDOG_PRETIMEOUT_DEFAULT_GOV_DUMP)
+#define WATCHDOG_PRETIMEOUT_DEFAULT_GOV "dump"
+#elif IS_ENABLED(CONFIG_WATCHDOG_PRETIMEOUT_DEFAULT_GOV_NOOP)
#define WATCHDOG_PRETIMEOUT_DEFAULT_GOV "noop"
#elif IS_ENABLED(CONFIG_WATCHDOG_PRETIMEOUT_DEFAULT_GOV_PANIC)
#define WATCHDOG_PRETIMEOUT_DEFAULT_GOV "panic"
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 37cbbb43a764..5bcd4027d203 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -1632,11 +1632,8 @@ static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
&& (fattr->valid & NFS_ATTR_FATTR_SIZE)
&& i_size_read(inode) == nfs_size_to_loff_t(fattr->pre_size)
&& !nfs_have_writebacks(inode)) {
- if ((!nfs_have_write_delegation(inode)) ||
- (NFS_I(inode)->cache_validity & NFS_INO_INVALID_SIZE)) {
- trace_nfs_size_wcc(inode, fattr->size);
- i_size_write(inode, nfs_size_to_loff_t(fattr->size));
- }
+ trace_nfs_size_wcc(inode, fattr->size);
+ i_size_write(inode, nfs_size_to_loff_t(fattr->size));
}
}
diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
index a3555bebad63..b59f0aa43c4b 100644
--- a/fs/notify/fanotify/fanotify.c
+++ b/fs/notify/fanotify/fanotify.c
@@ -599,6 +599,7 @@ static struct fanotify_event *fanotify_alloc_perm_event(const void *data,
pevent->hdr.pad = 0;
pevent->hdr.len = 0;
pevent->state = FAN_EVENT_INIT;
+ pevent->watchdog_cnt = 0;
pevent->path = *path;
/* NULL ppos means no range info */
pevent->ppos = range ? &range->pos : NULL;
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
index 815bf3f659da..41db7dd39ed9 100644
--- a/fs/ocfs2/inode.c
+++ b/fs/ocfs2/inode.c
@@ -1952,8 +1952,6 @@ int ocfs2_read_inode_block_full(struct inode *inode, struct buffer_head **bh,
rc = ocfs2_read_blocks(INODE_CACHE(inode), OCFS2_I(inode)->ip_blkno,
1, &tmp, flags, ocfs2_validate_inode_block);
- if (rc < 0)
- make_bad_inode(inode);
/* If ocfs2_read_blocks() got us a new bh, pass it up. */
if (!rc && !*bh)
*bh = tmp;
diff --git a/fs/pipe.c b/fs/pipe.c
index 429b0714ec57..8f98ca864cb4 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -1589,7 +1589,7 @@ static int u2k_pipe_maxsz(const ulong *u_ptr, uint *k_ptr)
return proc_uint_u2k_conv_uop(u_ptr, k_ptr, round_pipe_size_ul);
}
-static int do_proc_uint_conv_pipe_maxsz(ulong *u_ptr, uint *k_ptr,
+static int do_proc_uint_conv_pipe_maxsz(bool *negp, ulong *u_ptr, uint *k_ptr,
int dir, const struct ctl_table *table)
{
return proc_uint_conv(u_ptr, k_ptr, dir, table, true,
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index e4302fcf0227..8285f497178b 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -1237,6 +1237,9 @@ static void show_smap_vma_flags(struct seq_file *m, struct vm_area_struct *vma)
#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_MINOR
[ilog2(VM_UFFD_MINOR)] = "ui",
#endif /* CONFIG_HAVE_ARCH_USERFAULTFD_MINOR */
+#ifdef CONFIG_USERFAULTFD_RWP
+ [ilog2(VM_UFFD_RWP)] = "ur",
+#endif
#ifdef CONFIG_ARCH_HAS_USER_SHADOW_STACK
[ilog2(VM_SHADOW_STACK)] = "ss",
#endif
@@ -2035,14 +2038,14 @@ static pagemap_entry_t pte_to_pagemap_entry(struct pagemapread *pm,
page = vm_normal_page(vma, addr, pte);
if (pte_soft_dirty(pte))
flags |= PM_SOFT_DIRTY;
- if (pte_uffd_wp(pte))
+ if (pte_uffd(pte))
flags |= PM_UFFD_WP;
} else {
softleaf_t entry;
if (pte_swp_soft_dirty(pte))
flags |= PM_SOFT_DIRTY;
- if (pte_swp_uffd_wp(pte))
+ if (pte_swp_uffd(pte))
flags |= PM_UFFD_WP;
entry = softleaf_from_pte(pte);
if (pm->show_pfn) {
@@ -2108,7 +2111,7 @@ static int pagemap_pmd_range_thp(pmd_t *pmdp, unsigned long addr,
flags |= PM_PRESENT;
if (pmd_soft_dirty(pmd))
flags |= PM_SOFT_DIRTY;
- if (pmd_uffd_wp(pmd))
+ if (pmd_uffd(pmd))
flags |= PM_UFFD_WP;
if (pm->show_pfn)
frame = pmd_pfn(pmd) + idx;
@@ -2127,7 +2130,7 @@ static int pagemap_pmd_range_thp(pmd_t *pmdp, unsigned long addr,
flags |= PM_SWAP;
if (pmd_swp_soft_dirty(pmd))
flags |= PM_SOFT_DIRTY;
- if (pmd_swp_uffd_wp(pmd))
+ if (pmd_swp_uffd(pmd))
flags |= PM_UFFD_WP;
if (softleaf_has_pfn(entry))
page = softleaf_to_page(entry);
@@ -2233,14 +2236,14 @@ static int pagemap_hugetlb_range(pte_t *ptep, unsigned long hmask,
!hugetlb_pmd_shared(ptep))
flags |= PM_MMAP_EXCLUSIVE;
- if (huge_pte_uffd_wp(pte))
+ if (huge_pte_uffd(pte))
flags |= PM_UFFD_WP;
flags |= PM_PRESENT;
if (pm->show_pfn)
frame = pte_pfn(pte) +
((addr & ~hmask) >> PAGE_SHIFT);
- } else if (pte_swp_uffd_wp_any(pte)) {
+ } else if (pte_swp_uffd_any(pte)) {
flags |= PM_UFFD_WP;
}
@@ -2281,7 +2284,7 @@ static const struct mm_walk_ops pagemap_ops = {
* Bits 5-54 swap offset if swapped
* Bit 55 pte is soft-dirty (see Documentation/admin-guide/mm/soft-dirty.rst)
* Bit 56 page exclusively mapped
- * Bit 57 pte is uffd-wp write-protected
+ * Bit 57 pte is tracked by userfaultfd (uffd-wp or RWP)
* Bit 58 pte is a guard region
* Bits 59-60 zero
* Bit 61 page is file-page or shared-anon
@@ -2416,7 +2419,7 @@ static int pagemap_release(struct inode *inode, struct file *file)
PAGE_IS_FILE | PAGE_IS_PRESENT | \
PAGE_IS_SWAPPED | PAGE_IS_PFNZERO | \
PAGE_IS_HUGE | PAGE_IS_SOFT_DIRTY | \
- PAGE_IS_GUARD)
+ PAGE_IS_GUARD | PAGE_IS_ACCESSED)
#define PM_SCAN_FLAGS (PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC)
struct pagemap_scan_private {
@@ -2435,15 +2438,17 @@ static unsigned long pagemap_page_category(struct pagemap_scan_private *p,
if (pte_none(pte)) {
/*
- * An unpopulated pte carries no uffd-wp marker, i.e. it is not
- * write-protected, the same condition under which the present
- * and swap cases below report PAGE_IS_WRITTEN. Report it here
- * too so this generic path agrees with the PAGE_IS_WRITTEN fast
- * path in pagemap_scan_pmd_entry(), which reports pte_none as
- * written and, under PM_SCAN_WP_MATCHING, arms a marker. The
- * fast path applies no VMA test, so neither does this.
+ * An unpopulated pte carries no uffd bit, i.e. it is not
+ * write-protected. The PAGE_IS_WRITTEN fast path in
+ * pagemap_scan_pmd_entry() is now gated on a VM_UFFD_WP VMA;
+ * gate the pte_none report here the same way so the two paths
+ * still agree. RWP has no such fast path and an unpopulated
+ * page is not part of the RWP working set, so it is reported as
+ * neither.
*/
- return PAGE_IS_WRITTEN;
+ if (userfaultfd_wp(vma))
+ return PAGE_IS_WRITTEN;
+ return 0;
}
if (pte_present(pte)) {
@@ -2451,8 +2456,12 @@ static unsigned long pagemap_page_category(struct pagemap_scan_private *p,
categories = PAGE_IS_PRESENT;
- if (!pte_uffd_wp(pte))
- categories |= PAGE_IS_WRITTEN;
+ if (!pte_uffd(pte)) {
+ if (userfaultfd_wp(vma))
+ categories |= PAGE_IS_WRITTEN;
+ if (userfaultfd_rwp(vma))
+ categories |= PAGE_IS_ACCESSED;
+ }
if (p->masks_of_interest & PAGE_IS_FILE) {
page = vm_normal_page(vma, addr, pte);
@@ -2469,8 +2478,12 @@ static unsigned long pagemap_page_category(struct pagemap_scan_private *p,
categories = PAGE_IS_SWAPPED;
- if (!pte_swp_uffd_wp_any(pte))
- categories |= PAGE_IS_WRITTEN;
+ if (!pte_swp_uffd_any(pte)) {
+ if (userfaultfd_wp(vma))
+ categories |= PAGE_IS_WRITTEN;
+ if (userfaultfd_rwp(vma))
+ categories |= PAGE_IS_ACCESSED;
+ }
entry = softleaf_from_pte(pte);
if (softleaf_is_guard_marker(entry))
@@ -2494,13 +2507,13 @@ static void make_uffd_wp_pte(struct vm_area_struct *vma,
pte_t old_pte;
old_pte = ptep_modify_prot_start(vma, addr, pte);
- ptent = pte_mkuffd_wp(old_pte);
+ ptent = pte_mkuffd(old_pte);
ptep_modify_prot_commit(vma, addr, pte, old_pte, ptent);
} else if (pte_none(ptent)) {
set_pte_at(vma->vm_mm, addr, pte,
make_pte_marker(PTE_MARKER_UFFD_WP));
} else {
- ptent = pte_swp_mkuffd_wp(ptent);
+ ptent = pte_swp_mkuffd(ptent);
set_pte_at(vma->vm_mm, addr, pte, ptent);
}
}
@@ -2519,8 +2532,12 @@ static unsigned long pagemap_thp_category(struct pagemap_scan_private *p,
struct page *page;
categories |= PAGE_IS_PRESENT;
- if (!pmd_uffd_wp(pmd))
- categories |= PAGE_IS_WRITTEN;
+ if (!pmd_uffd(pmd)) {
+ if (userfaultfd_wp(vma))
+ categories |= PAGE_IS_WRITTEN;
+ if (userfaultfd_rwp(vma))
+ categories |= PAGE_IS_ACCESSED;
+ }
if (p->masks_of_interest & PAGE_IS_FILE) {
page = vm_normal_page_pmd(vma, addr, pmd);
@@ -2534,8 +2551,12 @@ static unsigned long pagemap_thp_category(struct pagemap_scan_private *p,
categories |= PAGE_IS_SOFT_DIRTY;
} else {
categories |= PAGE_IS_SWAPPED;
- if (!pmd_swp_uffd_wp(pmd))
- categories |= PAGE_IS_WRITTEN;
+ if (!pmd_swp_uffd(pmd)) {
+ if (userfaultfd_wp(vma))
+ categories |= PAGE_IS_WRITTEN;
+ if (userfaultfd_rwp(vma))
+ categories |= PAGE_IS_ACCESSED;
+ }
if (pmd_swp_soft_dirty(pmd))
categories |= PAGE_IS_SOFT_DIRTY;
@@ -2558,17 +2579,18 @@ static void make_uffd_wp_pmd(struct vm_area_struct *vma,
if (pmd_present(pmd)) {
old = pmdp_invalidate_ad(vma, addr, pmdp);
- pmd = pmd_mkuffd_wp(old);
+ pmd = pmd_mkuffd(old);
set_pmd_at(vma->vm_mm, addr, pmdp, pmd);
} else if (pmd_is_migration_entry(pmd)) {
- pmd = pmd_swp_mkuffd_wp(pmd);
+ pmd = pmd_swp_mkuffd(pmd);
set_pmd_at(vma->vm_mm, addr, pmdp, pmd);
}
}
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
#ifdef CONFIG_HUGETLB_PAGE
-static unsigned long pagemap_hugetlb_category(pte_t pte)
+static unsigned long pagemap_hugetlb_category(struct vm_area_struct *vma,
+ pte_t pte)
{
unsigned long categories = PAGE_IS_HUGE;
@@ -2583,8 +2605,12 @@ static unsigned long pagemap_hugetlb_category(pte_t pte)
if (pte_present(pte)) {
categories |= PAGE_IS_PRESENT;
- if (!huge_pte_uffd_wp(pte))
- categories |= PAGE_IS_WRITTEN;
+ if (!huge_pte_uffd(pte)) {
+ if (userfaultfd_wp(vma))
+ categories |= PAGE_IS_WRITTEN;
+ if (userfaultfd_rwp(vma))
+ categories |= PAGE_IS_ACCESSED;
+ }
if (!PageAnon(pte_page(pte)))
categories |= PAGE_IS_FILE;
if (is_zero_pfn(pte_pfn(pte)))
@@ -2594,8 +2620,12 @@ static unsigned long pagemap_hugetlb_category(pte_t pte)
} else {
categories |= PAGE_IS_SWAPPED;
- if (!pte_swp_uffd_wp_any(pte))
- categories |= PAGE_IS_WRITTEN;
+ if (!pte_swp_uffd_any(pte)) {
+ if (userfaultfd_wp(vma))
+ categories |= PAGE_IS_WRITTEN;
+ if (userfaultfd_rwp(vma))
+ categories |= PAGE_IS_ACCESSED;
+ }
if (pte_swp_soft_dirty(pte))
categories |= PAGE_IS_SOFT_DIRTY;
}
@@ -2622,12 +2652,12 @@ static void make_uffd_wp_huge_pte(struct vm_area_struct *vma,
if (softleaf_is_migration(entry)) {
set_huge_pte_at(vma->vm_mm, addr, ptep,
- pte_swp_mkuffd_wp(ptent), psize);
+ pte_swp_mkuffd(ptent), psize);
} else {
pte_t old_pte, new_pte;
old_pte = huge_ptep_modify_prot_start(vma, addr, ptep);
- new_pte = huge_pte_mkuffd_wp(old_pte);
+ new_pte = huge_pte_mkuffd(old_pte);
huge_ptep_modify_prot_commit(vma, addr, ptep, old_pte, new_pte);
}
}
@@ -2860,8 +2890,8 @@ static int pagemap_scan_pmd_entry(pmd_t *pmd, unsigned long start,
for (addr = start; addr != end; pte++, addr += PAGE_SIZE) {
pte_t ptent = ptep_get(pte);
- if ((pte_present(ptent) && pte_uffd_wp(ptent)) ||
- pte_swp_uffd_wp_any(ptent))
+ if ((pte_present(ptent) && pte_uffd(ptent)) ||
+ pte_swp_uffd_any(ptent))
continue;
make_uffd_wp_pte(vma, addr, pte, ptent);
if (!flush_end)
@@ -2871,15 +2901,16 @@ static int pagemap_scan_pmd_entry(pmd_t *pmd, unsigned long start,
goto flush_and_return;
}
- if (!p->arg.category_anyof_mask && !p->arg.category_inverted &&
+ if (userfaultfd_wp(vma) && !p->arg.category_anyof_mask &&
+ !p->arg.category_inverted &&
p->arg.category_mask == PAGE_IS_WRITTEN &&
p->arg.return_mask == PAGE_IS_WRITTEN) {
for (addr = start; addr < end; pte++, addr += PAGE_SIZE) {
unsigned long next = addr + PAGE_SIZE;
pte_t ptent = ptep_get(pte);
- if ((pte_present(ptent) && pte_uffd_wp(ptent)) ||
- pte_swp_uffd_wp_any(ptent))
+ if ((pte_present(ptent) && pte_uffd(ptent)) ||
+ pte_swp_uffd_any(ptent))
continue;
ret = pagemap_scan_output(p->cur_vma_category | PAGE_IS_WRITTEN,
p, addr, &next);
@@ -2946,7 +2977,8 @@ static int pagemap_scan_hugetlb_entry(pte_t *ptep, unsigned long hmask,
/* Go the short route when not write-protecting pages. */
pte = huge_ptep_get(walk->mm, start, ptep);
- categories = p->cur_vma_category | pagemap_hugetlb_category(pte);
+ categories = p->cur_vma_category |
+ pagemap_hugetlb_category(vma, pte);
if (!pagemap_scan_is_interesting_page(categories, p))
return 0;
@@ -2958,7 +2990,7 @@ static int pagemap_scan_hugetlb_entry(pte_t *ptep, unsigned long hmask,
ptl = huge_pte_lock(hstate_vma(vma), vma->vm_mm, ptep);
pte = huge_ptep_get(walk->mm, start, ptep);
- categories = p->cur_vma_category | pagemap_hugetlb_category(pte);
+ categories = p->cur_vma_category | pagemap_hugetlb_category(vma, pte);
if (!pagemap_scan_is_interesting_page(categories, p))
goto out_unlock;
@@ -3050,12 +3082,35 @@ static int pagemap_scan_pte_hole(unsigned long addr, unsigned long end,
{
struct pagemap_scan_private *p = walk->private;
struct vm_area_struct *vma = walk->vma;
+ unsigned long categories;
int ret, err;
- if (!vma || !pagemap_scan_is_interesting_page(p->cur_vma_category, p))
+ if (!vma)
+ return 0;
+
+ /*
+ * An unpopulated range with no page table -- e.g. a 2MB anon THP
+ * dropped via MADV_DONTNEED, which pagemap_page_category() never sees
+ * -- reads as written on a uffd-wp VMA, matching the pte_none case
+ * there. Reporting it also lets the PM_SCAN_WP_MATCHING arming below
+ * install markers (uffd_wp_range() allocates the page table under
+ * WP_UNPOPULATED), so the next scan sees it clean until re-written.
+ *
+ * hugetlb is excluded: pagemap_hugetlb_category() reports an empty
+ * hugetlb entry (huge_pte_none) as not-written, unlike
+ * pagemap_page_category(), which reports pte_none as written. This
+ * path fires for a hugetlb slot only when it has no page table;
+ * keeping that not-written matches how an allocated-but-empty
+ * hugetlb entry reads, so the two agree within the VMA.
+ */
+ categories = p->cur_vma_category;
+ if (userfaultfd_wp(vma) && !is_vm_hugetlb_page(vma))
+ categories |= PAGE_IS_WRITTEN;
+
+ if (!pagemap_scan_is_interesting_page(categories, p))
return 0;
- ret = pagemap_scan_output(p->cur_vma_category, p, addr, &end);
+ ret = pagemap_scan_output(categories, p, addr, &end);
if (addr == end)
return ret;
diff --git a/fs/smb/client/cifsacl.c b/fs/smb/client/cifsacl.c
index 07cf0e578233..9424281a7674 100644
--- a/fs/smb/client/cifsacl.c
+++ b/fs/smb/client/cifsacl.c
@@ -962,7 +962,7 @@ static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl,
*/
fattr->cf_mode &= ~07777;
fattr->cf_mode |=
- le32_to_cpu(ppace[i]->sid.sub_auth[2]);
+ le32_to_cpu(ppace[i]->sid.sub_auth[2]) & 07777;
break;
} else {
if (compare_sids(&(ppace[i]->sid), pownersid) == 0) {
diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 99f9e6dca62b..08e94633a9c1 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -250,6 +250,7 @@ struct cifs_open_info_data {
bool adjust_tz;
bool reparse_point;
bool contains_posix_file_info;
+ bool unknown_nlink;
struct {
/* ioctl response buffer */
struct {
diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h
index c4ababcb51a3..00168839c123 100644
--- a/fs/smb/client/cifsproto.h
+++ b/fs/smb/client/cifsproto.h
@@ -317,7 +317,7 @@ int generate_smb311signingkey(struct cifs_ses *ses,
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
-void cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb);
+void cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb, const char *reason, int rc);
bool couldbe_mf_symlink(const struct cifs_fattr *fattr);
int check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c
index d39175cdf1b1..40162d5554ea 100644
--- a/fs/smb/client/cifssmb.c
+++ b/fs/smb/client/cifssmb.c
@@ -5829,38 +5829,6 @@ CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
return rc;
}
-static int
-CIFSSMBSetPathInfoFB(const unsigned int xid, struct cifs_tcon *tcon,
- const char *fileName, const FILE_BASIC_INFO *data,
- const struct nls_table *nls_codepage,
- struct cifs_sb_info *cifs_sb)
-{
- int oplock = 0;
- struct cifs_open_parms oparms;
- struct cifs_fid fid;
- int rc;
-
- oparms = (struct cifs_open_parms) {
- .tcon = tcon,
- .cifs_sb = cifs_sb,
- .desired_access = GENERIC_WRITE,
- .create_options = cifs_create_options(cifs_sb, 0),
- .disposition = FILE_OPEN,
- .path = fileName,
- .fid = &fid,
- };
-
- rc = CIFS_open(xid, &oparms, &oplock, NULL);
- if (rc)
- goto out;
-
- rc = CIFSSMBSetFileInfo(xid, tcon, data, fid.netfid, current->tgid);
- CIFSSMBClose(xid, tcon, fid.netfid);
-out:
-
- return rc;
-}
-
int
CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
const char *fileName, const FILE_BASIC_INFO *data,
@@ -5939,10 +5907,6 @@ SetTimesRetry:
if (rc == -EAGAIN)
goto SetTimesRetry;
- if (rc == -EOPNOTSUPP)
- return CIFSSMBSetPathInfoFB(xid, tcon, fileName, data,
- nls_codepage, cifs_sb);
-
return rc;
}
diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
index a187398fbabd..ba749ec25a59 100644
--- a/fs/smb/client/connect.c
+++ b/fs/smb/client/connect.c
@@ -3876,7 +3876,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
* After reconnecting to a different server, unique ids won't match anymore, so we disable
* serverino. This prevents dentry revalidation to think the dentry are stale (ESTALE).
*/
- cifs_autodisable_serverino(cifs_sb);
+ cifs_autodisable_serverino(cifs_sb, "DFS failover may potentially connect to a different server, inode numbers won't match anymore", 0);
/*
* Force the use of prefix path to support failover on DFS paths that resolve to targets
* that have different prefix paths.
diff --git a/fs/smb/client/dfs_cache.c b/fs/smb/client/dfs_cache.c
index 83f8cf2f8d2b..8cd93cd2f00f 100644
--- a/fs/smb/client/dfs_cache.c
+++ b/fs/smb/client/dfs_cache.c
@@ -363,10 +363,10 @@ static struct cache_dfs_tgt *alloc_target(const char *name, int path_consumed)
{
struct cache_dfs_tgt *t;
- t = kmalloc_obj(*t, GFP_ATOMIC);
+ t = kmalloc_obj(*t, GFP_KERNEL);
if (!t)
return ERR_PTR(-ENOMEM);
- t->name = kstrdup(name, GFP_ATOMIC);
+ t->name = kstrdup(name, GFP_KERNEL);
if (!t->name) {
kfree(t);
return ERR_PTR(-ENOMEM);
@@ -626,7 +626,7 @@ static int update_cache_entry_locked(struct cache_entry *ce, const struct dfs_in
target = READ_ONCE(ce->tgthint);
if (target) {
- th = kstrdup(target->name, GFP_ATOMIC);
+ th = kstrdup(target->name, GFP_KERNEL);
if (!th)
return -ENOMEM;
}
@@ -760,11 +760,11 @@ static int setup_referral(const char *path, struct cache_entry *ce,
memset(ref, 0, sizeof(*ref));
- ref->path_name = kstrdup(path, GFP_ATOMIC);
+ ref->path_name = kstrdup(path, GFP_KERNEL);
if (!ref->path_name)
return -ENOMEM;
- ref->node_name = kstrdup(target, GFP_ATOMIC);
+ ref->node_name = kstrdup(target, GFP_KERNEL);
if (!ref->node_name) {
rc = -ENOMEM;
goto err_free_path;
@@ -1328,7 +1328,7 @@ int dfs_cache_remount_fs(struct cifs_sb_info *cifs_sb)
* After reconnecting to a different server, unique ids won't match anymore, so we disable
* serverino. This prevents dentry revalidation to think the dentry are stale (ESTALE).
*/
- cifs_autodisable_serverino(cifs_sb);
+ cifs_autodisable_serverino(cifs_sb, "DFS failover may potentially connect to a different server, inode numbers won't match anymore", 0);
/*
* Force the use of prefix path to support failover on DFS paths that resolve to targets
* that have different prefix paths.
diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c
index 0f2dcc444c22..968740e7c9c3 100644
--- a/fs/smb/client/file.c
+++ b/fs/smb/client/file.c
@@ -303,7 +303,7 @@ static void cifs_rreq_done(struct netfs_io_request *rreq)
/* we do not want atime to be less than mtime, it broke some apps */
atime = inode_set_atime_to_ts(inode, current_time(inode));
mtime = inode_get_mtime(inode);
- if (timespec64_compare(&atime, &mtime))
+ if (timespec64_compare(&atime, &mtime) < 0)
inode_set_atime_to_ts(inode, inode_get_mtime(inode));
}
diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
index 10de74937911..4e8e4a23e29d 100644
--- a/fs/smb/client/inode.c
+++ b/fs/smb/client/inode.c
@@ -909,6 +909,8 @@ static void cifs_open_info_to_fattr(struct cifs_fattr *fattr,
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
memset(fattr, 0, sizeof(*fattr));
+ if (data->unknown_nlink)
+ fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK;
fattr->cf_cifsattrs = le32_to_cpu(info->Attributes);
if (info->DeletePending)
fattr->cf_flags |= CIFS_FATTR_DELETE_PENDING;
@@ -1145,7 +1147,7 @@ static void cifs_set_fattr_ino(int xid, struct cifs_tcon *tcon, struct super_blo
fattr->cf_uniqueid = CIFS_I(*inode)->uniqueid;
else {
fattr->cf_uniqueid = iunique(sb, ROOT_I);
- cifs_autodisable_serverino(cifs_sb);
+ cifs_autodisable_serverino(cifs_sb, "Cannot retrieve inode number via get_srv_inum", rc);
}
return;
}
@@ -1642,7 +1644,7 @@ retry_iget5_locked:
fattr->cf_flags &= ~CIFS_FATTR_INO_COLLISION;
if (inode_has_hashed_dentries(inode)) {
- cifs_autodisable_serverino(CIFS_SB(sb));
+ cifs_autodisable_serverino(CIFS_SB(sb), "Inode number collision detected", 0);
iput(inode);
fattr->cf_uniqueid = iunique(sb, ROOT_I);
goto retry_iget5_locked;
@@ -1708,8 +1710,9 @@ struct inode *cifs_root_iget(struct super_block *sb)
iget_root:
if (!rc) {
if (fattr.cf_flags & CIFS_FATTR_JUNCTION) {
+ cifs_dbg(VFS, "Removing junction mark and disabling 'serverino' to prevent inode collisions\n");
fattr.cf_flags &= ~CIFS_FATTR_JUNCTION;
- cifs_autodisable_serverino(cifs_sb);
+ cifs_autodisable_serverino(cifs_sb, "Cannot retrieve attributes for junction point", rc);
}
inode = cifs_iget(sb, &fattr);
}
diff --git a/fs/smb/client/link.c b/fs/smb/client/link.c
index dd127917a340..8d5d6aca742a 100644
--- a/fs/smb/client/link.c
+++ b/fs/smb/client/link.c
@@ -234,7 +234,7 @@ cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
struct cifs_open_parms oparms;
struct cifs_io_parms io_parms = {0};
int buf_type = CIFS_NO_BUFFER;
- struct cifs_open_info_data query_data;
+ struct cifs_open_info_data query_data = {};
oparms = (struct cifs_open_parms) {
.tcon = tcon,
@@ -320,7 +320,7 @@ smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
int buf_type = CIFS_NO_BUFFER;
__le16 *utf16_path;
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
- struct smb2_file_all_info *pfile_info = NULL;
+ struct cifs_open_info_data data = {};
oparms = (struct cifs_open_parms) {
.tcon = tcon,
@@ -336,20 +336,12 @@ smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
if (utf16_path == NULL)
return -ENOMEM;
- pfile_info = kzalloc(sizeof(struct smb2_file_all_info) + PATH_MAX * 2,
- GFP_KERNEL);
-
- if (pfile_info == NULL) {
- kfree(utf16_path);
- return -ENOMEM;
- }
-
- rc = SMB2_open(xid, &oparms, utf16_path, &oplock, pfile_info, NULL,
+ rc = SMB2_open(xid, &oparms, utf16_path, &oplock, &data, NULL,
NULL, NULL);
if (rc)
goto qmf_out_open_fail;
- if (pfile_info->EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
+ if (data.fi.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
/* it's not a symlink */
rc = -ENOENT; /* Is there a better rc to return? */
goto qmf_out;
@@ -367,7 +359,6 @@ qmf_out:
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
qmf_out_open_fail:
kfree(utf16_path);
- kfree(pfile_info);
return rc;
}
diff --git a/fs/smb/client/misc.c b/fs/smb/client/misc.c
index 0c54b9b79a2c..e4bac2a0b85d 100644
--- a/fs/smb/client/misc.c
+++ b/fs/smb/client/misc.c
@@ -278,7 +278,7 @@ dump_smb(void *buf, int smb_buf_length)
}
void
-cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb)
+cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb, const char *reason, int rc)
{
unsigned int sbflags = cifs_sb_flags(cifs_sb);
@@ -290,6 +290,10 @@ cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb)
atomic_andnot(CIFS_MOUNT_SERVER_INUM, &cifs_sb->mnt_cifs_flags);
cifs_sb->mnt_cifs_serverino_autodisabled = true;
+ if (rc)
+ cifs_dbg(VFS, "%s: %d\n", reason, rc);
+ else
+ cifs_dbg(VFS, "%s\n", reason);
cifs_dbg(VFS, "Autodisabling the use of server inode numbers on %s\n",
tcon ? tcon->tree_name : "new server");
cifs_dbg(VFS, "The server doesn't seem to support them properly or the files might be on different servers (DFS)\n");
@@ -752,6 +756,10 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size,
node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
/* copy DfsPath */
+ if (le16_to_cpu(ref->DfsPathOffset) > data_end - (char *)ref) {
+ rc = -EINVAL;
+ goto parse_DFS_referrals_exit;
+ }
temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
max_len = data_end - temp;
node->path_name = cifs_strndup_from_utf16(temp, max_len,
@@ -762,6 +770,10 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size,
}
/* copy link target UNC */
+ if (le16_to_cpu(ref->NetworkAddressOffset) > data_end - (char *)ref) {
+ rc = -EINVAL;
+ goto parse_DFS_referrals_exit;
+ }
temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
max_len = data_end - temp;
node->node_name = cifs_strndup_from_utf16(temp, max_len,
diff --git a/fs/smb/client/readdir.c b/fs/smb/client/readdir.c
index a50c86bbe60f..ee5996e6d7d8 100644
--- a/fs/smb/client/readdir.c
+++ b/fs/smb/client/readdir.c
@@ -415,7 +415,7 @@ ffirst_retry:
if (rc == 0) {
cifsFile->invalidHandle = false;
} else if (rc == -EOPNOTSUPP && (sbflags & CIFS_MOUNT_SERVER_INUM)) {
- cifs_autodisable_serverino(cifs_sb);
+ cifs_autodisable_serverino(cifs_sb, "Cannot retrieve inode number via query_dir_first", rc);
goto ffirst_retry;
}
error_exit:
@@ -1029,7 +1029,7 @@ static int cifs_filldir(char *find_entry, struct file *file,
fattr.cf_uniqueid = de.ino;
} else {
fattr.cf_uniqueid = iunique(sb, ROOT_I);
- cifs_autodisable_serverino(cifs_sb);
+ cifs_autodisable_serverino(cifs_sb, "Cannot retrieve inode number from readdir", 0);
}
if ((sbflags & CIFS_MOUNT_MF_SYMLINKS) && couldbe_mf_symlink(&fattr))
diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c
index d34b3d99f6ed..dc5a8c1da623 100644
--- a/fs/smb/client/smb1ops.c
+++ b/fs/smb/client/smb1ops.c
@@ -505,21 +505,27 @@ static int
cifs_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb, const char *full_path)
{
- int rc;
- FILE_ALL_INFO *file_info;
+ int rc = -EOPNOTSUPP;
+ FILE_ALL_INFO file_info;
- file_info = kmalloc_obj(FILE_ALL_INFO);
- if (file_info == NULL)
- return -ENOMEM;
+ if (tcon->ses->capabilities & CAP_NT_SMBS)
+ rc = CIFSSMBQPathInfo(xid, tcon, full_path, &file_info,
+ 0 /* not legacy */, cifs_sb->local_nls,
+ cifs_remap(cifs_sb));
- rc = CIFSSMBQPathInfo(xid, tcon, full_path, file_info,
- 0 /* not legacy */, cifs_sb->local_nls,
- cifs_remap(cifs_sb));
+ /*
+ * Non-UNICODE variant of fallback functions below expands wildcards,
+ * so they cannot be used for querying paths with wildcard characters.
+ * Therefore for such paths returns -ENOENT as they cannot exist.
+ */
+ if ((rc == -EOPNOTSUPP || rc == -EINVAL) &&
+ !(tcon->ses->capabilities & CAP_UNICODE) &&
+ strpbrk(full_path, "*?\"><"))
+ rc = -ENOENT;
if (rc == -EOPNOTSUPP || rc == -EINVAL)
- rc = SMBQueryInformation(xid, tcon, full_path, file_info,
+ rc = SMBQueryInformation(xid, tcon, full_path, &file_info,
cifs_sb->local_nls, cifs_remap(cifs_sb));
- kfree(file_info);
return rc;
}
@@ -949,7 +955,7 @@ smb_set_file_info(struct inode *inode, const char *full_path,
struct cifs_open_parms oparms;
struct cifsFileInfo *open_file;
FILE_BASIC_INFO new_buf;
- struct cifs_open_info_data query_data;
+ struct cifs_open_info_data query_data = {};
__le64 write_time = buf->LastWriteTime;
struct cifsInodeInfo *cinode = CIFS_I(inode);
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
diff --git a/fs/smb/client/smb2file.c b/fs/smb/client/smb2file.c
index 6860eff31693..5ef919bce52d 100644
--- a/fs/smb/client/smb2file.c
+++ b/fs/smb/client/smb2file.c
@@ -154,8 +154,6 @@ int smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
__le16 *smb2_path;
__u8 smb2_oplock;
struct cifs_open_info_data *data = buf;
- struct smb2_file_all_info file_info = {};
- struct smb2_file_all_info *smb2_data = data ? &file_info : NULL;
struct kvec err_iov = {};
int err_buftype = CIFS_NO_BUFFER;
struct cifs_fid *fid = oparms->fid;
@@ -182,14 +180,14 @@ int smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
}
smb2_oplock = SMB2_OPLOCK_LEVEL_BATCH;
- rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, smb2_data, NULL, &err_iov,
+ rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, data, NULL, &err_iov,
&err_buftype);
if (rc == -EACCES && retry_without_read_attributes) {
free_rsp_buf(err_buftype, err_iov.iov_base);
memset(&err_iov, 0, sizeof(err_iov));
err_buftype = CIFS_NO_BUFFER;
oparms->desired_access &= ~FILE_READ_ATTRIBUTES;
- rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, smb2_data, NULL, &err_iov,
+ rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, data, NULL, &err_iov,
&err_buftype);
}
if (rc && data) {
@@ -202,9 +200,9 @@ int smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
oparms->path,
&data->symlink_target);
if (!rc) {
- memset(smb2_data, 0, sizeof(*smb2_data));
+ memset(&data->fi, 0, sizeof(data->fi));
oparms->create_options |= OPEN_REPARSE_POINT;
- rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, smb2_data,
+ rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, data,
NULL, NULL, NULL);
oparms->create_options &= ~OPEN_REPARSE_POINT;
}
@@ -238,23 +236,22 @@ int smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
rc = 0;
}
- if (smb2_data) {
+ if (data) {
/* if open response does not have IndexNumber field - get it */
- if (smb2_data->IndexNumber == 0) {
+ if (data->fi.IndexNumber == 0) {
rc = SMB2_get_srv_num(xid, oparms->tcon,
fid->persistent_fid,
fid->volatile_fid,
- &smb2_data->IndexNumber);
+ &data->fi.IndexNumber);
if (rc) {
/*
* let get_inode_info disable server inode
* numbers
*/
- smb2_data->IndexNumber = 0;
+ data->fi.IndexNumber = 0;
rc = 0;
}
}
- memcpy(&data->fi, smb2_data, sizeof(data->fi));
}
*oplock = smb2_oplock;
diff --git a/fs/smb/client/smb2misc.c b/fs/smb/client/smb2misc.c
index 2a7355ce1a07..6270b33147d2 100644
--- a/fs/smb/client/smb2misc.c
+++ b/fs/smb/client/smb2misc.c
@@ -19,6 +19,8 @@
#include "nterr.h"
#include "cached_dir.h"
+static unsigned int __smb2_calc_size(void *buf, bool *have_data);
+
static int
check_smb2_hdr(struct smb2_hdr *shdr, __u64 mid)
{
@@ -145,6 +147,7 @@ smb2_check_message(char *buf, unsigned int pdu_len, unsigned int len,
int command;
__u32 calc_len; /* calculated length */
__u64 mid;
+ bool have_data;
/* If server is a channel, select the primary channel */
pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
@@ -228,7 +231,8 @@ smb2_check_message(char *buf, unsigned int pdu_len, unsigned int len,
}
}
- calc_len = smb2_calc_size(buf);
+ have_data = false;
+ calc_len = __smb2_calc_size(buf, &have_data);
/* For SMB2_IOCTL, OutputOffset and OutputLength are optional, so might
* be 0, and not a real miscalculation */
@@ -247,8 +251,13 @@ smb2_check_message(char *buf, unsigned int pdu_len, unsigned int len,
/* Windows 7 server returns 24 bytes more */
if (calc_len + 24 == len && command == SMB2_OPLOCK_BREAK_HE)
return 0;
- /* server can return one byte more due to implied bcc[0] */
- if (calc_len == len + 1)
+ /*
+ * Server can return one byte more due to implied bcc[0].
+ * Allow it only when there is no data area; if data_length > 0
+ * the +1 gap indicates an overreported data length rather than
+ * the bcc[0] omission.
+ */
+ if (calc_len == len + 1 && !have_data)
return 0;
/*
@@ -409,14 +418,17 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *shdr)
/*
* Calculate the size of the SMB message based on the fixed header
* portion, the number of word parameters and the data portion of the message.
+ * If have_data is non-NULL, it is set to true when a non-empty data area was
+ * found (data_length > 0), allowing callers to distinguish the implied bcc[0]
+ * case (no data area) from an overreported data length.
*/
-unsigned int
-smb2_calc_size(void *buf)
+static unsigned int
+__smb2_calc_size(void *buf, bool *have_data)
{
struct smb2_pdu *pdu = buf;
struct smb2_hdr *shdr = &pdu->hdr;
int offset; /* the offset from the beginning of SMB to data area */
- int data_length; /* the length of the variable length data area */
+ int data_length = 0; /* the length of the variable length data area */
/* Structure Size has already been checked to make sure it is 64 */
int len = le16_to_cpu(shdr->StructureSize);
@@ -449,9 +461,17 @@ smb2_calc_size(void *buf)
}
calc_size_exit:
cifs_dbg(FYI, "SMB2 len %d\n", len);
+ if (have_data)
+ *have_data = (data_length > 0);
return len;
}
+unsigned int
+smb2_calc_size(void *buf)
+{
+ return __smb2_calc_size(buf, NULL);
+}
+
/* Note: caller must free return buffer */
__le16 *
cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb)
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index 06e9322a762a..6bce44b171e4 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -1772,8 +1772,8 @@ replay_again:
if (le32_to_cpu(io_rsp->OutputCount) < qi.input_buffer_length)
qi.input_buffer_length = le32_to_cpu(io_rsp->OutputCount);
if (qi.input_buffer_length > 0 &&
- le32_to_cpu(io_rsp->OutputOffset) + qi.input_buffer_length
- > rsp_iov[1].iov_len) {
+ size_add(le32_to_cpu(io_rsp->OutputOffset),
+ qi.input_buffer_length) > rsp_iov[1].iov_len) {
rc = -EFAULT;
goto out;
}
@@ -5237,7 +5237,7 @@ int __cifs_sfu_make_node(unsigned int xid, struct inode *inode,
{
struct TCP_Server_Info *server = tcon->ses->server;
struct cifs_open_parms oparms;
- struct cifs_open_info_data idata;
+ struct cifs_open_info_data idata = {};
struct cifs_io_parms io_parms = {};
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct cifs_fid fid;
@@ -5286,16 +5286,13 @@ int __cifs_sfu_make_node(unsigned int xid, struct inode *inode,
data = (u8 *)symname_utf16;
break;
case S_IFSOCK:
- type_len = 8;
- strscpy(type, "LnxSOCK");
- data = (u8 *)&pdev;
- data_len = sizeof(pdev);
+ /* SFU socket is system file with one zero byte */
+ type_len = 1;
+ type[0] = '\0';
break;
case S_IFIFO:
- type_len = 8;
- strscpy(type, "LnxFIFO");
- data = (u8 *)&pdev;
- data_len = sizeof(pdev);
+ /* SFU fifo is system file which is empty */
+ type_len = 0;
break;
default:
rc = -EPERM;
diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index 95c0efe9d43b..8f83ab377db1 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -3287,7 +3287,7 @@ SMB2_open_free(struct smb_rqst *rqst)
int
SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
- __u8 *oplock, struct smb2_file_all_info *buf,
+ __u8 *oplock, struct cifs_open_info_data *buf,
struct create_posix_rsp *posix,
struct kvec *err_iov, int *buftype)
{
@@ -3302,6 +3302,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
int rc = 0;
int flags = 0;
int retries = 0, cur_sleep = 0;
+ struct smb2_file_all_info *file_info = buf ? &buf->fi : NULL;
replay_again:
/* reinitialize for possible replay */
@@ -3370,21 +3371,22 @@ replay_again:
oparms->fid->mid = le64_to_cpu(rsp->hdr.MessageId);
#endif /* CIFS_DEBUG2 */
- if (buf) {
- buf->CreationTime = rsp->CreationTime;
- buf->LastAccessTime = rsp->LastAccessTime;
- buf->LastWriteTime = rsp->LastWriteTime;
- buf->ChangeTime = rsp->ChangeTime;
- buf->AllocationSize = rsp->AllocationSize;
- buf->EndOfFile = rsp->EndofFile;
- buf->Attributes = rsp->FileAttributes;
- buf->NumberOfLinks = cpu_to_le32(1);
- buf->DeletePending = 0; /* successful open = not delete pending */
+ if (file_info) {
+ file_info->CreationTime = rsp->CreationTime;
+ file_info->LastAccessTime = rsp->LastAccessTime;
+ file_info->LastWriteTime = rsp->LastWriteTime;
+ file_info->ChangeTime = rsp->ChangeTime;
+ file_info->AllocationSize = rsp->AllocationSize;
+ file_info->EndOfFile = rsp->EndofFile;
+ file_info->Attributes = rsp->FileAttributes;
+ file_info->NumberOfLinks = cpu_to_le32(1);
+ buf->unknown_nlink = true;
+ file_info->DeletePending = 0; /* successful open = not delete pending */
}
rc = smb2_parse_contexts(server, &rsp_iov, &oparms->fid->epoch,
- oparms->fid->lease_key, oplock, buf, posix);
+ oparms->fid->lease_key, oplock, file_info, posix);
trace_smb3_open_done(xid, rsp->PersistentFileId, tcon->tid, ses->Suid,
oparms->create_options, oparms->desired_access,
diff --git a/fs/smb/client/smb2proto.h b/fs/smb/client/smb2proto.h
index 78a4e1c340f9..e01effe45ae2 100644
--- a/fs/smb/client/smb2proto.h
+++ b/fs/smb/client/smb2proto.h
@@ -136,7 +136,7 @@ int SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
struct cifs_tcon *tcon, const struct nls_table *cp);
int SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon);
int SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms,
- __le16 *path, __u8 *oplock, struct smb2_file_all_info *buf,
+ __le16 *path, __u8 *oplock, struct cifs_open_info_data *buf,
struct create_posix_rsp *posix, struct kvec *err_iov,
int *buftype);
int SMB2_open_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c
index cc6dc6e1d84d..30cec5600149 100644
--- a/fs/udf/balloc.c
+++ b/fs/udf/balloc.c
@@ -502,6 +502,8 @@ static int udf_table_prealloc_blocks(struct super_block *sb,
int8_t etype = -1;
struct udf_inode_info *iinfo;
int ret = 0;
+ /* AED block freed by udf_delete_aext(), released after unlock */
+ struct kernel_lb_addr freed = { .partitionReferenceNum = 0xFFFF };
if (first_block >= sbi->s_partmaps[partition].s_partition_len)
return 0;
@@ -541,7 +543,7 @@ static int udf_table_prealloc_blocks(struct super_block *sb,
udf_write_aext(table, &epos, &eloc,
(etype << 30) | elen, 1);
} else
- udf_delete_aext(table, epos);
+ udf_delete_aext(table, epos, &freed);
} else {
alloc_count = 0;
}
@@ -552,6 +554,8 @@ err_out:
if (alloc_count)
udf_add_free_space(sb, partition, -alloc_count);
mutex_unlock(&sbi->s_alloc_mutex);
+ if (freed.partitionReferenceNum != 0xFFFF)
+ udf_free_blocks(sb, table, &freed, 0, 1);
return alloc_count;
}
@@ -560,6 +564,8 @@ static udf_pblk_t udf_table_new_block(struct super_block *sb,
uint32_t goal, int *err)
{
struct udf_sb_info *sbi = UDF_SB(sb);
+ /* AED block freed by udf_delete_aext(), released after unlock */
+ struct kernel_lb_addr freed = { .partitionReferenceNum = 0xFFFF };
uint32_t spread = 0xFFFFFFFF, nspread = 0xFFFFFFFF;
udf_pblk_t newblock = 0;
uint32_t adsize;
@@ -643,12 +649,14 @@ static udf_pblk_t udf_table_new_block(struct super_block *sb,
if (goal_elen)
udf_write_aext(table, &goal_epos, &goal_eloc, goal_elen, 1);
else
- udf_delete_aext(table, goal_epos);
+ udf_delete_aext(table, goal_epos, &freed);
brelse(goal_epos.bh);
udf_add_free_space(sb, partition, -1);
mutex_unlock(&sbi->s_alloc_mutex);
+ if (freed.partitionReferenceNum != 0xFFFF)
+ udf_free_blocks(sb, table, &freed, 0, 1);
*err = 0;
return newblock;
}
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index 67bcf83758c8..c97914aa8d8b 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -1204,7 +1204,7 @@ static int udf_update_extents(struct inode *inode, struct kernel_long_ad *laarr,
if (startnum > endnum) {
for (i = 0; i < (startnum - endnum); i++)
- udf_delete_aext(inode, *epos);
+ udf_delete_aext(inode, *epos, NULL);
} else if (startnum < endnum) {
for (i = 0; i < (endnum - startnum); i++) {
err = udf_insert_aext(inode, *epos,
@@ -2299,6 +2299,13 @@ int udf_current_aext(struct inode *inode, struct extent_position *epos,
return -EINVAL;
}
+ if (eloc->partitionReferenceNum >= UDF_SB(inode->i_sb)->s_partitions) {
+ udf_debug("invalid partition reference %u (partitions %u)\n",
+ eloc->partitionReferenceNum,
+ UDF_SB(inode->i_sb)->s_partitions);
+ return -EFSCORRUPTED;
+ }
+
return 1;
}
@@ -2328,7 +2335,8 @@ static int udf_insert_aext(struct inode *inode, struct extent_position epos,
return ret;
}
-int8_t udf_delete_aext(struct inode *inode, struct extent_position epos)
+int8_t udf_delete_aext(struct inode *inode, struct extent_position epos,
+ struct kernel_lb_addr *freed)
{
struct extent_position oepos;
int adsize;
@@ -2378,7 +2386,19 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos)
elen = 0;
if (epos.bh != oepos.bh) {
- udf_free_blocks(inode->i_sb, inode, &epos.block, 0, 1);
+ /*
+ * The block that held the now-empty allocation extent must be
+ * returned to free space. When the caller already holds
+ * s_alloc_mutex (the space-table allocator in balloc.c),
+ * freeing it inline would recurse through udf_free_blocks()
+ * into udf_table_free_blocks() and deadlock re-acquiring
+ * s_alloc_mutex. In that case report the block to the caller,
+ * which frees it after dropping the lock.
+ */
+ if (freed)
+ *freed = epos.block;
+ else
+ udf_free_blocks(inode->i_sb, inode, &epos.block, 0, 1);
udf_write_aext(inode, &oepos, &eloc, elen, 1);
udf_write_aext(inode, &oepos, &eloc, elen, 1);
if (!oepos.bh) {
diff --git a/fs/udf/partition.c b/fs/udf/partition.c
index 2b85c9501bed..ad8dcedca263 100644
--- a/fs/udf/partition.c
+++ b/fs/udf/partition.c
@@ -55,7 +55,7 @@ uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block,
map = &sbi->s_partmaps[partition];
vdata = &map->s_type_specific.s_virtual;
- if (block > vdata->s_num_entries) {
+ if (block >= vdata->s_num_entries) {
udf_debug("Trying to access block beyond end of VAT (%u max %u)\n",
block, vdata->s_num_entries);
return 0xFFFFFFFF;
diff --git a/fs/udf/super.c b/fs/udf/super.c
index 7b85f5a2b79f..9686078bba64 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -2054,6 +2054,17 @@ static int udf_load_vrs(struct super_block *sb, struct udf_options *uopt,
return 0;
}
+static void udf_mark_buffer_dirty(struct buffer_head *bh)
+{
+ /*
+ * We set buffer uptodate unconditionally here to avoid spurious
+ * warnings from mark_buffer_dirty() when previous EIO has marked
+ * the buffer as !uptodate
+ */
+ set_buffer_uptodate(bh);
+ mark_buffer_dirty(bh);
+}
+
static void udf_finalize_lvid(struct logicalVolIntegrityDesc *lvid)
{
struct timespec64 ts;
@@ -2089,7 +2100,7 @@ static void udf_open_lvid(struct super_block *sb)
UDF_SET_FLAG(sb, UDF_FLAG_INCONSISTENT);
udf_finalize_lvid(lvid);
- mark_buffer_dirty(bh);
+ udf_mark_buffer_dirty(bh);
sbi->s_lvid_dirty = 0;
mutex_unlock(&sbi->s_alloc_mutex);
/* Make opening of filesystem visible on the media immediately */
@@ -2122,14 +2133,8 @@ static void udf_close_lvid(struct super_block *sb)
if (!UDF_QUERY_FLAG(sb, UDF_FLAG_INCONSISTENT))
lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_CLOSE);
- /*
- * We set buffer uptodate unconditionally here to avoid spurious
- * warnings from mark_buffer_dirty() when previous EIO has marked
- * the buffer as !uptodate
- */
- set_buffer_uptodate(bh);
udf_finalize_lvid(lvid);
- mark_buffer_dirty(bh);
+ udf_mark_buffer_dirty(bh);
sbi->s_lvid_dirty = 0;
mutex_unlock(&sbi->s_alloc_mutex);
/* Make closing of filesystem visible on the media immediately */
@@ -2411,7 +2416,7 @@ static int udf_sync_fs(struct super_block *sb, int wait)
* Blockdevice will be synced later so we don't have to submit
* the buffer for IO
*/
- mark_buffer_dirty(bh);
+ udf_mark_buffer_dirty(bh);
sbi->s_lvid_dirty = 0;
}
mutex_unlock(&sbi->s_alloc_mutex);
diff --git a/fs/udf/truncate.c b/fs/udf/truncate.c
index 41b2bfd30449..0990f94b8551 100644
--- a/fs/udf/truncate.c
+++ b/fs/udf/truncate.c
@@ -159,7 +159,7 @@ void udf_discard_prealloc(struct inode *inode)
if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
lbcount -= elen;
- udf_delete_aext(inode, prev_epos);
+ udf_delete_aext(inode, prev_epos, NULL);
udf_free_blocks(inode->i_sb, inode, &eloc, 0,
DIV_ROUND_UP(elen, bsize));
}
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h
index 6d951e05c004..21de6925fc68 100644
--- a/fs/udf/udfdecl.h
+++ b/fs/udf/udfdecl.h
@@ -170,7 +170,8 @@ extern int udf_add_aext(struct inode *, struct extent_position *,
struct kernel_lb_addr *, uint32_t, int);
extern void udf_write_aext(struct inode *, struct extent_position *,
struct kernel_lb_addr *, uint32_t, int);
-extern int8_t udf_delete_aext(struct inode *, struct extent_position);
+extern int8_t udf_delete_aext(struct inode *, struct extent_position,
+ struct kernel_lb_addr *);
extern int udf_next_aext(struct inode *inode, struct extent_position *epos,
struct kernel_lb_addr *eloc, uint32_t *elen,
int8_t *etype, int inc);
diff --git a/include/asm-generic/hugetlb.h b/include/asm-generic/hugetlb.h
index e1a2e1b7c8e7..635c41cc3479 100644
--- a/include/asm-generic/hugetlb.h
+++ b/include/asm-generic/hugetlb.h
@@ -37,24 +37,24 @@ static inline pte_t huge_pte_modify(pte_t pte, pgprot_t newprot)
return pte_modify(pte, newprot);
}
-#ifndef __HAVE_ARCH_HUGE_PTE_MKUFFD_WP
-static inline pte_t huge_pte_mkuffd_wp(pte_t pte)
+#ifndef __HAVE_ARCH_HUGE_PTE_MKUFFD
+static inline pte_t huge_pte_mkuffd(pte_t pte)
{
- return huge_pte_wrprotect(pte_mkuffd_wp(pte));
+ return huge_pte_wrprotect(pte_mkuffd(pte));
}
#endif
-#ifndef __HAVE_ARCH_HUGE_PTE_CLEAR_UFFD_WP
-static inline pte_t huge_pte_clear_uffd_wp(pte_t pte)
+#ifndef __HAVE_ARCH_HUGE_PTE_CLEAR_UFFD
+static inline pte_t huge_pte_clear_uffd(pte_t pte)
{
- return pte_clear_uffd_wp(pte);
+ return pte_clear_uffd(pte);
}
#endif
-#ifndef __HAVE_ARCH_HUGE_PTE_UFFD_WP
-static inline int huge_pte_uffd_wp(pte_t pte)
+#ifndef __HAVE_ARCH_HUGE_PTE_UFFD
+static inline int huge_pte_uffd(pte_t pte)
{
- return pte_uffd_wp(pte);
+ return pte_uffd(pte);
}
#endif
diff --git a/include/asm-generic/pgtable_uffd.h b/include/asm-generic/pgtable_uffd.h
index 0d85791efdf7..30e88fc1de2f 100644
--- a/include/asm-generic/pgtable_uffd.h
+++ b/include/asm-generic/pgtable_uffd.h
@@ -2,79 +2,79 @@
#define _ASM_GENERIC_PGTABLE_UFFD_H
/*
- * Some platforms can customize the uffd-wp bit, making it unavailable
+ * Some platforms can customize the uffd PTE bit, making it unavailable
* even if the architecture provides the resource.
* Adding this API allows architectures to add their own checks for the
* devices on which the kernel is running.
* Note: When overriding it, please make sure the
* CONFIG_HAVE_ARCH_USERFAULTFD_WP is part of this macro.
*/
-#ifndef pgtable_supports_uffd_wp
-#define pgtable_supports_uffd_wp() IS_ENABLED(CONFIG_HAVE_ARCH_USERFAULTFD_WP)
+#ifndef pgtable_supports_uffd
+#define pgtable_supports_uffd() IS_ENABLED(CONFIG_HAVE_ARCH_USERFAULTFD_WP)
#endif
static inline bool uffd_supports_wp_marker(void)
{
- return pgtable_supports_uffd_wp() && IS_ENABLED(CONFIG_PTE_MARKER_UFFD_WP);
+ return pgtable_supports_uffd() && IS_ENABLED(CONFIG_PTE_MARKER_UFFD_WP);
}
#ifndef CONFIG_HAVE_ARCH_USERFAULTFD_WP
-static __always_inline int pte_uffd_wp(pte_t pte)
+static __always_inline int pte_uffd(pte_t pte)
{
return 0;
}
-static __always_inline int pmd_uffd_wp(pmd_t pmd)
+static __always_inline int pmd_uffd(pmd_t pmd)
{
return 0;
}
-static __always_inline pte_t pte_mkuffd_wp(pte_t pte)
+static __always_inline pte_t pte_mkuffd(pte_t pte)
{
return pte;
}
-static __always_inline pmd_t pmd_mkuffd_wp(pmd_t pmd)
+static __always_inline pmd_t pmd_mkuffd(pmd_t pmd)
{
return pmd;
}
-static __always_inline pte_t pte_clear_uffd_wp(pte_t pte)
+static __always_inline pte_t pte_clear_uffd(pte_t pte)
{
return pte;
}
-static __always_inline pmd_t pmd_clear_uffd_wp(pmd_t pmd)
+static __always_inline pmd_t pmd_clear_uffd(pmd_t pmd)
{
return pmd;
}
-static __always_inline pte_t pte_swp_mkuffd_wp(pte_t pte)
+static __always_inline pte_t pte_swp_mkuffd(pte_t pte)
{
return pte;
}
-static __always_inline int pte_swp_uffd_wp(pte_t pte)
+static __always_inline int pte_swp_uffd(pte_t pte)
{
return 0;
}
-static __always_inline pte_t pte_swp_clear_uffd_wp(pte_t pte)
+static __always_inline pte_t pte_swp_clear_uffd(pte_t pte)
{
return pte;
}
-static inline pmd_t pmd_swp_mkuffd_wp(pmd_t pmd)
+static inline pmd_t pmd_swp_mkuffd(pmd_t pmd)
{
return pmd;
}
-static inline int pmd_swp_uffd_wp(pmd_t pmd)
+static inline int pmd_swp_uffd(pmd_t pmd)
{
return 0;
}
-static inline pmd_t pmd_swp_clear_uffd_wp(pmd_t pmd)
+static inline pmd_t pmd_swp_clear_uffd(pmd_t pmd)
{
return pmd;
}
diff --git a/include/drm/drm_gpusvm.h b/include/drm/drm_gpusvm.h
index 8a4d7134a9a7..b7d987bf76aa 100644
--- a/include/drm/drm_gpusvm.h
+++ b/include/drm/drm_gpusvm.h
@@ -109,9 +109,7 @@ struct drm_gpusvm_notifier {
/**
* struct drm_gpusvm_pages_flags - Structure representing a GPU SVM pages flags
*
- * @migrate_devmem: Flag indicating whether the pages can be migrated to device memory
* @unmapped: Flag indicating if the pages has been unmapped
- * @partial_unmap: Flag indicating if the pages has been partially unmapped
* @has_devmem_pages: Flag indicating if the pages has devmem pages
* @has_dma_mapping: Flag indicating if the pages has a DMA mapping
* @__flags: Flags for pages in u16 form (used for READ_ONCE)
@@ -119,11 +117,8 @@ struct drm_gpusvm_notifier {
struct drm_gpusvm_pages_flags {
union {
struct {
- /* All flags below must be set upon creation */
- u16 migrate_devmem : 1;
/* All flags below must be set / cleared under notifier lock */
u16 unmapped : 1;
- u16 partial_unmap : 1;
u16 has_devmem_pages : 1;
u16 has_dma_mapping : 1;
};
@@ -134,6 +129,7 @@ struct drm_gpusvm_pages_flags {
/**
* struct drm_gpusvm_pages - Structure representing a GPU SVM mapped pages
*
+ * @drm: The DRM device that owns the dma mappings
* @dma_addr: Device address array
* @dpagemap: The struct drm_pagemap of the device pages we're dma-mapping.
* Note this is assuming only one drm_pagemap per range is allowed.
@@ -143,6 +139,7 @@ struct drm_gpusvm_pages_flags {
* @flags: Flags for the range; see &struct drm_gpusvm_pages_flags
*/
struct drm_gpusvm_pages {
+ struct drm_device *drm;
struct drm_pagemap_addr *dma_addr;
struct drm_pagemap *dpagemap;
struct dma_iova_state state;
@@ -152,6 +149,27 @@ struct drm_gpusvm_pages {
};
/**
+ * struct drm_gpusvm_range_flags - Range-level GPU SVM flags
+ *
+ * @migrate_devmem: Flag indicating whether the range can be migrated to device memory
+ * @unmapped: Flag indicating if the range has been unmapped
+ * @partial_unmap: Flag indicating if the range has been partially unmapped
+ * @__flags: All flags in u16 form (used for READ_ONCE)
+ */
+struct drm_gpusvm_range_flags {
+ union {
+ struct {
+ /* All flags below must be set upon creation */
+ u16 migrate_devmem : 1;
+ /* All flags below must be set / cleared under notifier lock */
+ u16 unmapped : 1;
+ u16 partial_unmap : 1;
+ };
+ u16 __flags;
+ };
+};
+
+/**
* struct drm_gpusvm_range - Structure representing a GPU SVM range
*
* @gpusvm: Pointer to the GPU SVM structure
@@ -159,7 +177,7 @@ struct drm_gpusvm_pages {
* @refcount: Reference count for the range
* @itree: Interval tree node for the range (inserted in GPU SVM notifier)
* @entry: List entry to fast interval tree traversal
- * @pages: The pages for this range.
+ * @flags: Flags for range see &struct drm_gpusvm_range_flags
*
* This structure represents a GPU SVM range used for tracking memory ranges
* mapped in a DRM device.
@@ -170,14 +188,13 @@ struct drm_gpusvm_range {
struct kref refcount;
struct interval_tree_node itree;
struct list_head entry;
- struct drm_gpusvm_pages pages;
+ struct drm_gpusvm_range_flags flags;
};
/**
* struct drm_gpusvm - GPU SVM structure
*
* @name: Name of the GPU SVM
- * @drm: Pointer to the DRM device structure
* @mm: Pointer to the mm_struct for the address space
* @mm_start: Start address of GPU SVM
* @mm_range: Range of the GPU SVM
@@ -201,7 +218,6 @@ struct drm_gpusvm_range {
*/
struct drm_gpusvm {
const char *name;
- struct drm_device *drm;
struct mm_struct *mm;
unsigned long mm_start;
unsigned long mm_range;
@@ -253,7 +269,7 @@ struct drm_gpusvm_ctx {
};
int drm_gpusvm_init(struct drm_gpusvm *gpusvm,
- const char *name, struct drm_device *drm,
+ const char *name,
struct mm_struct *mm,
unsigned long mm_start, unsigned long mm_range,
unsigned long notifier_size,
@@ -287,16 +303,8 @@ drm_gpusvm_range_get(struct drm_gpusvm_range *range);
void drm_gpusvm_range_put(struct drm_gpusvm_range *range);
-bool drm_gpusvm_range_pages_valid(struct drm_gpusvm *gpusvm,
- struct drm_gpusvm_range *range);
-
-int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm,
- struct drm_gpusvm_range *range,
- const struct drm_gpusvm_ctx *ctx);
-
-void drm_gpusvm_range_unmap_pages(struct drm_gpusvm *gpusvm,
- struct drm_gpusvm_range *range,
- const struct drm_gpusvm_ctx *ctx);
+bool drm_gpusvm_pages_valid(struct drm_gpusvm *gpusvm,
+ struct drm_gpusvm_pages *svm_pages);
bool drm_gpusvm_has_mapping(struct drm_gpusvm *gpusvm, unsigned long start,
unsigned long end);
@@ -310,6 +318,8 @@ drm_gpusvm_range_find(struct drm_gpusvm_notifier *notifier, unsigned long start,
unsigned long end);
void drm_gpusvm_range_set_unmapped(struct drm_gpusvm_range *range,
+ struct drm_gpusvm_pages *pages,
+ unsigned int pages_count,
const struct mmu_notifier_range *mmu_range);
int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
@@ -329,6 +339,23 @@ void drm_gpusvm_free_pages(struct drm_gpusvm *gpusvm,
unsigned long npages);
/**
+ * drm_gpusvm_init_pages() - Initialize a freshly allocated drm_gpusvm_pages
+ * @svm_pages: Pointer to the drm_gpusvm_pages to initialize.
+ * @drm: The DRM device that will own DMA mappings for this pages object.
+ *
+ * Drivers that embed one or more drm_gpusvm_pages in their own range
+ * structure must call this once on each pages instance after allocation,
+ * before the first drm_gpusvm_get_pages() / unmap / free.
+ */
+static inline void drm_gpusvm_init_pages(struct drm_gpusvm_pages *svm_pages,
+ struct drm_device *drm)
+{
+ memset(svm_pages, 0, sizeof(*svm_pages));
+ svm_pages->drm = drm;
+ svm_pages->notifier_seq = LONG_MAX;
+}
+
+/**
* enum drm_gpusvm_scan_result - Scan result from the drm_gpusvm_scan_mm() function.
* @DRM_GPUSVM_SCAN_UNPOPULATED: At least one page was not present or inaccessible.
* @DRM_GPUSVM_SCAN_EQUAL: All pages belong to the struct dev_pagemap indicated as
diff --git a/include/drm/drm_of.h b/include/drm/drm_of.h
index 7bcc0ccfe0f4..ebebed14c611 100644
--- a/include/drm/drm_of.h
+++ b/include/drm/drm_of.h
@@ -20,6 +20,8 @@ struct device_node;
struct mipi_dsi_device_info;
struct mipi_dsi_host;
+enum drm_panel_orientation;
+
/**
* enum drm_lvds_dual_link_pixels - Pixel order of an LVDS dual-link connection
* @DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS: Even pixels are expected to be generated
@@ -47,6 +49,8 @@ int drm_of_component_probe(struct device *dev,
int drm_of_encoder_active_endpoint(struct device_node *node,
struct drm_encoder *encoder,
struct of_endpoint *endpoint);
+int drm_of_get_panel_orientation(const struct device_node *np,
+ enum drm_panel_orientation *orientation);
int drm_of_find_panel_or_bridge(const struct device_node *np,
int port, int endpoint,
struct drm_panel **panel,
@@ -101,6 +105,13 @@ static inline int drm_of_encoder_active_endpoint(struct device_node *node,
{
return -EINVAL;
}
+
+static inline int drm_of_get_panel_orientation(const struct device_node *np,
+ enum drm_panel_orientation *orientation)
+{
+ return -EINVAL;
+}
+
static inline int drm_of_find_panel_or_bridge(const struct device_node *np,
int port, int endpoint,
struct drm_panel **panel,
diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h
index 86b3f9c65c92..b87323443f49 100644
--- a/include/drm/drm_panel.h
+++ b/include/drm/drm_panel.h
@@ -337,19 +337,11 @@ int drm_panel_get_modes(struct drm_panel *panel, struct drm_connector *connector
#if defined(CONFIG_OF) && defined(CONFIG_DRM_PANEL)
struct drm_panel *of_drm_find_panel(const struct device_node *np);
-int of_drm_get_panel_orientation(const struct device_node *np,
- enum drm_panel_orientation *orientation);
#else
static inline struct drm_panel *of_drm_find_panel(const struct device_node *np)
{
return ERR_PTR(-ENODEV);
}
-
-static inline int of_drm_get_panel_orientation(const struct device_node *np,
- enum drm_panel_orientation *orientation)
-{
- return -ENODEV;
-}
#endif
#if defined(CONFIG_DRM_PANEL)
diff --git a/include/dt-bindings/clock/qcom,shikra-gcc.h b/include/dt-bindings/clock/qcom,shikra-gcc.h
new file mode 100644
index 000000000000..656c959c7e12
--- /dev/null
+++ b/include/dt-bindings/clock/qcom,shikra-gcc.h
@@ -0,0 +1,263 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef _DT_BINDINGS_CLK_QCOM_GCC_SHIKRA_H
+#define _DT_BINDINGS_CLK_QCOM_GCC_SHIKRA_H
+
+/* GCC clocks */
+#define GPLL0 0
+#define GPLL0_OUT_AUX2 1
+#define GPLL1 2
+#define GPLL10 3
+#define GPLL11 4
+#define GPLL12 5
+#define GPLL12_OUT_AUX2 6
+#define GPLL3 7
+#define GPLL3_OUT_MAIN 8
+#define GPLL4 9
+#define GPLL5 10
+#define GPLL6 11
+#define GPLL6_OUT_MAIN 12
+#define GPLL7 13
+#define GPLL8 14
+#define GPLL8_OUT_MAIN 15
+#define GPLL9 16
+#define GPLL9_OUT_MAIN 17
+#define GCC_AHB2PHY_CSI_CLK 18
+#define GCC_AHB2PHY_USB_CLK 19
+#define GCC_BOOT_ROM_AHB_CLK 20
+#define GCC_CAM_THROTTLE_NRT_CLK 21
+#define GCC_CAM_THROTTLE_RT_CLK 22
+#define GCC_CAMERA_AHB_CLK 23
+#define GCC_CAMERA_XO_CLK 24
+#define GCC_CAMSS_AXI_CLK 25
+#define GCC_CAMSS_AXI_CLK_SRC 26
+#define GCC_CAMSS_CAMNOC_ATB_CLK 27
+#define GCC_CAMSS_CAMNOC_DRAGONLINK_ATB_CLK 28
+#define GCC_CAMSS_CAMNOC_NTS_XO_CLK 29
+#define GCC_CAMSS_CCI_0_CLK 30
+#define GCC_CAMSS_CCI_CLK_SRC 31
+#define GCC_CAMSS_CPHY_0_CLK 32
+#define GCC_CAMSS_CPHY_1_CLK 33
+#define GCC_CAMSS_CSI0PHYTIMER_CLK 34
+#define GCC_CAMSS_CSI0PHYTIMER_CLK_SRC 35
+#define GCC_CAMSS_CSI1PHYTIMER_CLK 36
+#define GCC_CAMSS_CSI1PHYTIMER_CLK_SRC 37
+#define GCC_CAMSS_MCLK0_CLK 38
+#define GCC_CAMSS_MCLK0_CLK_SRC 39
+#define GCC_CAMSS_MCLK1_CLK 40
+#define GCC_CAMSS_MCLK1_CLK_SRC 41
+#define GCC_CAMSS_MCLK2_CLK 42
+#define GCC_CAMSS_MCLK2_CLK_SRC 43
+#define GCC_CAMSS_MCLK3_CLK 44
+#define GCC_CAMSS_MCLK3_CLK_SRC 45
+#define GCC_CAMSS_NRT_AXI_CLK 46
+#define GCC_CAMSS_OPE_AHB_CLK 47
+#define GCC_CAMSS_OPE_AHB_CLK_SRC 48
+#define GCC_CAMSS_OPE_CLK 49
+#define GCC_CAMSS_OPE_CLK_SRC 50
+#define GCC_CAMSS_RT_AXI_CLK 51
+#define GCC_CAMSS_TFE_0_CLK 52
+#define GCC_CAMSS_TFE_0_CLK_SRC 53
+#define GCC_CAMSS_TFE_0_CPHY_RX_CLK 54
+#define GCC_CAMSS_TFE_0_CSID_CLK 55
+#define GCC_CAMSS_TFE_0_CSID_CLK_SRC 56
+#define GCC_CAMSS_TFE_1_CLK 57
+#define GCC_CAMSS_TFE_1_CLK_SRC 58
+#define GCC_CAMSS_TFE_1_CPHY_RX_CLK 59
+#define GCC_CAMSS_TFE_1_CSID_CLK 60
+#define GCC_CAMSS_TFE_1_CSID_CLK_SRC 61
+#define GCC_CAMSS_TFE_CPHY_RX_CLK_SRC 62
+#define GCC_CAMSS_TOP_AHB_CLK 63
+#define GCC_CAMSS_TOP_AHB_CLK_SRC 64
+#define GCC_CFG_NOC_USB2_PRIM_AXI_CLK 65
+#define GCC_CFG_NOC_USB3_PRIM_AXI_CLK 66
+#define GCC_DDRSS_GPU_AXI_CLK 67
+#define GCC_DDRSS_MEMNOC_PCIE_SF_CLK 68
+#define GCC_DISP_AHB_CLK 69
+#define GCC_DISP_GPLL0_CLK_SRC 70
+#define GCC_DISP_GPLL0_DIV_CLK_SRC 71
+#define GCC_DISP_HF_AXI_CLK 72
+#define GCC_DISP_THROTTLE_CORE_CLK 73
+#define GCC_DISP_XO_CLK 74
+#define GCC_EMAC0_AHB_CLK 75
+#define GCC_EMAC0_AXI_CLK 76
+#define GCC_EMAC0_AXI_CLK_SRC 77
+#define GCC_EMAC0_AXI_SYS_NOC_CLK 78
+#define GCC_EMAC0_CC_SGMIIPHY_RX_CLK 79
+#define GCC_EMAC0_CC_SGMIIPHY_RX_CLK_SRC 80
+#define GCC_EMAC0_CC_SGMIIPHY_TX_CLK 81
+#define GCC_EMAC0_CC_SGMIIPHY_TX_CLK_SRC 82
+#define GCC_EMAC0_PHY_AUX_CLK 83
+#define GCC_EMAC0_PHY_AUX_CLK_SRC 84
+#define GCC_EMAC0_PTP_CLK 85
+#define GCC_EMAC0_PTP_CLK_SRC 86
+#define GCC_EMAC0_RGMII_CLK 87
+#define GCC_EMAC0_RGMII_CLK_SRC 88
+#define GCC_EMAC1_AHB_CLK 89
+#define GCC_EMAC1_AXI_CLK 90
+#define GCC_EMAC1_AXI_CLK_SRC 91
+#define GCC_EMAC1_AXI_SYS_NOC_CLK 92
+#define GCC_EMAC1_CC_SGMIIPHY_RX_CLK 93
+#define GCC_EMAC1_CC_SGMIIPHY_RX_CLK_SRC 94
+#define GCC_EMAC1_CC_SGMIIPHY_TX_CLK 95
+#define GCC_EMAC1_CC_SGMIIPHY_TX_CLK_SRC 96
+#define GCC_EMAC1_PHY_AUX_CLK 97
+#define GCC_EMAC1_PHY_AUX_CLK_SRC 98
+#define GCC_EMAC1_PTP_CLK 99
+#define GCC_EMAC1_PTP_CLK_SRC 100
+#define GCC_EMAC1_RGMII_CLK 101
+#define GCC_EMAC1_RGMII_CLK_SRC 102
+#define GCC_GP1_CLK 103
+#define GCC_GP1_CLK_SRC 104
+#define GCC_GP2_CLK 105
+#define GCC_GP2_CLK_SRC 106
+#define GCC_GP3_CLK 107
+#define GCC_GP3_CLK_SRC 108
+#define GCC_GPU_CFG_AHB_CLK 109
+#define GCC_GPU_GPLL0_CLK_SRC 110
+#define GCC_GPU_GPLL0_DIV_CLK_SRC 111
+#define GCC_GPU_IREF_CLK 112
+#define GCC_GPU_MEMNOC_GFX_CLK 113
+#define GCC_GPU_SMMU_VOTE_CLK 114
+#define GCC_GPU_SNOC_DVM_GFX_CLK 115
+#define GCC_GPU_THROTTLE_CORE_CLK 116
+#define GCC_LPASS_CONFIG_CLK 117
+#define GCC_LPASS_CORE_AXIM_CLK 118
+#define GCC_MMU_TCU_VOTE_CLK 119
+#define GCC_PCIE_AUX_CLK 120
+#define GCC_PCIE_AUX_CLK_SRC 121
+#define GCC_PCIE_AUX_PHY_CLK_SRC 122
+#define GCC_PCIE_CFG_AHB_CLK 123
+#define GCC_PCIE_CLKREF_EN 124
+#define GCC_PCIE_MSTR_AXI_CLK 125
+#define GCC_PCIE_PIPE_CLK 126
+#define GCC_PCIE_PIPE_CLK_SRC 127
+#define GCC_PCIE_RCHNG_PHY_CLK 128
+#define GCC_PCIE_RCHNG_PHY_CLK_SRC 129
+#define GCC_PCIE_SLEEP_CLK 130
+#define GCC_PCIE_SLV_AXI_CLK 131
+#define GCC_PCIE_SLV_Q2A_AXI_CLK 132
+#define GCC_PCIE_TBU_CLK 133
+#define GCC_PCIE_THROTTLE_CORE_CLK 134
+#define GCC_PCIE_THROTTLE_XO_CLK 135
+#define GCC_PCIE_TILE_AXI_SYS_NOC_CLK 136
+#define GCC_PDM2_CLK 137
+#define GCC_PDM2_CLK_SRC 138
+#define GCC_PDM_AHB_CLK 139
+#define GCC_PDM_XO4_CLK 140
+#define GCC_PWM0_XO512_CLK 141
+#define GCC_QMIP_CAMERA_NRT_AHB_CLK 142
+#define GCC_QMIP_CAMERA_RT_AHB_CLK 143
+#define GCC_QMIP_DISP_AHB_CLK 144
+#define GCC_QMIP_GPU_CFG_AHB_CLK 145
+#define GCC_QMIP_PCIE_CFG_AHB_CLK 146
+#define GCC_QMIP_VIDEO_VCODEC_AHB_CLK 147
+#define GCC_QUPV3_WRAP0_CORE_2X_CLK 148
+#define GCC_QUPV3_WRAP0_CORE_CLK 149
+#define GCC_QUPV3_WRAP0_S0_CLK 150
+#define GCC_QUPV3_WRAP0_S0_CLK_SRC 151
+#define GCC_QUPV3_WRAP0_S1_CLK 152
+#define GCC_QUPV3_WRAP0_S1_CLK_SRC 153
+#define GCC_QUPV3_WRAP0_S2_CLK 154
+#define GCC_QUPV3_WRAP0_S2_CLK_SRC 155
+#define GCC_QUPV3_WRAP0_S3_CLK 156
+#define GCC_QUPV3_WRAP0_S3_CLK_SRC 157
+#define GCC_QUPV3_WRAP0_S4_CLK 158
+#define GCC_QUPV3_WRAP0_S4_CLK_SRC 159
+#define GCC_QUPV3_WRAP0_S5_CLK 160
+#define GCC_QUPV3_WRAP0_S5_CLK_SRC 161
+#define GCC_QUPV3_WRAP0_S6_CLK 162
+#define GCC_QUPV3_WRAP0_S6_CLK_SRC 163
+#define GCC_QUPV3_WRAP0_S7_CLK 164
+#define GCC_QUPV3_WRAP0_S7_CLK_SRC 165
+#define GCC_QUPV3_WRAP0_S8_CLK 166
+#define GCC_QUPV3_WRAP0_S8_CLK_SRC 167
+#define GCC_QUPV3_WRAP0_S9_CLK 168
+#define GCC_QUPV3_WRAP0_S9_CLK_SRC 169
+#define GCC_QUPV3_WRAP_0_M_AHB_CLK 170
+#define GCC_QUPV3_WRAP_0_S_AHB_CLK 171
+#define GCC_SDCC1_AHB_CLK 172
+#define GCC_SDCC1_APPS_CLK 173
+#define GCC_SDCC1_APPS_CLK_SRC 174
+#define GCC_SDCC1_ICE_CORE_CLK 175
+#define GCC_SDCC1_ICE_CORE_CLK_SRC 176
+#define GCC_SDCC2_AHB_CLK 177
+#define GCC_SDCC2_APPS_CLK 178
+#define GCC_SDCC2_APPS_CLK_SRC 179
+#define GCC_SYS_NOC_CPUSS_AHB_CLK 180
+#define GCC_SYS_NOC_USB2_PRIM_AXI_CLK 181
+#define GCC_SYS_NOC_USB3_PRIM_AXI_CLK 182
+#define GCC_TSCSS_AHB_CLK 183
+#define GCC_TSCSS_CLK_SRC 184
+#define GCC_TSCSS_CNTR_CLK 185
+#define GCC_TSCSS_ETU_CLK 186
+#define GCC_UFS_CLKREF_EN 187
+#define GCC_USB20_MASTER_CLK 188
+#define GCC_USB20_MASTER_CLK_SRC 189
+#define GCC_USB20_MOCK_UTMI_CLK 190
+#define GCC_USB20_MOCK_UTMI_CLK_SRC 191
+#define GCC_USB20_MOCK_UTMI_POSTDIV_CLK_SRC 192
+#define GCC_USB20_SLEEP_CLK 193
+#define GCC_USB30_PRIM_MASTER_CLK 194
+#define GCC_USB30_PRIM_MASTER_CLK_SRC 195
+#define GCC_USB30_PRIM_MOCK_UTMI_CLK 196
+#define GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC 197
+#define GCC_USB30_PRIM_MOCK_UTMI_POSTDIV_CLK_SRC 198
+#define GCC_USB30_PRIM_SLEEP_CLK 199
+#define GCC_USB3_PRIM_CLKREF_EN 200
+#define GCC_USB3_PRIM_PHY_AUX_CLK_SRC 201
+#define GCC_USB3_PRIM_PHY_COM_AUX_CLK 202
+#define GCC_USB3_PRIM_PHY_PIPE_CLK 203
+#define GCC_USB3_PRIM_PHY_PIPE_CLK_SRC 204
+#define GCC_VCODEC0_AXI_CLK 205
+#define GCC_VENUS_AHB_CLK 206
+#define GCC_VENUS_CTL_AXI_CLK 207
+#define GCC_VIDEO_AHB_CLK 208
+#define GCC_VIDEO_AXI0_CLK 209
+#define GCC_VIDEO_THROTTLE_CORE_CLK 210
+#define GCC_VIDEO_VCODEC0_SYS_CLK 211
+#define GCC_VIDEO_VENUS_CLK_SRC 212
+#define GCC_VIDEO_VENUS_CTL_CLK 213
+#define GCC_VIDEO_XO_CLK 214
+
+/* GCC power domains */
+#define GCC_CAMSS_TOP_GDSC 0
+#define GCC_EMAC0_GDSC 1
+#define GCC_EMAC1_GDSC 2
+#define GCC_PCIE_GDSC 3
+#define GCC_USB20_GDSC 4
+#define GCC_USB30_PRIM_GDSC 5
+#define GCC_VCODEC0_GDSC 6
+#define GCC_VENUS_GDSC 7
+
+/* GCC resets */
+#define GCC_CAMSS_OPE_BCR 0
+#define GCC_CAMSS_TFE_BCR 1
+#define GCC_CAMSS_TOP_BCR 2
+#define GCC_EMAC0_BCR 3
+#define GCC_EMAC1_BCR 4
+#define GCC_GPU_BCR 5
+#define GCC_MMSS_BCR 6
+#define GCC_PCIE_BCR 7
+#define GCC_PCIE_PHY_BCR 8
+#define GCC_PDM_BCR 9
+#define GCC_QUPV3_WRAPPER_0_BCR 10
+#define GCC_QUSB2PHY_PRIM_BCR 11
+#define GCC_QUSB2PHY_SEC_BCR 12
+#define GCC_SDCC1_BCR 13
+#define GCC_SDCC2_BCR 14
+#define GCC_TSCSS_BCR 15
+#define GCC_USB20_BCR 16
+#define GCC_USB30_PRIM_BCR 17
+#define GCC_USB3PHY_PHY_PRIM_SP0_BCR 18
+#define GCC_USB3_DP_PHY_PRIM_BCR 19
+#define GCC_USB3_PHY_PRIM_SP0_BCR 20
+#define GCC_USB_PHY_CFG_AHB2PHY_BCR 21
+#define GCC_VCODEC0_BCR 22
+#define GCC_VENUS_BCR 23
+#define GCC_VIDEO_INTERFACE_BCR 24
+
+#endif
diff --git a/include/dt-bindings/iio/adc/mediatek,mt6323-auxadc.h b/include/dt-bindings/iio/adc/mediatek,mt6323-auxadc.h
new file mode 100644
index 000000000000..6ee9a9ecffc1
--- /dev/null
+++ b/include/dt-bindings/iio/adc/mediatek,mt6323-auxadc.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+
+#ifndef _DT_BINDINGS_MEDIATEK_MT6323_AUXADC_H
+#define _DT_BINDINGS_MEDIATEK_MT6323_AUXADC_H
+
+#define MT6323_AUXADC_BATON2 0
+#define MT6323_AUXADC_CH6 1
+#define MT6323_AUXADC_BAT_TEMP 2
+#define MT6323_AUXADC_CHIP_TEMP 3
+#define MT6323_AUXADC_VCDT 4
+#define MT6323_AUXADC_BATON1 5
+#define MT6323_AUXADC_ISENSE 6
+#define MT6323_AUXADC_BATSNS 7
+#define MT6323_AUXADC_ACCDET 8
+#define MT6323_AUXADC_AUDIO0 9
+#define MT6323_AUXADC_AUDIO1 10
+#define MT6323_AUXADC_AUDIO2 11
+#define MT6323_AUXADC_AUDIO3 12
+#define MT6323_AUXADC_AUDIO4 13
+#define MT6323_AUXADC_AUDIO5 14
+#define MT6323_AUXADC_AUDIO6 15
+#define MT6323_AUXADC_AUDIO7 16
+
+#endif
diff --git a/include/dt-bindings/power/fsl,imx93-power.h b/include/dt-bindings/power/fsl,imx93-power.h
index 17f9f015bf7d..071221fe5c57 100644
--- a/include/dt-bindings/power/fsl,imx93-power.h
+++ b/include/dt-bindings/power/fsl,imx93-power.h
@@ -11,5 +11,6 @@
#define IMX93_MEDIABLK_PD_PXP 2
#define IMX93_MEDIABLK_PD_LCDIF 3
#define IMX93_MEDIABLK_PD_ISI 4
+#define IMX93_MEDIABLK_PD_MIPI_PHY 5
#endif
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 60ab50cb8930..899dc00b4b01 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -94,6 +94,12 @@ static inline void acpi_preset_companion(struct device *dev,
ACPI_COMPANION_SET(dev, acpi_find_child_device(parent, addr, false));
}
+static inline void acpi_device_clear_deps(struct device *dev)
+{
+ if (has_acpi_companion(dev))
+ acpi_dev_clear_dependencies(ACPI_COMPANION(dev));
+}
+
static inline const char *acpi_dev_name(struct acpi_device *adev)
{
return dev_name(&adev->dev);
@@ -360,9 +366,10 @@ int acpi_gsi_to_irq (u32 gsi, unsigned int *irq);
int acpi_isa_irq_to_gsi (unsigned isa_irq, u32 *gsi);
typedef struct fwnode_handle *(*acpi_gsi_domain_disp_fn)(u32);
+typedef acpi_handle (*acpi_gsi_handle_disp_fn)(u32);
void acpi_set_irq_model(enum acpi_irq_model_id model,
- acpi_gsi_domain_disp_fn fn);
+ acpi_gsi_domain_disp_fn fn, acpi_gsi_handle_disp_fn gsi_dep_fn);
acpi_gsi_domain_disp_fn acpi_get_gsi_dispatcher(void);
void acpi_set_gsi_to_irq_fallback(u32 (*)(u32));
@@ -372,6 +379,8 @@ struct irq_domain *acpi_irq_create_hierarchy(unsigned int flags,
const struct irq_domain_ops *ops,
void *host_data);
+u32 acpi_irq_add_auto_dep(acpi_handle handle);
+
#ifdef CONFIG_X86_IO_APIC
extern int acpi_get_override_irq(u32 gsi, int *trigger, int *polarity);
#else
@@ -908,6 +917,8 @@ static inline void acpi_preset_companion(struct device *dev,
{
}
+static inline void acpi_device_clear_deps(struct device *dev) {}
+
static inline const char *acpi_dev_name(struct acpi_device *adev)
{
return NULL;
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
index 17bb3374f4ca..931eaa7bbf6a 100644
--- a/include/linux/acpi_iort.h
+++ b/include/linux/acpi_iort.h
@@ -27,7 +27,8 @@ int iort_register_domain_token(int trans_id, phys_addr_t base,
struct fwnode_handle *fw_node);
void iort_deregister_domain_token(int trans_id);
struct fwnode_handle *iort_find_domain_token(int trans_id);
-struct fwnode_handle *iort_iwb_handle(u32 iwb_id);
+acpi_handle iort_iwb_handle(u32 iwb_id);
+struct fwnode_handle *iort_iwb_handle_fwnode(u32 iwb_id);
#ifdef CONFIG_ACPI_IORT
u32 iort_msi_map_id(struct device *dev, u32 id);
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index adf53f7edf28..31181e0c2b80 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -299,7 +299,6 @@ struct bpf_map_owner {
struct bpf_map {
u8 sha[SHA256_DIGEST_SIZE];
- u32 excl;
const struct bpf_map_ops *ops;
struct bpf_map *inner_map_meta;
#ifdef CONFIG_SECURITY
@@ -1865,8 +1864,9 @@ struct bpf_prog_aux {
struct bpf_prog {
u16 pages; /* Number of allocated pages */
- u16 jited:1, /* Is our filter JIT'ed? */
+ u32 jited:1, /* Is our filter JIT'ed? */
jit_requested:1,/* archs need to JIT the prog */
+ jit_required:1, /* program strictly requires JIT compiler */
gpl_compatible:1, /* Is filter GPL compatible? */
cb_access:1, /* Is control block accessed? */
dst_needed:1, /* Do we need dst entry? */
@@ -3170,7 +3170,6 @@ const struct bpf_func_proto *bpf_base_func_proto(enum bpf_func_id func_id,
const struct bpf_prog *prog);
void bpf_task_storage_free(struct task_struct *task);
void bpf_cgrp_storage_free(struct cgroup *cgroup);
-bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog);
const struct btf_func_model *
bpf_jit_find_kfunc_model(const struct bpf_prog *prog,
const struct bpf_insn *insn);
@@ -3509,11 +3508,6 @@ static inline void bpf_task_storage_free(struct task_struct *task)
{
}
-static inline bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog)
-{
- return false;
-}
-
static inline const struct btf_func_model *
bpf_jit_find_kfunc_model(const struct bpf_prog *prog,
const struct bpf_insn *insn)
diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index 76b8b7627a10..317e99b9acc0 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -898,6 +898,14 @@ struct bpf_scc_info {
struct bpf_liveness;
+struct bpf_fd_array {
+ union {
+ struct bpf_map *map;
+ struct btf *btf;
+ unsigned long val;
+ };
+};
+
/* single container for all structs
* one verifier_env per bpf_check() call
*/
@@ -939,6 +947,7 @@ struct bpf_verifier_env {
bool bypass_spec_v4;
bool seen_direct_write;
bool seen_exception;
+ bool signature;
struct bpf_insn_aux_data *insn_aux_data; /* array of per-insn state */
const struct bpf_line_info *prev_linfo;
struct bpf_verifier_log log;
@@ -989,7 +998,19 @@ struct bpf_verifier_env {
u32 free_list_size;
u32 explored_states_size;
u32 num_backedges;
- bpfptr_t fd_array;
+ /*
+ * The program's fd_array comes in two shapes, told apart by whether
+ * the caller passed fd_array_cnt. They are mutually exclusive:
+ * - continuous (fd_array_cnt given): ->fd_array holds every entry
+ * resolved to its object up front, indexed by fd_array position,
+ * with ->fd_array_cnt slots; ->fd_array_raw is unused.
+ * - sparse (no fd_array_cnt): ->fd_array is NULL, and entries are
+ * read from ->fd_array_raw (the caller's fd_array) and resolved
+ * on the spot at each reference.
+ */
+ struct bpf_fd_array *fd_array;
+ u32 fd_array_cnt;
+ bpfptr_t fd_array_raw;
/* bit mask to keep track of whether a register has been accessed
* since the last time the function state was printed
diff --git a/include/linux/damon.h b/include/linux/damon.h
index 2661231c0ae8..19b7e839bde0 100644
--- a/include/linux/damon.h
+++ b/include/linux/damon.h
@@ -1070,7 +1070,7 @@ static inline unsigned int damon_max_nr_accesses(const struct damon_attrs *attrs
bool damon_initialized(void);
int damon_start(struct damon_ctx **ctxs, int nr_ctxs, bool exclusive);
-int damon_stop(struct damon_ctx **ctxs, int nr_ctxs);
+void damon_stop(struct damon_ctx **ctxs, int nr_ctxs);
bool damon_is_running(struct damon_ctx *ctx);
int damon_kdamond_pid(struct damon_ctx *ctx);
diff --git a/include/linux/efi.h b/include/linux/efi.h
index ccbc35479684..015505423277 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -1212,8 +1212,8 @@ efi_call_acpi_prm_handler(efi_status_t (__efiapi *handler_addr)(u64, void *),
/*
* efi_runtime_service() function identifiers.
- * "NONE" is used by efi_recover_from_page_fault() to check if the page
- * fault happened while executing an efi runtime service.
+ * "NONE" is used by efi_crash_gracefully_on_page_fault() to check if the
+ * page fault happened while executing an efi runtime service.
*/
enum efi_rts_ids {
EFI_NONE,
@@ -1256,6 +1256,8 @@ extern struct efi_runtime_work efi_rts_work;
/* Workqueue to queue EFI Runtime Services */
extern struct workqueue_struct *efi_rts_wq;
+void efi_rts_park_worker(void);
+
struct linux_efi_memreserve {
int size; // allocated size of the array
atomic_t count; // number of entries used
diff --git a/include/linux/firmware/qcom/qcom_pas.h b/include/linux/firmware/qcom/qcom_pas.h
new file mode 100644
index 000000000000..65b1c9564458
--- /dev/null
+++ b/include/linux/firmware/qcom/qcom_pas.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2010-2015, 2018-2019 The Linux Foundation. All rights reserved.
+ * Copyright (C) 2015 Linaro Ltd.
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef __QCOM_PAS_H
+#define __QCOM_PAS_H
+
+#include <linux/err.h>
+#include <linux/types.h>
+
+struct qcom_pas_context {
+ struct device *dev;
+ u32 pas_id;
+ phys_addr_t mem_phys;
+ size_t mem_size;
+ void *ptr;
+ dma_addr_t phys;
+ ssize_t size;
+ bool use_tzmem;
+};
+
+bool qcom_pas_is_available(void);
+struct qcom_pas_context *devm_qcom_pas_context_alloc(struct device *dev,
+ u32 pas_id,
+ phys_addr_t mem_phys,
+ size_t mem_size);
+int qcom_pas_init_image(u32 pas_id, const void *metadata, size_t size,
+ struct qcom_pas_context *ctx);
+struct resource_table *qcom_pas_get_rsc_table(struct qcom_pas_context *ctx,
+ void *input_rt, size_t input_rt_size,
+ size_t *output_rt_size);
+int qcom_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size);
+int qcom_pas_auth_and_reset(u32 pas_id);
+int qcom_pas_prepare_and_auth_reset(struct qcom_pas_context *ctx);
+int qcom_pas_set_remote_state(u32 state, u32 pas_id);
+int qcom_pas_shutdown(u32 pas_id);
+bool qcom_pas_supported(u32 pas_id);
+void qcom_pas_metadata_release(struct qcom_pas_context *ctx);
+
+#endif /* __QCOM_PAS_H */
diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h
index b34e8e5e5f9a..19a7bfce279e 100644
--- a/include/linux/huge_mm.h
+++ b/include/linux/huge_mm.h
@@ -529,6 +529,8 @@ static inline bool folio_test_pmd_mappable(struct folio *folio)
vm_fault_t do_huge_pmd_numa_page(struct vm_fault *vmf);
+vm_fault_t do_huge_pmd_uffd_rwp(struct vm_fault *vmf);
+
vm_fault_t do_huge_pmd_device_private(struct vm_fault *vmf);
extern struct folio *huge_zero_folio;
@@ -723,6 +725,11 @@ static inline spinlock_t *pud_trans_huge_lock(pud_t *pud,
return NULL;
}
+static inline vm_fault_t do_huge_pmd_uffd_rwp(struct vm_fault *vmf)
+{
+ return 0;
+}
+
static inline vm_fault_t do_huge_pmd_numa_page(struct vm_fault *vmf)
{
return 0;
diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h
index dccbeb25f701..6032eea2539a 100644
--- a/include/linux/inetdevice.h
+++ b/include/linux/inetdevice.h
@@ -293,6 +293,11 @@ static inline void in_dev_put(struct in_device *idev)
#define __in_dev_put(idev) refcount_dec(&(idev)->refcnt)
#define in_dev_hold(idev) refcount_inc(&(idev)->refcnt)
+static inline bool in_dev_hold_safe(struct in_device *idev)
+{
+ return refcount_inc_not_zero(&idev->refcnt);
+}
+
#endif /* __KERNEL__ */
static __inline__ __be32 inet_make_mask(int logmask)
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index ab8cfaec82d3..0bdfa3699352 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -989,6 +989,13 @@ static inline struct kvm_io_bus *kvm_get_bus(struct kvm *kvm, enum kvm_bus idx)
lockdep_is_held(&kvm->slots_lock));
}
+static inline void kvm_lockdep_assert_vcpu_is_locked_or_unreachable(struct kvm_vcpu *vcpu)
+{
+ lockdep_assert_once(lockdep_is_held(&vcpu->mutex) ||
+ vcpu->vcpu_idx < 0 ||
+ !refcount_read(&vcpu->kvm->users_count));
+}
+
static inline struct kvm_vcpu *kvm_get_vcpu(struct kvm *kvm, int i)
{
int num_vcpus = atomic_read(&kvm->online_vcpus);
diff --git a/include/linux/leafops.h b/include/linux/leafops.h
index ef84ac1cce19..4c1476ae3234 100644
--- a/include/linux/leafops.h
+++ b/include/linux/leafops.h
@@ -100,8 +100,8 @@ static inline softleaf_t softleaf_from_pmd(pmd_t pmd)
if (pmd_swp_soft_dirty(pmd))
pmd = pmd_swp_clear_soft_dirty(pmd);
- if (pmd_swp_uffd_wp(pmd))
- pmd = pmd_swp_clear_uffd_wp(pmd);
+ if (pmd_swp_uffd(pmd))
+ pmd = pmd_swp_clear_uffd(pmd);
arch_entry = __pmd_to_swp_entry(pmd);
/* Temporary until swp_entry_t eliminated. */
diff --git a/include/linux/mdio.h b/include/linux/mdio.h
index f4f9d9609448..300805e66592 100644
--- a/include/linux/mdio.h
+++ b/include/linux/mdio.h
@@ -8,7 +8,6 @@
#include <uapi/linux/mdio.h>
#include <linux/bitfield.h>
-#include <linux/mod_devicetable.h>
struct gpio_desc;
struct mii_bus;
diff --git a/include/linux/mfd/db8500-prcmu.h b/include/linux/mfd/db8500-prcmu.h
index a62de3d155ed..c939c9a1170a 100644
--- a/include/linux/mfd/db8500-prcmu.h
+++ b/include/linux/mfd/db8500-prcmu.h
@@ -12,6 +12,9 @@
#include <linux/interrupt.h>
#include <linux/bitops.h>
+#include <linux/err.h>
+
+#include <dt-bindings/mfd/dbx500-prcmu.h> /* For clock identifiers */
/*
* Registers
@@ -24,6 +27,38 @@
#define DB8500_PRCM_DSI_SW_RESET_DSI1_SW_RESETN BIT(1)
#define DB8500_PRCM_DSI_SW_RESET_DSI2_SW_RESETN BIT(2)
+/* Offset for the firmware version within the TCPM */
+#define DB8500_PRCMU_FW_VERSION_OFFSET 0xA4
+
+#define DB8500_PRCMU_LEGACY_OFFSET 0xDD4
+
+/*
+ * CLKOUT sources
+ */
+#define PRCMU_CLKSRC_CLK38M 0x00
+#define PRCMU_CLKSRC_ACLK 0x01
+#define PRCMU_CLKSRC_SYSCLK 0x02
+#define PRCMU_CLKSRC_LCDCLK 0x03
+#define PRCMU_CLKSRC_SDMMCCLK 0x04
+#define PRCMU_CLKSRC_TVCLK 0x05
+#define PRCMU_CLKSRC_TIMCLK 0x06
+#define PRCMU_CLKSRC_CLK009 0x07
+/* These are only valid for CLKOUT1: */
+#define PRCMU_CLKSRC_SIAMMDSPCLK 0x40
+#define PRCMU_CLKSRC_I2CCLK 0x41
+#define PRCMU_CLKSRC_MSP02CLK 0x42
+#define PRCMU_CLKSRC_ARMPLL_OBSCLK 0x43
+#define PRCMU_CLKSRC_HSIRXCLK 0x44
+#define PRCMU_CLKSRC_HSITXCLK 0x45
+#define PRCMU_CLKSRC_ARMCLKFIX 0x46
+#define PRCMU_CLKSRC_HDMICLK 0x47
+
+/*
+ * Definitions for controlling ESRAM0 in deep sleep.
+ */
+#define ESRAM0_DEEP_SLEEP_STATE_OFF 1
+#define ESRAM0_DEEP_SLEEP_STATE_RET 2
+
/* This portion previously known as <mach/prcmu-fw-defs_v1.h> */
/**
@@ -451,10 +486,173 @@ enum prcmu_power_status {
PRCMU_ARMPENDINGIT_ER = 0x93,
};
+/* PRCMU Wakeup defines */
+enum prcmu_wakeup_index {
+ PRCMU_WAKEUP_INDEX_RTC,
+ PRCMU_WAKEUP_INDEX_RTT0,
+ PRCMU_WAKEUP_INDEX_RTT1,
+ PRCMU_WAKEUP_INDEX_HSI0,
+ PRCMU_WAKEUP_INDEX_HSI1,
+ PRCMU_WAKEUP_INDEX_USB,
+ PRCMU_WAKEUP_INDEX_ABB,
+ PRCMU_WAKEUP_INDEX_ABB_FIFO,
+ PRCMU_WAKEUP_INDEX_ARM,
+ PRCMU_WAKEUP_INDEX_CD_IRQ,
+ NUM_PRCMU_WAKEUP_INDICES
+};
+
+#define PRCMU_WAKEUP(_name) (BIT(PRCMU_WAKEUP_INDEX_##_name))
+
+/**
+ * enum prcmu_wdog_id - PRCMU watchdog IDs
+ * @PRCMU_WDOG_ALL: use all timers
+ * @PRCMU_WDOG_CPU1: use first CPU timer only
+ * @PRCMU_WDOG_CPU2: use second CPU timer conly
+ */
+enum prcmu_wdog_id {
+ PRCMU_WDOG_ALL = 0x00,
+ PRCMU_WDOG_CPU1 = 0x01,
+ PRCMU_WDOG_CPU2 = 0x02,
+};
+
+/**
+ * enum ape_opp - APE OPP states definition
+ * @APE_OPP_INIT:
+ * @APE_NO_CHANGE: The APE operating point is unchanged
+ * @APE_100_OPP: The new APE operating point is ape100opp
+ * @APE_50_OPP: 50%
+ * @APE_50_PARTLY_25_OPP: 50%, except some clocks at 25%.
+ */
+enum ape_opp {
+ APE_OPP_INIT = 0x00,
+ APE_NO_CHANGE = 0x01,
+ APE_100_OPP = 0x02,
+ APE_50_OPP = 0x03,
+ APE_50_PARTLY_25_OPP = 0xFF,
+};
+
+/**
+ * enum arm_opp - ARM OPP states definition
+ * @ARM_OPP_INIT:
+ * @ARM_NO_CHANGE: The ARM operating point is unchanged
+ * @ARM_100_OPP: The new ARM operating point is arm100opp
+ * @ARM_50_OPP: The new ARM operating point is arm50opp
+ * @ARM_MAX_OPP: Operating point is "max" (more than 100)
+ * @ARM_MAX_FREQ100OPP: Set max opp if available, else 100
+ * @ARM_EXTCLK: The new ARM operating point is armExtClk
+ */
+enum arm_opp {
+ ARM_OPP_INIT = 0x00,
+ ARM_NO_CHANGE = 0x01,
+ ARM_100_OPP = 0x02,
+ ARM_50_OPP = 0x03,
+ ARM_MAX_OPP = 0x04,
+ ARM_MAX_FREQ100OPP = 0x05,
+ ARM_EXTCLK = 0x07
+};
+
+/**
+ * enum ddr_opp - DDR OPP states definition
+ * @DDR_100_OPP: The new DDR operating point is ddr100opp
+ * @DDR_50_OPP: The new DDR operating point is ddr50opp
+ * @DDR_25_OPP: The new DDR operating point is ddr25opp
+ */
+enum ddr_opp {
+ DDR_100_OPP = 0x00,
+ DDR_50_OPP = 0x01,
+ DDR_25_OPP = 0x02,
+};
+
+/**
+ * enum ddr_pwrst - DDR power states definition
+ * @DDR_PWR_STATE_UNCHANGED: SDRAM and DDR controller state is unchanged
+ * @DDR_PWR_STATE_ON:
+ * @DDR_PWR_STATE_OFFLOWLAT:
+ * @DDR_PWR_STATE_OFFHIGHLAT:
+ */
+enum ddr_pwrst {
+ DDR_PWR_STATE_UNCHANGED = 0x00,
+ DDR_PWR_STATE_ON = 0x01,
+ DDR_PWR_STATE_OFFLOWLAT = 0x02,
+ DDR_PWR_STATE_OFFHIGHLAT = 0x03
+};
+
/*
* Definitions for autonomous power management configuration.
*/
+/* EPOD (power domain) IDs */
+
+/*
+ * DB8500 EPODs
+ * - EPOD_ID_SVAMMDSP: power domain for SVA MMDSP
+ * - EPOD_ID_SVAPIPE: power domain for SVA pipe
+ * - EPOD_ID_SIAMMDSP: power domain for SIA MMDSP
+ * - EPOD_ID_SIAPIPE: power domain for SIA pipe
+ * - EPOD_ID_SGA: power domain for SGA
+ * - EPOD_ID_B2R2_MCDE: power domain for B2R2 and MCDE
+ * - EPOD_ID_ESRAM12: power domain for ESRAM 1 and 2
+ * - EPOD_ID_ESRAM34: power domain for ESRAM 3 and 4
+ * - NUM_EPOD_ID: number of power domains
+ *
+ * TODO: These should be prefixed.
+ */
+#define EPOD_ID_SVAMMDSP 0
+#define EPOD_ID_SVAPIPE 1
+#define EPOD_ID_SIAMMDSP 2
+#define EPOD_ID_SIAPIPE 3
+#define EPOD_ID_SGA 4
+#define EPOD_ID_B2R2_MCDE 5
+#define EPOD_ID_ESRAM12 6
+#define EPOD_ID_ESRAM34 7
+#define NUM_EPOD_ID 8
+
+/*
+ * state definition for EPOD (power domain)
+ * - EPOD_STATE_NO_CHANGE: The EPOD should remain unchanged
+ * - EPOD_STATE_OFF: The EPOD is switched off
+ * - EPOD_STATE_RAMRET: The EPOD is switched off with its internal RAM in
+ * retention
+ * - EPOD_STATE_ON_CLK_OFF: The EPOD is switched on, clock is still off
+ * - EPOD_STATE_ON: Same as above, but with clock enabled
+ */
+#define EPOD_STATE_NO_CHANGE 0x00
+#define EPOD_STATE_OFF 0x01
+#define EPOD_STATE_RAMRET 0x02
+#define EPOD_STATE_ON_CLK_OFF 0x03
+#define EPOD_STATE_ON 0x04
+
+#define PRCMU_FW_PROJECT_U8500 2
+#define PRCMU_FW_PROJECT_U8400 3
+#define PRCMU_FW_PROJECT_U9500 4 /* Customer specific */
+#define PRCMU_FW_PROJECT_U8500_MBB 5
+#define PRCMU_FW_PROJECT_U8500_C1 6
+#define PRCMU_FW_PROJECT_U8500_C2 7
+#define PRCMU_FW_PROJECT_U8500_C3 8
+#define PRCMU_FW_PROJECT_U8500_C4 9
+#define PRCMU_FW_PROJECT_U9500_MBL 10
+#define PRCMU_FW_PROJECT_U8500_SSG1 11 /* Samsung specific */
+#define PRCMU_FW_PROJECT_U8500_MBL2 12 /* Customer specific */
+#define PRCMU_FW_PROJECT_U8520 13
+#define PRCMU_FW_PROJECT_U8420 14
+#define PRCMU_FW_PROJECT_U8500_SSG2 15 /* Samsung specific */
+#define PRCMU_FW_PROJECT_U8420_SYSCLK 17
+#define PRCMU_FW_PROJECT_A9420 20
+/* [32..63] 9540 and derivatives */
+#define PRCMU_FW_PROJECT_U9540 32
+/* [64..95] 8540 and derivatives */
+#define PRCMU_FW_PROJECT_L8540 64
+/* [96..126] 8580 and derivatives */
+#define PRCMU_FW_PROJECT_L8580 96
+
+#define PRCMU_FW_PROJECT_NAME_LEN 20
+
+/* PRCMU QoS APE OPP class */
+#define PRCMU_QOS_APE_OPP 1
+#define PRCMU_QOS_DDR_OPP 2
+#define PRCMU_QOS_ARM_OPP 3
+#define PRCMU_QOS_DEFAULT_VALUE -1
+
#define PRCMU_AUTO_PM_OFF 0
#define PRCMU_AUTO_PM_ON 1
@@ -469,6 +667,14 @@ enum prcmu_auto_pm_policy {
PRCMU_AUTO_PM_POLICY_DSP_CLK_OFF_HWP_CLK_OFF,
};
+struct prcmu_fw_version {
+ u32 project; /* Notice, project shifted with 8 on ux540 */
+ u8 api_version;
+ u8 func_version;
+ u8 errata;
+ char project_name[PRCMU_FW_PROJECT_NAME_LEN];
+};
+
/**
* struct prcmu_auto_pm_config - Autonomous power management configuration.
* @sia_auto_pm_enable: SIA autonomous pm enable. (PRCMU_AUTO_PM_{OFF,ON})
@@ -501,6 +707,9 @@ void prcmu_configure_auto_pm(struct prcmu_auto_pm_config *sleep,
bool prcmu_is_auto_pm_enabled(void);
int prcmu_config_clkout(u8 clkout, u8 source, u8 div);
+unsigned long prcmu_clock_rate(u8 clock);
+long prcmu_round_clock_rate(u8 clock, unsigned long rate);
+int prcmu_set_clock_rate(u8 clock, unsigned long rate);
int prcmu_set_clock_divider(u8 clock, u8 divider);
int db8500_prcmu_config_hotdog(u8 threshold);
int db8500_prcmu_config_hotmon(u8 low, u8 high);
@@ -508,6 +717,8 @@ int db8500_prcmu_start_temp_sense(u16 cycles32k);
int db8500_prcmu_stop_temp_sense(void);
int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size);
+int prcmu_abb_write_masked(u8 slave, u8 reg, u8 *value,
+ u8 *mask, u8 size);
int prcmu_ac_wake_req(void);
void prcmu_ac_sleep_req(void);
@@ -610,6 +821,21 @@ static inline int prcmu_config_clkout(u8 clkout, u8 source, u8 div)
return 0;
}
+static inline unsigned long prcmu_clock_rate(u8 clock)
+{
+ return 0;
+}
+
+static inline long prcmu_round_clock_rate(u8 clock, unsigned long rate)
+{
+ return 0;
+}
+
+static inline int prcmu_set_clock_rate(u8 clock, unsigned long rate)
+{
+ return 0;
+}
+
static inline int prcmu_set_clock_divider(u8 clock, u8 divider)
{
return 0;
@@ -637,12 +863,18 @@ static inline int db8500_prcmu_stop_temp_sense(void)
static inline int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
{
- return -ENOSYS;
+ return -EINVAL;
}
static inline int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
{
- return -ENOSYS;
+ return -EINVAL;
+}
+
+static inline int prcmu_abb_write_masked(u8 slave, u8 reg,
+ u8 *value, u8 *mask, u8 size)
+{
+ return -EINVAL;
}
static inline int prcmu_ac_wake_req(void)
@@ -745,4 +977,20 @@ static inline void db8500_prcmu_write_masked(unsigned int reg, u32 mask,
#endif /* !CONFIG_MFD_DB8500_PRCMU */
+static inline int prcmu_qos_add_requirement(int prcmu_qos_class,
+ char *name, s32 value)
+{
+ return 0;
+}
+
+static inline int prcmu_qos_update_requirement(int prcmu_qos_class,
+ char *name, s32 new_value)
+{
+ return 0;
+}
+
+static inline void prcmu_qos_remove_requirement(int prcmu_qos_class, char *name)
+{
+}
+
#endif /* __MFD_DB8500_PRCMU_H */
diff --git a/include/linux/mfd/dbx500-prcmu.h b/include/linux/mfd/dbx500-prcmu.h
deleted file mode 100644
index 828362b7860c..000000000000
--- a/include/linux/mfd/dbx500-prcmu.h
+++ /dev/null
@@ -1,575 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (C) ST Ericsson SA 2011
- *
- * STE Ux500 PRCMU API
- */
-#ifndef __MACH_PRCMU_H
-#define __MACH_PRCMU_H
-
-#include <linux/interrupt.h>
-#include <linux/notifier.h>
-#include <linux/err.h>
-
-#include <dt-bindings/mfd/dbx500-prcmu.h> /* For clock identifiers */
-
-/* Offset for the firmware version within the TCPM */
-#define DB8500_PRCMU_FW_VERSION_OFFSET 0xA4
-#define DBX540_PRCMU_FW_VERSION_OFFSET 0xA8
-
-/* PRCMU Wakeup defines */
-enum prcmu_wakeup_index {
- PRCMU_WAKEUP_INDEX_RTC,
- PRCMU_WAKEUP_INDEX_RTT0,
- PRCMU_WAKEUP_INDEX_RTT1,
- PRCMU_WAKEUP_INDEX_HSI0,
- PRCMU_WAKEUP_INDEX_HSI1,
- PRCMU_WAKEUP_INDEX_USB,
- PRCMU_WAKEUP_INDEX_ABB,
- PRCMU_WAKEUP_INDEX_ABB_FIFO,
- PRCMU_WAKEUP_INDEX_ARM,
- PRCMU_WAKEUP_INDEX_CD_IRQ,
- NUM_PRCMU_WAKEUP_INDICES
-};
-#define PRCMU_WAKEUP(_name) (BIT(PRCMU_WAKEUP_INDEX_##_name))
-
-/* EPOD (power domain) IDs */
-
-/*
- * DB8500 EPODs
- * - EPOD_ID_SVAMMDSP: power domain for SVA MMDSP
- * - EPOD_ID_SVAPIPE: power domain for SVA pipe
- * - EPOD_ID_SIAMMDSP: power domain for SIA MMDSP
- * - EPOD_ID_SIAPIPE: power domain for SIA pipe
- * - EPOD_ID_SGA: power domain for SGA
- * - EPOD_ID_B2R2_MCDE: power domain for B2R2 and MCDE
- * - EPOD_ID_ESRAM12: power domain for ESRAM 1 and 2
- * - EPOD_ID_ESRAM34: power domain for ESRAM 3 and 4
- * - NUM_EPOD_ID: number of power domains
- *
- * TODO: These should be prefixed.
- */
-#define EPOD_ID_SVAMMDSP 0
-#define EPOD_ID_SVAPIPE 1
-#define EPOD_ID_SIAMMDSP 2
-#define EPOD_ID_SIAPIPE 3
-#define EPOD_ID_SGA 4
-#define EPOD_ID_B2R2_MCDE 5
-#define EPOD_ID_ESRAM12 6
-#define EPOD_ID_ESRAM34 7
-#define NUM_EPOD_ID 8
-
-/*
- * state definition for EPOD (power domain)
- * - EPOD_STATE_NO_CHANGE: The EPOD should remain unchanged
- * - EPOD_STATE_OFF: The EPOD is switched off
- * - EPOD_STATE_RAMRET: The EPOD is switched off with its internal RAM in
- * retention
- * - EPOD_STATE_ON_CLK_OFF: The EPOD is switched on, clock is still off
- * - EPOD_STATE_ON: Same as above, but with clock enabled
- */
-#define EPOD_STATE_NO_CHANGE 0x00
-#define EPOD_STATE_OFF 0x01
-#define EPOD_STATE_RAMRET 0x02
-#define EPOD_STATE_ON_CLK_OFF 0x03
-#define EPOD_STATE_ON 0x04
-
-/*
- * CLKOUT sources
- */
-#define PRCMU_CLKSRC_CLK38M 0x00
-#define PRCMU_CLKSRC_ACLK 0x01
-#define PRCMU_CLKSRC_SYSCLK 0x02
-#define PRCMU_CLKSRC_LCDCLK 0x03
-#define PRCMU_CLKSRC_SDMMCCLK 0x04
-#define PRCMU_CLKSRC_TVCLK 0x05
-#define PRCMU_CLKSRC_TIMCLK 0x06
-#define PRCMU_CLKSRC_CLK009 0x07
-/* These are only valid for CLKOUT1: */
-#define PRCMU_CLKSRC_SIAMMDSPCLK 0x40
-#define PRCMU_CLKSRC_I2CCLK 0x41
-#define PRCMU_CLKSRC_MSP02CLK 0x42
-#define PRCMU_CLKSRC_ARMPLL_OBSCLK 0x43
-#define PRCMU_CLKSRC_HSIRXCLK 0x44
-#define PRCMU_CLKSRC_HSITXCLK 0x45
-#define PRCMU_CLKSRC_ARMCLKFIX 0x46
-#define PRCMU_CLKSRC_HDMICLK 0x47
-
-/**
- * enum prcmu_wdog_id - PRCMU watchdog IDs
- * @PRCMU_WDOG_ALL: use all timers
- * @PRCMU_WDOG_CPU1: use first CPU timer only
- * @PRCMU_WDOG_CPU2: use second CPU timer conly
- */
-enum prcmu_wdog_id {
- PRCMU_WDOG_ALL = 0x00,
- PRCMU_WDOG_CPU1 = 0x01,
- PRCMU_WDOG_CPU2 = 0x02,
-};
-
-/**
- * enum ape_opp - APE OPP states definition
- * @APE_OPP_INIT:
- * @APE_NO_CHANGE: The APE operating point is unchanged
- * @APE_100_OPP: The new APE operating point is ape100opp
- * @APE_50_OPP: 50%
- * @APE_50_PARTLY_25_OPP: 50%, except some clocks at 25%.
- */
-enum ape_opp {
- APE_OPP_INIT = 0x00,
- APE_NO_CHANGE = 0x01,
- APE_100_OPP = 0x02,
- APE_50_OPP = 0x03,
- APE_50_PARTLY_25_OPP = 0xFF,
-};
-
-/**
- * enum arm_opp - ARM OPP states definition
- * @ARM_OPP_INIT:
- * @ARM_NO_CHANGE: The ARM operating point is unchanged
- * @ARM_100_OPP: The new ARM operating point is arm100opp
- * @ARM_50_OPP: The new ARM operating point is arm50opp
- * @ARM_MAX_OPP: Operating point is "max" (more than 100)
- * @ARM_MAX_FREQ100OPP: Set max opp if available, else 100
- * @ARM_EXTCLK: The new ARM operating point is armExtClk
- */
-enum arm_opp {
- ARM_OPP_INIT = 0x00,
- ARM_NO_CHANGE = 0x01,
- ARM_100_OPP = 0x02,
- ARM_50_OPP = 0x03,
- ARM_MAX_OPP = 0x04,
- ARM_MAX_FREQ100OPP = 0x05,
- ARM_EXTCLK = 0x07
-};
-
-/**
- * enum ddr_opp - DDR OPP states definition
- * @DDR_100_OPP: The new DDR operating point is ddr100opp
- * @DDR_50_OPP: The new DDR operating point is ddr50opp
- * @DDR_25_OPP: The new DDR operating point is ddr25opp
- */
-enum ddr_opp {
- DDR_100_OPP = 0x00,
- DDR_50_OPP = 0x01,
- DDR_25_OPP = 0x02,
-};
-
-/*
- * Definitions for controlling ESRAM0 in deep sleep.
- */
-#define ESRAM0_DEEP_SLEEP_STATE_OFF 1
-#define ESRAM0_DEEP_SLEEP_STATE_RET 2
-
-/**
- * enum ddr_pwrst - DDR power states definition
- * @DDR_PWR_STATE_UNCHANGED: SDRAM and DDR controller state is unchanged
- * @DDR_PWR_STATE_ON:
- * @DDR_PWR_STATE_OFFLOWLAT:
- * @DDR_PWR_STATE_OFFHIGHLAT:
- */
-enum ddr_pwrst {
- DDR_PWR_STATE_UNCHANGED = 0x00,
- DDR_PWR_STATE_ON = 0x01,
- DDR_PWR_STATE_OFFLOWLAT = 0x02,
- DDR_PWR_STATE_OFFHIGHLAT = 0x03
-};
-
-#define DB8500_PRCMU_LEGACY_OFFSET 0xDD4
-
-#define PRCMU_FW_PROJECT_U8500 2
-#define PRCMU_FW_PROJECT_U8400 3
-#define PRCMU_FW_PROJECT_U9500 4 /* Customer specific */
-#define PRCMU_FW_PROJECT_U8500_MBB 5
-#define PRCMU_FW_PROJECT_U8500_C1 6
-#define PRCMU_FW_PROJECT_U8500_C2 7
-#define PRCMU_FW_PROJECT_U8500_C3 8
-#define PRCMU_FW_PROJECT_U8500_C4 9
-#define PRCMU_FW_PROJECT_U9500_MBL 10
-#define PRCMU_FW_PROJECT_U8500_SSG1 11 /* Samsung specific */
-#define PRCMU_FW_PROJECT_U8500_MBL2 12 /* Customer specific */
-#define PRCMU_FW_PROJECT_U8520 13
-#define PRCMU_FW_PROJECT_U8420 14
-#define PRCMU_FW_PROJECT_U8500_SSG2 15 /* Samsung specific */
-#define PRCMU_FW_PROJECT_U8420_SYSCLK 17
-#define PRCMU_FW_PROJECT_A9420 20
-/* [32..63] 9540 and derivatives */
-#define PRCMU_FW_PROJECT_U9540 32
-/* [64..95] 8540 and derivatives */
-#define PRCMU_FW_PROJECT_L8540 64
-/* [96..126] 8580 and derivatives */
-#define PRCMU_FW_PROJECT_L8580 96
-
-#define PRCMU_FW_PROJECT_NAME_LEN 20
-struct prcmu_fw_version {
- u32 project; /* Notice, project shifted with 8 on ux540 */
- u8 api_version;
- u8 func_version;
- u8 errata;
- char project_name[PRCMU_FW_PROJECT_NAME_LEN];
-};
-
-#include <linux/mfd/db8500-prcmu.h>
-
-#if defined(CONFIG_UX500_SOC_DB8500)
-
-static inline void __init prcmu_early_init(void)
-{
- db8500_prcmu_early_init();
-}
-
-static inline int prcmu_set_power_state(u8 state, bool keep_ulp_clk,
- bool keep_ap_pll)
-{
- return db8500_prcmu_set_power_state(state, keep_ulp_clk,
- keep_ap_pll);
-}
-
-static inline u8 prcmu_get_power_state_result(void)
-{
- return db8500_prcmu_get_power_state_result();
-}
-
-static inline int prcmu_set_epod(u16 epod_id, u8 epod_state)
-{
- return db8500_prcmu_set_epod(epod_id, epod_state);
-}
-
-static inline void prcmu_enable_wakeups(u32 wakeups)
-{
- db8500_prcmu_enable_wakeups(wakeups);
-}
-
-static inline void prcmu_disable_wakeups(void)
-{
- prcmu_enable_wakeups(0);
-}
-
-static inline void prcmu_config_abb_event_readout(u32 abb_events)
-{
- db8500_prcmu_config_abb_event_readout(abb_events);
-}
-
-static inline void prcmu_get_abb_event_buffer(void __iomem **buf)
-{
- db8500_prcmu_get_abb_event_buffer(buf);
-}
-
-int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
-int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size);
-int prcmu_abb_write_masked(u8 slave, u8 reg, u8 *value, u8 *mask, u8 size);
-
-int prcmu_config_clkout(u8 clkout, u8 source, u8 div);
-
-static inline int prcmu_request_clock(u8 clock, bool enable)
-{
- return db8500_prcmu_request_clock(clock, enable);
-}
-
-unsigned long prcmu_clock_rate(u8 clock);
-long prcmu_round_clock_rate(u8 clock, unsigned long rate);
-int prcmu_set_clock_rate(u8 clock, unsigned long rate);
-
-static inline int prcmu_get_ddr_opp(void)
-{
- return db8500_prcmu_get_ddr_opp();
-}
-
-static inline int prcmu_set_arm_opp(u8 opp)
-{
- return db8500_prcmu_set_arm_opp(opp);
-}
-
-static inline int prcmu_get_arm_opp(void)
-{
- return db8500_prcmu_get_arm_opp();
-}
-
-static inline int prcmu_set_ape_opp(u8 opp)
-{
- return db8500_prcmu_set_ape_opp(opp);
-}
-
-static inline int prcmu_get_ape_opp(void)
-{
- return db8500_prcmu_get_ape_opp();
-}
-
-static inline int prcmu_request_ape_opp_100_voltage(bool enable)
-{
- return db8500_prcmu_request_ape_opp_100_voltage(enable);
-}
-
-static inline void prcmu_system_reset(u16 reset_code)
-{
- db8500_prcmu_system_reset(reset_code);
-}
-
-static inline u16 prcmu_get_reset_code(void)
-{
- return db8500_prcmu_get_reset_code();
-}
-
-int prcmu_ac_wake_req(void);
-void prcmu_ac_sleep_req(void);
-static inline void prcmu_modem_reset(void)
-{
- db8500_prcmu_modem_reset();
-}
-
-static inline bool prcmu_is_ac_wake_requested(void)
-{
- return db8500_prcmu_is_ac_wake_requested();
-}
-
-static inline int prcmu_config_esram0_deep_sleep(u8 state)
-{
- return db8500_prcmu_config_esram0_deep_sleep(state);
-}
-
-static inline int prcmu_config_hotdog(u8 threshold)
-{
- return db8500_prcmu_config_hotdog(threshold);
-}
-
-static inline int prcmu_config_hotmon(u8 low, u8 high)
-{
- return db8500_prcmu_config_hotmon(low, high);
-}
-
-static inline int prcmu_start_temp_sense(u16 cycles32k)
-{
- return db8500_prcmu_start_temp_sense(cycles32k);
-}
-
-static inline int prcmu_stop_temp_sense(void)
-{
- return db8500_prcmu_stop_temp_sense();
-}
-
-static inline u32 prcmu_read(unsigned int reg)
-{
- return db8500_prcmu_read(reg);
-}
-
-static inline void prcmu_write(unsigned int reg, u32 value)
-{
- db8500_prcmu_write(reg, value);
-}
-
-static inline void prcmu_write_masked(unsigned int reg, u32 mask, u32 value)
-{
- db8500_prcmu_write_masked(reg, mask, value);
-}
-
-static inline int prcmu_enable_a9wdog(u8 id)
-{
- return db8500_prcmu_enable_a9wdog(id);
-}
-
-static inline int prcmu_disable_a9wdog(u8 id)
-{
- return db8500_prcmu_disable_a9wdog(id);
-}
-
-static inline int prcmu_kick_a9wdog(u8 id)
-{
- return db8500_prcmu_kick_a9wdog(id);
-}
-
-static inline int prcmu_load_a9wdog(u8 id, u32 timeout)
-{
- return db8500_prcmu_load_a9wdog(id, timeout);
-}
-
-static inline int prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
-{
- return db8500_prcmu_config_a9wdog(num, sleep_auto_off);
-}
-#else
-
-static inline void prcmu_early_init(void) {}
-
-static inline int prcmu_set_power_state(u8 state, bool keep_ulp_clk,
- bool keep_ap_pll)
-{
- return 0;
-}
-
-static inline int prcmu_set_epod(u16 epod_id, u8 epod_state)
-{
- return 0;
-}
-
-static inline void prcmu_enable_wakeups(u32 wakeups) {}
-
-static inline void prcmu_disable_wakeups(void) {}
-
-static inline int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
-{
- return -ENOSYS;
-}
-
-static inline int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
-{
- return -ENOSYS;
-}
-
-static inline int prcmu_abb_write_masked(u8 slave, u8 reg, u8 *value, u8 *mask,
- u8 size)
-{
- return -ENOSYS;
-}
-
-static inline int prcmu_config_clkout(u8 clkout, u8 source, u8 div)
-{
- return 0;
-}
-
-static inline int prcmu_request_clock(u8 clock, bool enable)
-{
- return 0;
-}
-
-static inline long prcmu_round_clock_rate(u8 clock, unsigned long rate)
-{
- return 0;
-}
-
-static inline int prcmu_set_clock_rate(u8 clock, unsigned long rate)
-{
- return 0;
-}
-
-static inline unsigned long prcmu_clock_rate(u8 clock)
-{
- return 0;
-}
-
-static inline int prcmu_set_ape_opp(u8 opp)
-{
- return 0;
-}
-
-static inline int prcmu_get_ape_opp(void)
-{
- return APE_100_OPP;
-}
-
-static inline int prcmu_request_ape_opp_100_voltage(bool enable)
-{
- return 0;
-}
-
-static inline int prcmu_set_arm_opp(u8 opp)
-{
- return 0;
-}
-
-static inline int prcmu_get_arm_opp(void)
-{
- return ARM_100_OPP;
-}
-
-static inline int prcmu_get_ddr_opp(void)
-{
- return DDR_100_OPP;
-}
-
-static inline void prcmu_system_reset(u16 reset_code) {}
-
-static inline u16 prcmu_get_reset_code(void)
-{
- return 0;
-}
-
-static inline int prcmu_ac_wake_req(void)
-{
- return 0;
-}
-
-static inline void prcmu_ac_sleep_req(void) {}
-
-static inline void prcmu_modem_reset(void) {}
-
-static inline bool prcmu_is_ac_wake_requested(void)
-{
- return false;
-}
-
-static inline int prcmu_config_esram0_deep_sleep(u8 state)
-{
- return 0;
-}
-
-static inline void prcmu_config_abb_event_readout(u32 abb_events) {}
-
-static inline void prcmu_get_abb_event_buffer(void __iomem **buf)
-{
- *buf = NULL;
-}
-
-static inline int prcmu_config_hotdog(u8 threshold)
-{
- return 0;
-}
-
-static inline int prcmu_config_hotmon(u8 low, u8 high)
-{
- return 0;
-}
-
-static inline int prcmu_start_temp_sense(u16 cycles32k)
-{
- return 0;
-}
-
-static inline int prcmu_stop_temp_sense(void)
-{
- return 0;
-}
-
-static inline u32 prcmu_read(unsigned int reg)
-{
- return 0;
-}
-
-static inline void prcmu_write(unsigned int reg, u32 value) {}
-
-static inline void prcmu_write_masked(unsigned int reg, u32 mask, u32 value) {}
-
-#endif
-
-static inline void prcmu_set(unsigned int reg, u32 bits)
-{
- prcmu_write_masked(reg, bits, bits);
-}
-
-static inline void prcmu_clear(unsigned int reg, u32 bits)
-{
- prcmu_write_masked(reg, bits, 0);
-}
-
-/* PRCMU QoS APE OPP class */
-#define PRCMU_QOS_APE_OPP 1
-#define PRCMU_QOS_DDR_OPP 2
-#define PRCMU_QOS_ARM_OPP 3
-#define PRCMU_QOS_DEFAULT_VALUE -1
-
-static inline int prcmu_qos_add_requirement(int prcmu_qos_class,
- char *name, s32 value)
-{
- return 0;
-}
-
-static inline int prcmu_qos_update_requirement(int prcmu_qos_class,
- char *name, s32 new_value)
-{
- return 0;
-}
-
-static inline void prcmu_qos_remove_requirement(int prcmu_qos_class, char *name)
-{
-}
-
-#endif /* __MACH_PRCMU_H */
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 113e1752548c..25e669632d2c 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -354,6 +354,7 @@ enum {
#endif
DECLARE_VMA_BIT(UFFD_MINOR, 41),
DECLARE_VMA_BIT(SEALED, 42),
+ DECLARE_VMA_BIT(UFFD_RWP, 43),
/* Flags that reuse flags above. */
DECLARE_VMA_BIT_ALIAS(PKEY_BIT0, HIGH_ARCH_0),
DECLARE_VMA_BIT_ALIAS(PKEY_BIT1, HIGH_ARCH_1),
@@ -497,12 +498,17 @@ enum {
#else
#define VM_UFFD_MINOR VM_NONE
#endif
+#ifdef CONFIG_USERFAULTFD_RWP
+#define VM_UFFD_RWP INIT_VM_FLAG(UFFD_RWP)
+#else
+#define VM_UFFD_RWP VM_NONE
+#endif
/*
- * vma_flags_t masks for the userfaultfd VMA flags. VMA_UFFD_MINOR is gated on
- * the same config as VM_UFFD_MINOR -- which implies 64BIT, where the bit fits
- * -- so an out-of-range bit is never fed to mk_vma_flags() on a build whose
- * bitmap cannot hold it.
+ * vma_flags_t masks for the userfaultfd VMA flags. The two high-bit modes are
+ * gated on the same configs as their VM_* flags above -- both of which imply
+ * 64BIT -- so an out-of-range bit is never fed to mk_vma_flags() on a build
+ * whose bitmap cannot hold it.
*/
#define VMA_UFFD_MISSING mk_vma_flags(VMA_UFFD_MISSING_BIT)
#define VMA_UFFD_WP mk_vma_flags(VMA_UFFD_WP_BIT)
@@ -511,6 +517,11 @@ enum {
#else
#define VMA_UFFD_MINOR EMPTY_VMA_FLAGS
#endif
+#ifdef CONFIG_USERFAULTFD_RWP
+#define VMA_UFFD_RWP mk_vma_flags(VMA_UFFD_RWP_BIT)
+#else
+#define VMA_UFFD_RWP EMPTY_VMA_FLAGS
+#endif
#ifdef CONFIG_64BIT
#define VM_ALLOW_ANY_UNCACHED INIT_VM_FLAG(ALLOW_ANY_UNCACHED)
@@ -649,29 +660,32 @@ enum {
* reconsistuted upon page fault, so necessitate page table copying upon fork.
*
* Note that these flags should be compared with the DESTINATION VMA not the
- * source, as VM_UFFD_WP may not be propagated to destination, while all other
- * flags will be.
+ * source: VM_UFFD_WP and VM_UFFD_RWP may be cleared on the destination
+ * (dup_userfaultfd() -> userfaultfd_reset_ctx() when the parent context did
+ * not negotiate UFFD_FEATURE_EVENT_FORK), while all other flags propagate.
*
* VM_PFNMAP / VM_MIXEDMAP - These contain kernel-mapped data which cannot be
* reasonably reconstructed on page fault.
*
* VM_UFFD_WP - Encodes metadata about an installed uffd
- * write protect handler, which cannot be
- * reconstructed on page fault.
+ * VM_UFFD_RWP write- or read-write-protect handler, which
+ * cannot be reconstructed on page fault.
*
- * We always copy pgtables when dst_vma has uffd-wp
- * enabled even if it's file-backed
- * (e.g. shmem). Because when uffd-wp is enabled,
- * pgtable contains uffd-wp protection information,
- * that's something we can't retrieve from page cache,
- * and skip copying will lose those info.
+ * We always copy pgtables when dst_vma has the
+ * uffd PTE bit in use even if it's file-backed
+ * (e.g. shmem). Because when the uffd bit is
+ * in use, the pgtable contains the protection
+ * information, that's something we can't
+ * retrieve from page cache, and skip copying
+ * will lose those info.
*
* VM_MAYBE_GUARD - Could contain page guard region markers which
* by design are a property of the page tables
* only and thus cannot be reconstructed on page
* fault.
*/
-#define VM_COPY_ON_FORK (VM_PFNMAP | VM_MIXEDMAP | VM_UFFD_WP | VM_MAYBE_GUARD)
+#define VM_COPY_ON_FORK (VM_PFNMAP | VM_MIXEDMAP | VM_UFFD_WP | VM_UFFD_RWP | \
+ VM_MAYBE_GUARD)
/*
* mapping from the currently active vm_flags protection bits (the
@@ -2303,29 +2317,15 @@ static inline int memdesc_nid(const memdesc_flags_t *mdf)
#endif
#endif
-#ifdef CONFIG_NUMA
static inline int page_to_nid(const struct page *page)
{
- const struct page *p = PF_POISONED_CHECK(page);
-
- return memdesc_nid(&p->flags);
+ return memdesc_nid(&(PF_POISONED_CHECK(page)->flags));
}
static inline int folio_nid(const struct folio *folio)
{
return memdesc_nid(&folio->flags);
}
-#else
-static inline int page_to_nid(const struct page *page)
-{
- return 0;
-}
-
-static inline int folio_nid(const struct folio *folio)
-{
- return 0;
-}
-#endif
#ifdef CONFIG_NUMA_BALANCING
/* page access time bits needs to hold at least 4 seconds */
@@ -2566,9 +2566,7 @@ static inline void set_page_section(struct page *page, unsigned long section)
static inline unsigned long memdesc_section(const memdesc_flags_t *mdf)
{
-#if SECTIONS_WIDTH != 0
ASSERT_EXCLUSIVE_BITS(mdf->f, SECTIONS_MASK << SECTIONS_PGSHIFT);
-#endif
return (mdf->f >> SECTIONS_PGSHIFT) & SECTIONS_MASK;
}
#else /* !SECTION_IN_PAGE_FLAGS */
@@ -3343,6 +3341,11 @@ int get_cmdline(struct task_struct *task, char *buffer, int buflen);
#define MM_CP_UFFD_WP_RESOLVE (1UL << 3) /* Resolve wp */
#define MM_CP_UFFD_WP_ALL (MM_CP_UFFD_WP | \
MM_CP_UFFD_WP_RESOLVE)
+/* Whether this change is for uffd RWP */
+#define MM_CP_UFFD_RWP (1UL << 4) /* do rwp */
+#define MM_CP_UFFD_RWP_RESOLVE (1UL << 5) /* resolve rwp */
+#define MM_CP_UFFD_RWP_ALL (MM_CP_UFFD_RWP | \
+ MM_CP_UFFD_RWP_RESOLVE)
bool can_change_pte_writable(struct vm_area_struct *vma, unsigned long addr,
pte_t pte);
@@ -4651,12 +4654,26 @@ static inline int vm_fault_to_errno(vm_fault_t vm_fault, int foll_flags)
/*
* Indicates whether GUP can follow a PROT_NONE mapped page, or whether
- * a (NUMA hinting) fault is required.
+ * a (NUMA hinting or userfaultfd RWP) fault is required.
*/
static inline bool gup_can_follow_protnone(const struct vm_area_struct *vma,
unsigned int flags)
{
/*
+ * VM_UFFD_RWP uses protnone as an access-tracking marker, not for
+ * NUMA hinting. GUP must always take a fault so the access is
+ * delivered to userfaultfd, regardless of FOLL_HONOR_NUMA_FAULT.
+ *
+ * Only do so while the VMA is accessible. If it has been made
+ * inaccessible (e.g. mprotect(PROT_NONE)), fall through to the guard
+ * below: forcing a fault there would loop, as handle_mm_fault() makes
+ * no progress on protnone in an inaccessible VMA, and the access is
+ * denied regardless of RWP anyway.
+ */
+ if (vma_test_single_mask(vma, VMA_UFFD_RWP) && vma_is_accessible(vma))
+ return false;
+
+ /*
* If callers don't want to honor NUMA hinting faults, no need to
* determine if we would actually have to trigger a NUMA hinting fault.
*/
diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h
index efcddb9925ad..b5c4dc0f3fe3 100644
--- a/include/linux/mm_inline.h
+++ b/include/linux/mm_inline.h
@@ -600,14 +600,14 @@ pte_install_uffd_wp_if_needed(struct vm_area_struct *vma, unsigned long addr,
return false;
/* A uffd-wp wr-protected normal pte */
- if (unlikely(pte_present(pteval) && pte_uffd_wp(pteval)))
+ if (unlikely(pte_present(pteval) && pte_uffd(pteval)))
arm_uffd_pte = true;
/*
* A uffd-wp wr-protected swap pte. Note: this should even cover an
* existing pte marker with uffd-wp bit set.
*/
- if (unlikely(pte_swp_uffd_wp_any(pteval)))
+ if (unlikely(pte_swp_uffd_any(pteval)))
arm_uffd_pte = true;
if (unlikely(arm_uffd_pte)) {
diff --git a/include/linux/module.h b/include/linux/module.h
index 7566815fabbe..96cc98568eea 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -477,10 +477,6 @@ struct module {
struct module_notes_attrs *notes_attrs;
#endif
- /* The command line arguments (may be mangled). People like
- keeping pointers to this stuff */
- char *args;
-
#ifdef CONFIG_SMP
/* Per-cpu data. */
void __percpu *percpu;
diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
index 3df6db1e9e39..8c093c119e5a 100644
--- a/include/linux/pgtable.h
+++ b/include/linux/pgtable.h
@@ -2110,18 +2110,26 @@ static inline int pud_trans_unstable(pud_t *pud)
return 0;
}
-#ifndef CONFIG_NUMA_BALANCING
+#ifndef CONFIG_ARCH_HAS_PTE_PROTNONE
/*
- * In an inaccessible (PROT_NONE) VMA, pte_protnone() may indicate "yes". It is
- * perfectly valid to indicate "no" in that case, which is why our default
- * implementation defaults to "always no".
+ * In an inaccessible (PROT_NONE) VMA, pte_protnone() may indicate "yes". It
+ * is perfectly valid to indicate "no" in that case, which is why our
+ * default implementation defaults to "always no".
*
- * In an accessible VMA, however, pte_protnone() reliably indicates PROT_NONE
- * page protection due to NUMA hinting. NUMA hinting faults only apply in
- * accessible VMAs.
+ * In an accessible VMA, pte_protnone() reliably indicates a present
+ * PROT_NONE page protection. Today the kernel uses such PTEs for two
+ * purposes: NUMA hinting faults, and userfaultfd RWP tracking on
+ * VM_UFFD_RWP VMAs. The two are distinguished by the uffd PTE bit and
+ * the VMA flag; see include/linux/userfaultfd_k.h.
*
- * So, to reliably identify PROT_NONE PTEs that require a NUMA hinting fault,
- * looking at the VMA accessibility is sufficient.
+ * So, to reliably identify PROT_NONE PTEs that require kernel handling,
+ * looking at the VMA accessibility (and the uffd bit on RWP VMAs) is
+ * sufficient.
+ *
+ * Architectures without CONFIG_ARCH_HAS_PTE_PROTNONE get the always-zero
+ * stubs below; PAGE_NONE references that survive to runtime fire the
+ * BUILD_BUG() fallback, since callers should have folded such paths to
+ * dead code via IS_ENABLED(CONFIG_ARCH_HAS_PTE_PROTNONE).
*/
static inline int pte_protnone(pte_t pte)
{
@@ -2132,7 +2140,11 @@ static inline int pmd_protnone(pmd_t pmd)
{
return 0;
}
-#endif /* CONFIG_NUMA_BALANCING */
+
+#ifndef PAGE_NONE
+#define PAGE_NONE ({ BUILD_BUG(); (pgprot_t){0}; })
+#endif
+#endif /* CONFIG_ARCH_HAS_PTE_PROTNONE */
#endif /* CONFIG_MMU */
diff --git a/include/linux/soc/qcom/mdt_loader.h b/include/linux/soc/qcom/mdt_loader.h
index 82372e0db0a1..142409555425 100644
--- a/include/linux/soc/qcom/mdt_loader.h
+++ b/include/linux/soc/qcom/mdt_loader.h
@@ -10,7 +10,7 @@
struct device;
struct firmware;
-struct qcom_scm_pas_context;
+struct qcom_pas_context;
#if IS_ENABLED(CONFIG_QCOM_MDT_LOADER)
@@ -20,7 +20,7 @@ int qcom_mdt_load(struct device *dev, const struct firmware *fw,
phys_addr_t mem_phys, size_t mem_size,
phys_addr_t *reloc_base);
-int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx, const struct firmware *fw,
+int qcom_mdt_pas_load(struct qcom_pas_context *ctx, const struct firmware *fw,
const char *firmware, void *mem_region, phys_addr_t *reloc_base);
int qcom_mdt_load_no_init(struct device *dev, const struct firmware *fw,
@@ -45,7 +45,7 @@ static inline int qcom_mdt_load(struct device *dev, const struct firmware *fw,
return -ENODEV;
}
-static inline int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx,
+static inline int qcom_mdt_pas_load(struct qcom_pas_context *ctx,
const struct firmware *fw, const char *firmware,
void *mem_region, phys_addr_t *reloc_base)
{
diff --git a/include/linux/swap.h b/include/linux/swap.h
index 3f31b6a56788..696ed01709c2 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -287,39 +287,19 @@ static inline swp_entry_t page_swap_entry(struct page *page)
return entry;
}
-/* linux/mm/workingset.c */
-bool workingset_test_recent(void *shadow, bool file, bool *workingset,
- bool flush);
-void workingset_age_nonresident(struct lruvec *lruvec, unsigned long nr_pages);
-void *workingset_eviction(struct folio *folio, struct mem_cgroup *target_memcg);
-void workingset_refault(struct folio *folio, void *shadow);
-void workingset_activation(struct folio *folio);
-
/* linux/mm/page_alloc.c */
extern unsigned long totalreserve_pages;
/* Definition of global_zone_page_state not available yet */
#define nr_free_pages() global_zone_page_state(NR_FREE_PAGES)
+/* linux/mm/folio.c */
+void folio_add_lru(struct folio *folio);
+void folio_mark_accessed(struct folio *folio);
+void lru_add_drain_all(void);
-/* linux/mm/swap.c */
-void lru_note_cost_unlock_irq(struct lruvec *lruvec, bool file,
- unsigned int nr_io, unsigned int nr_rotated);
-void lru_note_cost_refault(struct folio *);
-void folio_add_lru(struct folio *);
-void folio_add_lru_vma(struct folio *, struct vm_area_struct *);
-void mark_page_accessed(struct page *);
-void folio_mark_accessed(struct folio *);
-
-static inline bool folio_may_be_lru_cached(struct folio *folio)
-{
- /*
- * Holding PMD-sized folios in per-CPU LRU cache unbalances accounting.
- * Holding small numbers of low-order mTHP folios in per-CPU LRU cache
- * will be sensible, but nobody has implemented and tested that yet.
- */
- return !folio_test_large(folio);
-}
+/* linux/mm/folio-compat.c */
+void mark_page_accessed(struct page *page);
extern atomic_t lru_disable_count;
@@ -328,43 +308,6 @@ static inline bool lru_cache_disabled(void)
return atomic_read(&lru_disable_count);
}
-static inline void lru_cache_enable(void)
-{
- atomic_dec(&lru_disable_count);
-}
-
-extern void lru_cache_disable(void);
-extern void lru_add_drain(void);
-extern void lru_add_drain_cpu(int cpu);
-extern void lru_add_drain_cpu_zone(struct zone *zone);
-extern void lru_add_drain_all(void);
-void folio_deactivate(struct folio *folio);
-void folio_mark_lazyfree(struct folio *folio);
-extern void swap_setup(void);
-
-/* linux/mm/vmscan.c */
-extern unsigned long zone_reclaimable_pages(struct zone *zone);
-extern unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
- gfp_t gfp_mask, const nodemask_t *mask);
-unsigned long lruvec_lru_size(struct lruvec *lruvec, enum lru_list lru, int zone_idx);
-
-#define MEMCG_RECLAIM_MAY_SWAP (1 << 1)
-#define MEMCG_RECLAIM_PROACTIVE (1 << 2)
-#define MIN_SWAPPINESS 0
-#define MAX_SWAPPINESS 200
-
-/* Just reclaim from anon folios in proactive memory reclaim */
-#define SWAPPINESS_ANON_ONLY (MAX_SWAPPINESS + 1)
-
-extern unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg,
- unsigned long nr_pages,
- gfp_t gfp_mask,
- unsigned int reclaim_options,
- int *swappiness);
-extern unsigned long mem_cgroup_shrink_node(struct mem_cgroup *mem,
- gfp_t gfp_mask, bool noswap,
- pg_data_t *pgdat,
- unsigned long *nr_scanned);
extern unsigned long shrink_all_memory(unsigned long nr_pages);
extern int vm_swappiness;
long remove_mapping(struct address_space *mapping, struct folio *folio);
@@ -385,11 +328,6 @@ static inline void reclaim_unregister_node(struct node *node)
}
#endif /* CONFIG_SYSFS && CONFIG_NUMA */
-#ifdef CONFIG_NUMA
-extern int sysctl_min_unmapped_ratio;
-extern int sysctl_min_slab_ratio;
-#endif
-
void check_move_unevictable_folios(struct folio_batch *fbatch);
extern void __meminit kswapd_run(int nid);
@@ -545,7 +483,7 @@ static inline int mem_cgroup_swappiness(struct mem_cgroup *memcg)
void lru_reparent_memcg(struct mem_cgroup *memcg, struct mem_cgroup *parent, int nid);
#else
-static inline int mem_cgroup_swappiness(struct mem_cgroup *mem)
+static inline int mem_cgroup_swappiness(struct mem_cgroup *memcg)
{
return READ_ONCE(vm_swappiness);
}
diff --git a/include/linux/swapops.h b/include/linux/swapops.h
index 1125401b787e..c956bc445ee0 100644
--- a/include/linux/swapops.h
+++ b/include/linux/swapops.h
@@ -73,8 +73,8 @@ static inline pte_t pte_swp_clear_flags(pte_t pte)
pte = pte_swp_clear_exclusive(pte);
if (pte_swp_soft_dirty(pte))
pte = pte_swp_clear_soft_dirty(pte);
- if (pte_swp_uffd_wp(pte))
- pte = pte_swp_clear_uffd_wp(pte);
+ if (pte_swp_uffd(pte))
+ pte = pte_swp_clear_uffd(pte);
return pte;
}
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 2886fbceb5d6..39cf1bf9703f 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -74,53 +74,108 @@ extern const int sysctl_vals[];
extern const unsigned long sysctl_long_vals[];
-typedef int proc_handler(const struct ctl_table *ctl, int write, void *buffer,
- size_t *lenp, loff_t *ppos);
-
-int proc_dostring(const struct ctl_table *, int, void *, size_t *, loff_t *);
-int proc_dobool(const struct ctl_table *table, int write, void *buffer,
- size_t *lenp, loff_t *ppos);
+typedef int proc_handler(const struct ctl_table *ctl, int dir, void *buf,
+ size_t *lenp, loff_t *ppos);
-int proc_dointvec(const struct ctl_table *, int, void *, size_t *, loff_t *);
-int proc_dointvec_minmax(const struct ctl_table *table, int dir, void *buffer,
+/* proc_handler functions */
+int proc_dostring(const struct ctl_table *ctl, int dir, void *buf, size_t *lenp,
+ loff_t *ppos);
+int proc_dobool(const struct ctl_table *ctl, int dir, void *buf, size_t *lenp,
+ loff_t *ppos);
+int proc_dointvec(const struct ctl_table *ctl, int dir, void *buf, size_t *lenp,
+ loff_t *ppos);
+int proc_dointvec_minmax(const struct ctl_table *ctl, int dir, void *buf,
size_t *lenp, loff_t *ppos);
-int proc_dointvec_conv(const struct ctl_table *table, int dir, void *buffer,
+int proc_douintvec(const struct ctl_table *ctl, int dir, void *buf, size_t *lenp,
+ loff_t *ppos);
+int proc_douintvec_minmax(const struct ctl_table *ctl, int dir, void *buf,
+ size_t *lenp, loff_t *ppos);
+int proc_dou8vec_minmax(const struct ctl_table *ctl, int dir, void *buf,
+ size_t *lenp, loff_t *ppos);
+int proc_doulongvec_minmax(const struct ctl_table *ctl, int dir, void *buf,
+ size_t *lenp, loff_t *ppos);
+int proc_do_large_bitmap(const struct ctl_table *ctl, int dir, void *buf,
+ size_t *lenp, loff_t *ppos);
+int proc_do_static_key(const struct ctl_table *ctl, int dir, void *buf,
+ size_t *lenp, loff_t *ppos);
+
+/*
+ * proc_handler aggregators
+ *
+ * Create a proc_handler with a custom converter. Use when the user space
+ * value is a transformation of the kernel value. Cannot be passed as
+ * proc_handlers.
+ *
+ * Example of creating your custom proc handler:
+ * int custom_converter(bool *negp, ulong *u_ptr, uint *k_ptr,
+ * int dir, const struct ctl_table *ctl) {...}
+ * int custom_proc_handler(const struct ctl_table *ctl, int dir,
+ * void *buf, size_t *lenp, loff_t *ppos
+ * { return proc_dointvec_conv(ctl, dir, buf, lenp, ppos, custom_converter); }
+ */
+int proc_dointvec_conv(const struct ctl_table *ctl, int dir, void *buf,
size_t *lenp, loff_t *ppos,
int (*conv)(bool *negp, unsigned long *u_ptr, int *k_ptr,
- int dir, const struct ctl_table *table));
-int proc_int_k2u_conv_kop(ulong *u_ptr, const int *k_ptr, bool *negp,
- ulong (*k_ptr_op)(const ulong));
-int proc_int_u2k_conv_uop(const ulong *u_ptr, int *k_ptr, const bool *negp,
- ulong (*u_ptr_op)(const ulong));
+ int dir, const struct ctl_table *ctl));
+int proc_douintvec_conv(const struct ctl_table *ctl, int dir, void *buf,
+ size_t *lenp, loff_t *ppos,
+ int (*conv)(bool *negp, ulong *u_ptr, uint *k_ptr,
+ int dir, const struct ctl_table *ctl));
+int proc_doulongvec_conv(const struct ctl_table *ctl, int dir, void *buf,
+ size_t *lenp, loff_t *ppos,
+ int (*conv)(bool *negp, ulong *u_ptr, ulong *k_ptr,
+ int dir, const struct ctl_table *ctl));
+
+/*
+ * bi-directional converter functions
+ *
+ * Specify the converter function for both directions (user to kernel & kernel
+ * to user). Use when you want to change the value of the variable before
+ * assignment. Used to create custom proc_handler aggregators.
+ *
+ * Example of creating your custom bi-directional converter:
+ * int custom_u2k(ulong *u_ptr, const uint *k_ptr) { ... }
+ * int custom_converter(bool *negp, ulong *u_ptr, uint *k_ptr,
+ * int dir, const struct ctl_table *ctl)
+ * { return proc_uint_conv(u_ptr, k_ptr, dir, ctl, true,
+ * custom_u2k, proc_uint_k2u_conv}
+ */
int proc_int_conv(bool *negp, ulong *u_ptr, int *k_ptr, int dir,
const struct ctl_table *tbl, bool k_ptr_range_check,
int (*user_to_kern)(const bool *negp, const ulong *u_ptr, int *k_ptr),
int (*kern_to_user)(bool *negp, ulong *u_ptr, const int *k_ptr));
-
-int proc_douintvec(const struct ctl_table *, int, void *, size_t *, loff_t *);
-int proc_douintvec_minmax(const struct ctl_table *table, int write, void *buffer,
- size_t *lenp, loff_t *ppos);
-int proc_douintvec_conv(const struct ctl_table *table, int write, void *buffer,
- size_t *lenp, loff_t *ppos,
- int (*conv)(unsigned long *lvalp, unsigned int *valp,
- int write, const struct ctl_table *table));
-int proc_uint_k2u_conv(ulong *u_ptr, const uint *k_ptr);
-int proc_uint_u2k_conv_uop(const ulong *u_ptr, uint *k_ptr,
- ulong (*u_ptr_op)(const ulong));
int proc_uint_conv(ulong *u_ptr, uint *k_ptr, int dir,
const struct ctl_table *tbl, bool k_ptr_range_check,
int (*user_to_kern)(const ulong *u_ptr, uint *k_ptr),
int (*kern_to_user)(ulong *u_ptr, const uint *k_ptr));
+int proc_ulong_conv(ulong *u_ptr, ulong *k_ptr, int dir,
+ const struct ctl_table *tbl, bool k_ptr_range_check,
+ int (*user_to_kern)(const ulong *u_ptr, ulong *k_ptr),
+ int (*kern_to_user)(ulong *u_ptr, const ulong *k_ptr));
-int proc_dou8vec_minmax(const struct ctl_table *table, int write, void *buffer,
- size_t *lenp, loff_t *ppos);
-int proc_doulongvec_minmax(const struct ctl_table *, int, void *, size_t *, loff_t *);
-int proc_doulongvec_minmax_conv(const struct ctl_table *table, int dir,
- void *buffer, size_t *lenp, loff_t *ppos,
- unsigned long convmul, unsigned long convdiv);
-int proc_do_large_bitmap(const struct ctl_table *, int, void *, size_t *, loff_t *);
-int proc_do_static_key(const struct ctl_table *table, int write, void *buffer,
- size_t *lenp, loff_t *ppos);
+/*
+ * uni-directional converter functions
+ *
+ * Specify the converter function for one directions (user to kernel or
+ * kernel to user). Use to call the actual value conversion. Used to Create
+ * bi-directional converters.
+ *
+ * Example of creating a uni-directional converter:
+ * ulong op(const ulong val) { ... }
+ * int custom_unidir_conv(ulong *u_ptr, const uint *k_ptr)
+ * { return proc_uint_k2u_conv_kop(u_ptr, k_ptr, op); }
+ */
+int proc_int_k2u_conv_kop(ulong *u_ptr, const int *k_ptr, bool *negp,
+ ulong (*k_ptr_op)(const ulong));
+int proc_int_u2k_conv_uop(const ulong *u_ptr, int *k_ptr, const bool *negp,
+ ulong (*u_ptr_op)(const ulong));
+int proc_uint_k2u_conv(ulong *u_ptr, const uint *k_ptr);
+int proc_uint_u2k_conv_uop(const ulong *u_ptr, uint *k_ptr,
+ ulong (*u_ptr_op)(const ulong));
+int proc_ulong_u2k_conv_uop(const ulong *u_ptr, ulong *k_ptr,
+ ulong (*u_ptr_op)(const ulong));
+int proc_ulong_k2u_conv_kop(ulong *u_ptr, const ulong *k_ptr,
+ ulong (*k_ptr_op)(const ulong));
/*
* Register a set of sysctl names by calling register_sysctl
diff --git a/include/linux/tick.h b/include/linux/tick.h
index 1cf4651f09ad..a43b7bd8ba3f 100644
--- a/include/linux/tick.h
+++ b/include/linux/tick.h
@@ -44,9 +44,6 @@ static inline void tick_unfreeze(void) { }
#ifdef CONFIG_TICK_ONESHOT
extern void tick_irq_enter(void);
-# ifndef arch_needs_cpu
-# define arch_needs_cpu() (0)
-# endif
# else
static inline void tick_irq_enter(void) { }
#endif
diff --git a/include/linux/usb/typec.h b/include/linux/usb/typec.h
index d61ec38216fa..10a783b738ef 100644
--- a/include/linux/usb/typec.h
+++ b/include/linux/usb/typec.h
@@ -337,6 +337,7 @@ void typec_unregister_cable(struct typec_cable *cable);
struct typec_cable *typec_cable_get(struct typec_port *port);
void typec_cable_put(struct typec_cable *cable);
int typec_cable_is_active(struct typec_cable *cable);
+bool typec_cable_altmode_unsupported(struct typec_altmode *alt);
struct typec_plug *typec_register_plug(struct typec_cable *cable,
struct typec_plug_desc *desc);
diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h
index 68edac4dcd78..bfbd6a59909f 100644
--- a/include/linux/userfaultfd_k.h
+++ b/include/linux/userfaultfd_k.h
@@ -21,10 +21,11 @@
#include <linux/hugetlb_inline.h>
/* The set of all possible UFFD-related VM flags. */
-#define __VM_UFFD_FLAGS (VM_UFFD_MISSING | VM_UFFD_WP | VM_UFFD_MINOR)
+#define __VM_UFFD_FLAGS (VM_UFFD_MISSING | VM_UFFD_MINOR | \
+ VM_UFFD_WP | VM_UFFD_RWP)
#define __VMA_UFFD_FLAGS mk_vma_flags_from_masks(VMA_UFFD_MISSING, VMA_UFFD_WP, \
- VMA_UFFD_MINOR)
+ VMA_UFFD_MINOR, VMA_UFFD_RWP)
/*
* CAREFUL: Check include/uapi/asm-generic/fcntl.h when defining
@@ -149,6 +150,8 @@ static inline uffd_flags_t uffd_flags_set_mode(uffd_flags_t flags, enum mfill_at
extern long uffd_wp_range(struct vm_area_struct *vma,
unsigned long start, unsigned long len, bool enable_wp);
+extern int mrwprotect_range(struct userfaultfd_ctx *ctx, unsigned long start,
+ unsigned long len, bool enable_rwp);
/* move_pages */
void double_pt_lock(spinlock_t *ptl1, spinlock_t *ptl2);
@@ -168,7 +171,8 @@ static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma,
/*
* Never enable huge pmd sharing on some uffd registered vmas:
*
- * - VM_UFFD_WP VMAs, because write protect information is per pgtable entry.
+ * - VM_UFFD_WP and VM_UFFD_RWP VMAs, because the write protect / access
+ * tracking information is per pgtable entry.
*
* - VM_UFFD_MINOR VMAs, because otherwise we would never get minor faults for
* VMAs which share huge pmds. (If you have two mappings to the same
@@ -178,51 +182,80 @@ static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma,
*/
static inline bool uffd_disable_huge_pmd_share(struct vm_area_struct *vma)
{
- return vma->vm_flags & (VM_UFFD_WP | VM_UFFD_MINOR);
+ return vma_test_any_mask(vma,
+ mk_vma_flags_from_masks(VMA_UFFD_WP, VMA_UFFD_RWP,
+ VMA_UFFD_MINOR));
}
/*
- * Don't do fault around for either WP or MINOR registered uffd range. For
+ * Don't do fault around for WP, RWP or MINOR registered uffd range. For
* MINOR registered range, fault around will be a total disaster and ptes can
* be installed without notifications; for WP it should mostly be fine as long
* as the fault around checks for pte_none() before the installation, however
- * to be super safe we just forbid it.
+ * to be super safe we just forbid it; for RWP, pre-faulted neighbours would
+ * be indistinguishable from accessed pages in PAGEMAP_SCAN (PAGE_IS_ACCESSED)
+ * and pollute the tracked working set, so each page must be populated by its
+ * own fault.
*/
static inline bool uffd_disable_fault_around(struct vm_area_struct *vma)
{
- return vma->vm_flags & (VM_UFFD_WP | VM_UFFD_MINOR);
+ return vma_test_any_mask(vma,
+ mk_vma_flags_from_masks(VMA_UFFD_WP, VMA_UFFD_RWP,
+ VMA_UFFD_MINOR));
}
static inline bool userfaultfd_missing(struct vm_area_struct *vma)
{
- return vma->vm_flags & VM_UFFD_MISSING;
+ return vma_test_any_mask(vma, VMA_UFFD_MISSING);
}
static inline bool userfaultfd_wp(struct vm_area_struct *vma)
{
- return vma->vm_flags & VM_UFFD_WP;
+ return vma_test_any_mask(vma, VMA_UFFD_WP);
}
static inline bool userfaultfd_minor(struct vm_area_struct *vma)
{
- return vma->vm_flags & VM_UFFD_MINOR;
+ return vma_test_any_mask(vma, VMA_UFFD_MINOR);
+}
+
+static inline bool userfaultfd_rwp(struct vm_area_struct *vma)
+{
+ return vma_test_single_mask(vma, VMA_UFFD_RWP);
+}
+
+static inline bool userfaultfd_protected(struct vm_area_struct *vma)
+{
+ return userfaultfd_wp(vma) || userfaultfd_rwp(vma);
}
static inline bool userfaultfd_pte_wp(struct vm_area_struct *vma,
pte_t pte)
{
- return userfaultfd_wp(vma) && pte_uffd_wp(pte);
+ return userfaultfd_wp(vma) && pte_uffd(pte);
}
static inline bool userfaultfd_huge_pmd_wp(struct vm_area_struct *vma,
pmd_t pmd)
{
- return userfaultfd_wp(vma) && pmd_uffd_wp(pmd);
+ return userfaultfd_wp(vma) && pmd_uffd(pmd);
+}
+
+static inline bool userfaultfd_pte_rwp(struct vm_area_struct *vma,
+ pte_t pte)
+{
+ return userfaultfd_rwp(vma) && pte_uffd(pte);
+}
+
+static inline bool userfaultfd_huge_pmd_rwp(struct vm_area_struct *vma,
+ pmd_t pmd)
+{
+ return userfaultfd_rwp(vma) && pmd_uffd(pmd);
}
static inline bool userfaultfd_armed(struct vm_area_struct *vma)
{
- return vma->vm_flags & __VM_UFFD_FLAGS;
+ return vma_test_any_mask(vma, __VMA_UFFD_FLAGS);
}
static inline bool vma_has_uffd_without_event_remap(struct vm_area_struct *vma)
@@ -253,6 +286,7 @@ extern void userfaultfd_unmap_complete(struct mm_struct *mm,
struct list_head *uf);
extern bool userfaultfd_wp_unpopulated(struct vm_area_struct *vma);
extern bool userfaultfd_wp_async(struct vm_area_struct *vma);
+extern bool userfaultfd_rwp_async(struct vm_area_struct *vma);
static inline bool userfaultfd_wp_use_markers(struct vm_area_struct *vma)
{
@@ -272,10 +306,10 @@ static inline bool userfaultfd_wp_use_markers(struct vm_area_struct *vma)
}
/*
- * Returns true if this is a swap pte and was uffd-wp wr-protected in either
- * forms (pte marker or a normal swap pte), false otherwise.
+ * Returns true if this swap pte carries uffd-tracked state in either
+ * form (pte marker or a normal swap pte), false otherwise.
*/
-static inline bool pte_swp_uffd_wp_any(pte_t pte)
+static inline bool pte_swp_uffd_any(pte_t pte)
{
if (!uffd_supports_wp_marker())
return false;
@@ -283,7 +317,7 @@ static inline bool pte_swp_uffd_wp_any(pte_t pte)
if (pte_present(pte))
return false;
- if (pte_swp_uffd_wp(pte))
+ if (pte_swp_uffd(pte))
return true;
if (pte_is_uffd_wp_marker(pte))
@@ -328,6 +362,16 @@ static inline bool userfaultfd_minor(struct vm_area_struct *vma)
return false;
}
+static inline bool userfaultfd_rwp(struct vm_area_struct *vma)
+{
+ return false;
+}
+
+static inline bool userfaultfd_protected(struct vm_area_struct *vma)
+{
+ return false;
+}
+
static inline bool userfaultfd_pte_wp(struct vm_area_struct *vma,
pte_t pte)
{
@@ -340,6 +384,17 @@ static inline bool userfaultfd_huge_pmd_wp(struct vm_area_struct *vma,
return false;
}
+static inline bool userfaultfd_pte_rwp(struct vm_area_struct *vma,
+ pte_t pte)
+{
+ return false;
+}
+
+static inline bool userfaultfd_huge_pmd_rwp(struct vm_area_struct *vma,
+ pmd_t pmd)
+{
+ return false;
+}
static inline bool userfaultfd_armed(struct vm_area_struct *vma)
{
@@ -410,6 +465,11 @@ static inline bool userfaultfd_wp_async(struct vm_area_struct *vma)
return false;
}
+static inline bool userfaultfd_rwp_async(struct vm_area_struct *vma)
+{
+ return false;
+}
+
static inline bool vma_has_uffd_without_event_remap(struct vm_area_struct *vma)
{
return false;
@@ -421,10 +481,10 @@ static inline bool userfaultfd_wp_use_markers(struct vm_area_struct *vma)
}
/*
- * Returns true if this is a swap pte and was uffd-wp wr-protected in either
- * forms (pte marker or a normal swap pte), false otherwise.
+ * Returns true if this swap pte carries uffd-tracked state in either
+ * form (pte marker or a normal swap pte), false otherwise.
*/
-static inline bool pte_swp_uffd_wp_any(pte_t pte)
+static inline bool pte_swp_uffd_any(pte_t pte)
{
return false;
}
diff --git a/include/media/drv-intf/s3c_camif.h b/include/media/drv-intf/s3c_camif.h
index f746851a5ce6..00d83620ea5f 100644
--- a/include/media/drv-intf/s3c_camif.h
+++ b/include/media/drv-intf/s3c_camif.h
@@ -31,8 +31,6 @@ struct s3c_camif_sensor_info {
struct s3c_camif_plat_data {
struct s3c_camif_sensor_info sensor;
- int (*gpio_get)(void);
- int (*gpio_put)(void);
};
#endif /* MEDIA_S3C_CAMIF_ */
diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h
index 54c83b18d555..a13dca7c609f 100644
--- a/include/media/v4l2-ioctl.h
+++ b/include/media/v4l2-ioctl.h
@@ -736,8 +736,8 @@ long int video_usercopy(struct file *file, unsigned int cmd,
* @cmd: Ioctl name.
* @arg: Ioctl argument.
*
- * Method used to hancle an ioctl. Should be used to fill the
- * &v4l2_ioctl_ops.unlocked_ioctl on all V4L2 drivers.
+ * Method used to handle an ioctl. Should be used to fill the
+ * &v4l2_file_operations.unlocked_ioctl on all V4L2 drivers.
*/
long int video_ioctl2(struct file *file,
unsigned int cmd, unsigned long int arg);
diff --git a/include/net/addrconf.h b/include/net/addrconf.h
index 539bbbe54b14..8ced27a8229b 100644
--- a/include/net/addrconf.h
+++ b/include/net/addrconf.h
@@ -446,6 +446,11 @@ static inline void in6_dev_hold(struct inet6_dev *idev)
refcount_inc(&idev->refcnt);
}
+static inline bool in6_dev_hold_safe(struct inet6_dev *idev)
+{
+ return refcount_inc_not_zero(&idev->refcnt);
+}
+
/* called with rcu_read_lock held */
static inline bool ip6_ignore_linkdown(const struct net_device *dev)
{
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index ed2e9bc1bb4e..1737fbfce2d0 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -752,7 +752,8 @@ struct ip_vs_protocol {
void (*state_transition)(struct ip_vs_conn *cp, int direction,
const struct sk_buff *skb,
- struct ip_vs_proto_data *pd);
+ struct ip_vs_proto_data *pd,
+ unsigned int iph_len);
int (*register_app)(struct netns_ipvs *ipvs, struct ip_vs_app *inc);
diff --git a/include/net/mana/gdma.h b/include/net/mana/gdma.h
index 0c395917b214..8529cef0d7c4 100644
--- a/include/net/mana/gdma.h
+++ b/include/net/mana/gdma.h
@@ -47,6 +47,7 @@ enum gdma_queue_type {
GDMA_RQ,
GDMA_CQ,
GDMA_EQ,
+ GDMA_DIM,
};
enum gdma_work_request_flags {
@@ -126,6 +127,17 @@ union gdma_doorbell_entry {
u64 tail_ptr : 31;
u64 arm : 1;
} eq;
+
+ struct {
+ u64 id : 24;
+ u64 reserved : 8;
+ u64 mod_usec : 10;
+ u64 reserve1 : 5;
+ u64 mod_usec_vld : 1;
+ u64 mod_comps : 8;
+ u64 reserve2 : 7;
+ u64 mod_comps_vld: 1;
+ } dim;
}; /* HW DATA */
struct gdma_msg_hdr {
@@ -502,6 +514,9 @@ void mana_gd_ring_cq(struct gdma_queue *cq, u8 arm_bit);
int mana_schedule_serv_work(struct gdma_context *gc, enum gdma_eqe_type type);
+void mana_gd_ring_dim(struct gdma_queue *cq, u32 mod_usec, bool mod_usec_vld,
+ u32 mod_comps, bool mod_comps_vld);
+
struct gdma_wqe {
u32 reserved :24;
u32 last_vbytes :8;
@@ -650,6 +665,9 @@ enum {
/* Driver supports self recovery on Hardware Channel timeouts */
#define GDMA_DRV_CAP_FLAG_1_HWC_TIMEOUT_RECOVERY BIT(25)
+/* Driver supports dynamic interrupt moderation - DIM */
+#define GDMA_DRV_CAP_FLAG_1_DYN_INTERRUPT_MODERATION BIT(28)
+
#define GDMA_DRV_CAP_FLAGS1 \
(GDMA_DRV_CAP_FLAG_1_EQ_SHARING_MULTI_VPORT | \
GDMA_DRV_CAP_FLAG_1_NAPI_WKDONE_FIX | \
@@ -665,7 +683,8 @@ enum {
GDMA_DRV_CAP_FLAG_1_PROBE_RECOVERY | \
GDMA_DRV_CAP_FLAG_1_HANDLE_STALL_SQ_RECOVERY | \
GDMA_DRV_CAP_FLAG_1_HWC_TIMEOUT_RECOVERY | \
- GDMA_DRV_CAP_FLAG_1_EQ_MSI_UNSHARE_MULTI_VPORT)
+ GDMA_DRV_CAP_FLAG_1_EQ_MSI_UNSHARE_MULTI_VPORT | \
+ GDMA_DRV_CAP_FLAG_1_DYN_INTERRUPT_MODERATION)
#define GDMA_DRV_CAP_FLAGS2 0
@@ -701,6 +720,9 @@ struct gdma_verify_ver_req {
u8 os_ver_str4[128];
}; /* HW DATA */
+/* HW supports dynamic interrupt moderation - DIM */
+#define GDMA_PF_CAP_FLAG_1_DYN_INTERRUPT_MODERATION BIT(15)
+
struct gdma_verify_ver_resp {
struct gdma_resp_hdr hdr;
u64 gdma_protocol_ver;
diff --git a/include/net/mana/mana.h b/include/net/mana/mana.h
index 13c87baf018e..226b61504596 100644
--- a/include/net/mana/mana.h
+++ b/include/net/mana/mana.h
@@ -4,6 +4,7 @@
#ifndef _MANA_H
#define _MANA_H
+#include <linux/dim.h>
#include <net/xdp.h>
#include <net/net_shaper.h>
@@ -64,6 +65,19 @@ enum TRI_STATE {
/* Maximum number of packets per coalesced CQE */
#define MANA_RXCOMP_OOB_NUM_PPI 4
+/* Default/max interrupt moderation settings */
+#define MANA_INTR_MODR_USEC_DEF 0
+#define MANA_INTR_MODR_COMP_DEF 0
+
+#define MANA_ADAPTIVE_RX_DEF true
+#define MANA_ADAPTIVE_TX_DEF true
+
+/* DIM doorbell value field layout */
+#define MANA_INTR_MODR_USEC_MAX GENMASK(9, 0)
+#define MANA_INTR_MODR_USEC_VLD BIT(15)
+#define MANA_INTR_MODR_COMP_MAX GENMASK(7, 0)
+#define MANA_INTR_MODR_COMP_MASK GENMASK(23, 16)
+
/* Update this count whenever the respective structures are changed */
#define MANA_STATS_RX_COUNT (6 + MANA_RXCOMP_OOB_NUM_PPI - 1)
#define MANA_STATS_TX_COUNT 11
@@ -297,6 +311,17 @@ struct mana_cq {
int work_done;
int work_done_since_doorbell;
int budget;
+
+ /* DIM - Dynamic Interrupt Moderation */
+ struct dim dim;
+ u16 dim_event_ctr;
+
+ /* Cumulative TX completions fed to DIM. Updated and read only in
+ * NAPI context (mana_poll_tx_cq() / mana_update_tx_dim()), so they
+ * measure the hardware completion rate and need no u64_stats_sync.
+ */
+ u64 tx_dim_pkts;
+ u64 tx_dim_bytes;
};
struct mana_recv_buf_oob {
@@ -305,6 +330,14 @@ struct mana_recv_buf_oob {
void *buf_va;
bool from_pool; /* allocated from a page pool */
+ /* head page of the page_pool fragment; valid only when
+ * from_pool && frag_count > 1.
+ */
+ struct page *pp_page;
+ /* Fragment offset plus rxq->headroom, passed to
+ * page_pool_dma_sync_for_cpu().
+ */
+ u32 dma_sync_offset;
/* SGL of the buffer going to be sent as part of the work request. */
u32 num_sge;
@@ -573,6 +606,15 @@ struct mana_port_context {
u8 cqe_coalescing_enable;
u32 cqe_coalescing_timeout_ns;
+ /* Interrupt moderation settings */
+ u16 intr_modr_rx_usec;
+ u16 intr_modr_rx_comp;
+ u16 intr_modr_tx_usec;
+ u16 intr_modr_tx_comp;
+
+ bool rx_dim_enabled;
+ bool tx_dim_enabled;
+
struct mana_ethtool_stats eth_stats;
struct mana_ethtool_phy_stats phy_stats;
@@ -598,6 +640,8 @@ int mana_alloc_queues(struct net_device *ndev);
int mana_attach(struct net_device *ndev);
int mana_detach(struct net_device *ndev, bool from_close);
+void mana_dim_change(struct mana_cq *cq, bool enable);
+
int mana_probe(struct gdma_dev *gd, bool resuming);
void mana_remove(struct gdma_dev *gd, bool suspending);
@@ -633,6 +677,9 @@ struct mana_obj_spec {
u32 queue_size;
u32 attached_eq;
u32 modr_ctx_id;
+ u8 req_cq_moderation;
+ u16 cq_moderation_comp;
+ u16 cq_moderation_usec;
};
enum mana_command_code {
@@ -764,6 +811,15 @@ struct mana_create_wqobj_req {
u32 cq_size;
u32 cq_moderation_ctx_id;
u32 cq_parent_qid;
+
+ /* V2 */
+ u8 allow_rqwqe_chain;
+
+ /* V3 */
+ u8 req_cq_moderation;
+ u16 cq_moderation_comp;
+ u16 cq_moderation_usec;
+ u8 reserved2[2];
}; /* HW DATA */
struct mana_create_wqobj_resp {
@@ -771,6 +827,12 @@ struct mana_create_wqobj_resp {
u32 wq_id;
u32 cq_id;
mana_handle_t wq_obj;
+
+ /* V2 */
+ u16 cq_moderation_comp;
+ u16 cq_moderation_usec;
+ u8 cq_moderation_enabled;
+ u8 reserved1[3];
}; /* HW DATA */
/* Destroy WQ Object */
diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h
index 7b23b245a5a8..ce414118962f 100644
--- a/include/net/netfilter/nf_flow_table.h
+++ b/include/net/netfilter/nf_flow_table.h
@@ -155,11 +155,12 @@ struct flow_offload_tuple {
tun_num:2,
in_vlan_ingress:2;
u16 mtu;
+ u32 dst_cookie;
+ struct dst_entry *dst_cache;
+
union {
struct {
- struct dst_entry *dst_cache;
u32 ifidx;
- u32 dst_cookie;
};
struct {
u32 ifidx;
@@ -357,6 +358,8 @@ static inline int nf_flow_register_bpf(void)
void nf_flow_offload_add(struct nf_flowtable *flowtable,
struct flow_offload *flow);
+void nf_flow_offload_refresh(struct nf_flowtable *flowtable,
+ struct flow_offload *flow);
void nf_flow_offload_del(struct nf_flowtable *flowtable,
struct flow_offload *flow);
void nf_flow_offload_stats(struct nf_flowtable *flowtable,
diff --git a/include/trace/events/huge_memory.h b/include/trace/events/huge_memory.h
index 291fae364c62..5a48c5406cce 100644
--- a/include/trace/events/huge_memory.h
+++ b/include/trace/events/huge_memory.h
@@ -16,7 +16,7 @@
EM( SCAN_EXCEED_SWAP_PTE, "exceed_swap_pte") \
EM( SCAN_EXCEED_SHARED_PTE, "exceed_shared_pte") \
EM( SCAN_PTE_NON_PRESENT, "pte_non_present") \
- EM( SCAN_PTE_UFFD_WP, "pte_uffd_wp") \
+ EM( SCAN_PTE_UFFD, "pte_uffd_wp") \
EM( SCAN_PTE_MAPPED_HUGEPAGE, "pte_mapped_hugepage") \
EM( SCAN_LACK_REFERENCED_PAGE, "lack_referenced_page") \
EM( SCAN_PAGE_NULL, "page_null") \
diff --git a/include/trace/events/mmflags.h b/include/trace/events/mmflags.h
index c1a05ff0feab..935893e5ea53 100644
--- a/include/trace/events/mmflags.h
+++ b/include/trace/events/mmflags.h
@@ -186,6 +186,12 @@ IF_HAVE_PG_ARCH_3(arch_3)
# define IF_HAVE_UFFD_MINOR(flag, name)
#endif
+#ifdef CONFIG_USERFAULTFD_RWP
+# define IF_HAVE_UFFD_RWP(flag, name) {flag, name},
+#else
+# define IF_HAVE_UFFD_RWP(flag, name)
+#endif
+
#if defined(CONFIG_64BIT) || defined(CONFIG_PPC32)
# define IF_HAVE_VM_DROPPABLE(flag, name) {flag, name},
#else
@@ -207,6 +213,7 @@ IF_HAVE_UFFD_MINOR(VM_UFFD_MINOR, "uffd_minor" ) \
{VM_PFNMAP, "pfnmap" }, \
{VM_MAYBE_GUARD, "maybe_guard" }, \
{VM_UFFD_WP, "uffd_wp" }, \
+IF_HAVE_UFFD_RWP(VM_UFFD_RWP, "uffd_rwp" ) \
{VM_LOCKED, "locked" }, \
{VM_IO, "io" }, \
{VM_SEQ_READ, "seqread" }, \
diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
index bd87262f2e34..34c6f219462a 100644
--- a/include/uapi/linux/fs.h
+++ b/include/uapi/linux/fs.h
@@ -471,6 +471,7 @@ typedef int __bitwise __kernel_rwf_t;
#define PAGE_IS_HUGE (1 << 6)
#define PAGE_IS_SOFT_DIRTY (1 << 7)
#define PAGE_IS_GUARD (1 << 8)
+#define PAGE_IS_ACCESSED (1 << 9)
/*
* struct page_region - Page region with flags
diff --git a/include/uapi/linux/landlock.h b/include/uapi/linux/landlock.h
index 7ffe2ef127ee..272f047df438 100644
--- a/include/uapi/linux/landlock.h
+++ b/include/uapi/linux/landlock.h
@@ -315,16 +315,16 @@ struct landlock_net_port_attr {
* :manpage:`connect(2)` as well as calls to :manpage:`sendmsg(2)` with an
* explicit recipient address.
*
- * This access right only applies to connections to UNIX server sockets which
+ * This access right applies only to connections to UNIX server sockets which
* were created outside of the newly created Landlock domain (e.g. from within
* a parent domain or from an unrestricted process). Newly created UNIX
* servers within the same Landlock domain continue to be accessible. In this
* regard, %LANDLOCK_ACCESS_FS_RESOLVE_UNIX has the same semantics as the
* ``LANDLOCK_SCOPE_*`` flags.
*
- * If a resolve attempt is denied, the operation returns an ``EACCES`` error,
- * in line with other filesystem access rights (but different to denials for
- * abstract UNIX domain sockets).
+ * If a resolution attempt is denied, the operation returns an ``EACCES``
+ * error, in line with other filesystem access rights (but different to
+ * denials for abstract UNIX domain sockets).
*
* This access right is available since the ninth version of the Landlock ABI.
*
diff --git a/include/uapi/linux/userfaultfd.h b/include/uapi/linux/userfaultfd.h
index 2841e4ea8f2c..cea11aad6b54 100644
--- a/include/uapi/linux/userfaultfd.h
+++ b/include/uapi/linux/userfaultfd.h
@@ -25,7 +25,8 @@
#define UFFD_API ((__u64)0xAA)
#define UFFD_API_REGISTER_MODES (UFFDIO_REGISTER_MODE_MISSING | \
UFFDIO_REGISTER_MODE_WP | \
- UFFDIO_REGISTER_MODE_MINOR)
+ UFFDIO_REGISTER_MODE_MINOR | \
+ UFFDIO_REGISTER_MODE_RWP)
#define UFFD_API_FEATURES (UFFD_FEATURE_PAGEFAULT_FLAG_WP | \
UFFD_FEATURE_EVENT_FORK | \
UFFD_FEATURE_EVENT_REMAP | \
@@ -42,10 +43,13 @@
UFFD_FEATURE_WP_UNPOPULATED | \
UFFD_FEATURE_POISON | \
UFFD_FEATURE_WP_ASYNC | \
- UFFD_FEATURE_MOVE)
+ UFFD_FEATURE_MOVE | \
+ UFFD_FEATURE_RWP | \
+ UFFD_FEATURE_RWP_ASYNC)
#define UFFD_API_IOCTLS \
((__u64)1 << _UFFDIO_REGISTER | \
(__u64)1 << _UFFDIO_UNREGISTER | \
+ (__u64)1 << _UFFDIO_SET_MODE | \
(__u64)1 << _UFFDIO_API)
#define UFFD_API_RANGE_IOCTLS \
((__u64)1 << _UFFDIO_WAKE | \
@@ -54,13 +58,15 @@
(__u64)1 << _UFFDIO_MOVE | \
(__u64)1 << _UFFDIO_WRITEPROTECT | \
(__u64)1 << _UFFDIO_CONTINUE | \
- (__u64)1 << _UFFDIO_POISON)
+ (__u64)1 << _UFFDIO_POISON | \
+ (__u64)1 << _UFFDIO_RWPROTECT)
#define UFFD_API_RANGE_IOCTLS_BASIC \
((__u64)1 << _UFFDIO_WAKE | \
(__u64)1 << _UFFDIO_COPY | \
(__u64)1 << _UFFDIO_WRITEPROTECT | \
(__u64)1 << _UFFDIO_CONTINUE | \
- (__u64)1 << _UFFDIO_POISON)
+ (__u64)1 << _UFFDIO_POISON | \
+ (__u64)1 << _UFFDIO_RWPROTECT)
/*
* Valid ioctl command number range with this API is from 0x00 to
@@ -79,6 +85,8 @@
#define _UFFDIO_WRITEPROTECT (0x06)
#define _UFFDIO_CONTINUE (0x07)
#define _UFFDIO_POISON (0x08)
+#define _UFFDIO_RWPROTECT (0x09)
+#define _UFFDIO_SET_MODE (0x0A)
#define _UFFDIO_API (0x3F)
/* userfaultfd ioctl ids */
@@ -103,6 +111,10 @@
struct uffdio_continue)
#define UFFDIO_POISON _IOWR(UFFDIO, _UFFDIO_POISON, \
struct uffdio_poison)
+#define UFFDIO_RWPROTECT _IOWR(UFFDIO, _UFFDIO_RWPROTECT, \
+ struct uffdio_rwprotect)
+#define UFFDIO_SET_MODE _IOW(UFFDIO, _UFFDIO_SET_MODE, \
+ struct uffdio_set_mode)
/* read() structure */
struct uffd_msg {
@@ -158,6 +170,7 @@ struct uffd_msg {
#define UFFD_PAGEFAULT_FLAG_WRITE (1<<0) /* If this was a write fault */
#define UFFD_PAGEFAULT_FLAG_WP (1<<1) /* If reason is VM_UFFD_WP */
#define UFFD_PAGEFAULT_FLAG_MINOR (1<<2) /* If reason is VM_UFFD_MINOR */
+#define UFFD_PAGEFAULT_FLAG_RWP (1<<3) /* If reason is VM_UFFD_RWP */
struct uffdio_api {
/* userland asks for an API number and the features to enable */
@@ -230,6 +243,18 @@ struct uffdio_api {
*
* UFFD_FEATURE_MOVE indicates that the kernel supports moving an
* existing page contents from userspace.
+ *
+ * UFFD_FEATURE_RWP indicates that the kernel supports
+ * UFFDIO_REGISTER_MODE_RWP for read-write protection tracking.
+ * Pages are made inaccessible via UFFDIO_RWPROTECT and faults
+ * are delivered when the pages are re-accessed.
+ *
+ * UFFD_FEATURE_RWP_ASYNC indicates asynchronous mode for
+ * UFFDIO_REGISTER_MODE_RWP. When set, faults on read-write
+ * protected pages are auto-resolved by the kernel (PTE
+ * permissions restored immediately) without delivering a message
+ * to the userfaultfd handler. Use PAGEMAP_SCAN with inverted
+ * PAGE_IS_ACCESSED to find pages that were not re-accessed.
*/
#define UFFD_FEATURE_PAGEFAULT_FLAG_WP (1<<0)
#define UFFD_FEATURE_EVENT_FORK (1<<1)
@@ -248,6 +273,8 @@ struct uffdio_api {
#define UFFD_FEATURE_POISON (1<<14)
#define UFFD_FEATURE_WP_ASYNC (1<<15)
#define UFFD_FEATURE_MOVE (1<<16)
+#define UFFD_FEATURE_RWP (1<<17)
+#define UFFD_FEATURE_RWP_ASYNC (1<<18)
__u64 features;
__u64 ioctls;
@@ -263,6 +290,7 @@ struct uffdio_register {
#define UFFDIO_REGISTER_MODE_MISSING ((__u64)1<<0)
#define UFFDIO_REGISTER_MODE_WP ((__u64)1<<1)
#define UFFDIO_REGISTER_MODE_MINOR ((__u64)1<<2)
+#define UFFDIO_REGISTER_MODE_RWP ((__u64)1<<3)
__u64 mode;
/*
@@ -356,6 +384,14 @@ struct uffdio_poison {
__s64 updated;
};
+struct uffdio_rwprotect {
+ struct uffdio_range range;
+ /* !RWP means undo RWP-protection */
+#define UFFDIO_RWPROTECT_MODE_RWP ((__u64)1<<0)
+#define UFFDIO_RWPROTECT_MODE_DONTWAKE ((__u64)1<<1)
+ __u64 mode;
+};
+
struct uffdio_move {
__u64 dst;
__u64 src;
@@ -374,6 +410,16 @@ struct uffdio_move {
__s64 move;
};
+struct uffdio_set_mode {
+ /*
+ * Toggle async mode for features at runtime.
+ * Supported: UFFD_FEATURE_RWP_ASYNC.
+ * Setting a bit in both enable and disable is invalid.
+ */
+ __u64 enable;
+ __u64 disable;
+};
+
/*
* Flags for the userfaultfd(2) system call itself.
*/
diff --git a/init/Kconfig b/init/Kconfig
index fa42fb264c9c..9ee6447dd454 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -948,6 +948,13 @@ config SCHED_PROXY_EXEC
endmenu
#
+# For architectures that support present-but-inaccessible (PROT_NONE) page
+# table entries detectable via pte_protnone() / pmd_protnone():
+#
+config ARCH_HAS_PTE_PROTNONE
+ bool
+
+#
# For architectures that want to enable the support for NUMA-affine scheduler
# balancing logic:
#
@@ -1013,6 +1020,7 @@ config ARCH_WANT_NUMA_VARIABLE_LOCALITY
config NUMA_BALANCING
bool "Memory placement aware NUMA scheduler"
depends on ARCH_SUPPORTS_NUMA_BALANCING
+ depends on ARCH_HAS_PTE_PROTNONE
depends on !ARCH_WANT_NUMA_VARIABLE_LOCALITY
depends on SMP && NUMA_MIGRATION && !PREEMPT_RT
help
diff --git a/io_uring/tw.c b/io_uring/tw.c
index a4c872870d81..e6ee15571e85 100644
--- a/io_uring/tw.c
+++ b/io_uring/tw.c
@@ -139,11 +139,11 @@ void tctx_task_work(struct callback_head *cb)
*/
static void io_ctx_mark_taskrun(struct io_ring_ctx *ctx)
{
+ lockdep_assert_in_rcu_read_lock();
+
if (ctx->flags & IORING_SETUP_TASKRUN_FLAG) {
- struct io_rings *rings;
+ struct io_rings *rings = rcu_dereference(ctx->rings_rcu);
- guard(rcu)();
- rings = rcu_dereference(ctx->rings_rcu);
atomic_or(IORING_SQ_TASKRUN, &rings->sq_flags);
}
}
@@ -153,6 +153,9 @@ void io_req_local_work_add(struct io_kiocb *req, unsigned flags)
struct io_ring_ctx *ctx = req->ctx;
int nr_wait;
+ /* pairs with synchronize_rcu() in io_ring_exit_work() */
+ guard(rcu)();
+
/*
* We don't know how many requests there are in the link and whether
* they can even be queued lazily, fall back to non-lazy.
diff --git a/kernel/audit.c b/kernel/audit.c
index feaa4e2271d7..562476937fa7 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -62,6 +62,7 @@
#include <net/ip.h>
#include <net/ipv6.h>
#include <linux/sctp.h>
+#include <linux/overflow.h>
#include "audit.h"
@@ -2080,7 +2081,8 @@ void audit_log_format(struct audit_buffer *ab, const char *fmt, ...)
void audit_log_n_hex(struct audit_buffer *ab, const unsigned char *buf,
size_t len)
{
- int i, avail, new_len;
+ int avail;
+ size_t i, new_len;
unsigned char *ptr;
struct sk_buff *skb;
@@ -2090,7 +2092,12 @@ void audit_log_n_hex(struct audit_buffer *ab, const unsigned char *buf,
BUG_ON(!ab->skb);
skb = ab->skb;
avail = skb_tailroom(skb);
- new_len = len<<1;
+
+ if (check_shl_overflow(len, 1, &new_len)) {
+ audit_log_format(ab, "?");
+ return;
+ }
+
if (new_len >= avail) {
/* Round the buffer request up to the next multiple */
new_len = AUDIT_BUFSIZ*(((new_len-avail)/AUDIT_BUFSIZ) + 1);
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index dff5c0d91641..8c04c340f499 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -6451,7 +6451,7 @@ struct btf *btf_parse_vmlinux(void)
if (IS_ERR(btf))
goto err_out;
- /* btf_parse_vmlinux() runs under bpf_verifier_lock */
+ /* btf_parse_vmlinux() runs under btf_vmlinux_lock */
bpf_ctx_convert.t = btf_type_by_id(btf, bpf_ctx_convert_btf_id[0]);
err = btf_alloc_id(btf);
if (err) {
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 6e19a030da6f..47fe047ad30b 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -126,6 +126,7 @@ struct bpf_prog *bpf_prog_alloc_no_stats(unsigned int size, gfp_t gfp_extra_flag
fp->aux->main_prog_aux = aux;
fp->aux->prog = fp;
fp->jit_requested = ebpf_jit_enabled();
+ fp->jit_required = IS_ENABLED(CONFIG_BPF_JIT_ALWAYS_ON);
fp->blinding_requested = bpf_jit_blinding_enabled(fp);
#ifdef CONFIG_CGROUP_BPF
aux->cgroup_atype = CGROUP_BPF_ATTACH_TYPE_INVALID;
@@ -305,7 +306,7 @@ int bpf_prog_calc_tag(struct bpf_prog *fp)
bool was_ld_map;
u32 i;
- dst = vmalloc(size);
+ dst = __vmalloc(size, GFP_KERNEL_ACCOUNT);
if (!dst)
return -ENOMEM;
@@ -2670,15 +2671,11 @@ struct bpf_prog *__bpf_prog_select_runtime(struct bpf_verifier_env *env, struct
/* In case of BPF to BPF calls, verifier did all the prep
* work with regards to JITing, etc.
*/
- bool jit_needed = false;
+ bool jit_needed = fp->jit_required;
if (fp->bpf_func)
goto finalize;
- if (IS_ENABLED(CONFIG_BPF_JIT_ALWAYS_ON) ||
- bpf_prog_has_kfunc_call(fp))
- jit_needed = true;
-
if (!bpf_prog_select_interpreter(fp))
jit_needed = true;
diff --git a/kernel/bpf/fixups.c b/kernel/bpf/fixups.c
index 12a8a4eb757f..d3be972714b2 100644
--- a/kernel/bpf/fixups.c
+++ b/kernel/bpf/fixups.c
@@ -1378,7 +1378,6 @@ int bpf_fixup_call_args(struct bpf_verifier_env *env)
#ifndef CONFIG_BPF_JIT_ALWAYS_ON
struct bpf_prog *prog = env->prog;
struct bpf_insn *insn = prog->insnsi;
- bool has_kfunc_call = bpf_prog_has_kfunc_call(prog);
int depth;
#endif
int i, err = 0;
@@ -1404,8 +1403,8 @@ int bpf_fixup_call_args(struct bpf_verifier_env *env)
return err;
}
#ifndef CONFIG_BPF_JIT_ALWAYS_ON
- if (has_kfunc_call) {
- verbose(env, "calling kernel functions are not allowed in non-JITed programs\n");
+ if (prog->jit_required) {
+ verbose(env, "program requires BPF JIT compiler but it is not available\n");
return -EINVAL;
}
for (i = 0; i < env->subprog_cnt; i++) {
@@ -1841,8 +1840,10 @@ int bpf_do_misc_fixups(struct bpf_verifier_env *env)
}
/* Skip inlining the helper call if the JIT does it. */
- if (bpf_jit_inlines_helper_call(insn->imm))
+ if (bpf_jit_inlines_helper_call(insn->imm)) {
+ prog->jit_required = 1;
goto next_insn;
+ }
if (insn->imm == BPF_FUNC_get_route_realm)
prog->dst_needed = 1;
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 6db306d23b47..0ff9e3aa293d 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -40,7 +40,6 @@
#include <linux/tracepoint.h>
#include <linux/overflow.h>
#include <linux/cookie.h>
-#include <linux/verification.h>
#include <linux/btf_ids.h>
#include <net/netfilter/nf_bpf_link.h>
@@ -1599,13 +1598,6 @@ static int map_create_alloc(union bpf_attr *attr, bpfptr_t uattr, struct bpf_ver
err = -EFAULT;
goto free_map;
}
-
- /* See libbpf: emit_signature_match() */
- BUILD_BUG_ON(offsetof(struct bpf_map, excl) != SHA256_DIGEST_SIZE);
- BUILD_BUG_ON(!__same_type(map->excl, u32));
- BUILD_BUG_ON(offsetof(struct bpf_map, sha) != 0);
- BUILD_BUG_ON(!__same_type(map->sha, u8[SHA256_DIGEST_SIZE]));
- map->excl = 1;
} else if (attr->excl_prog_hash_size) {
bpf_log(log, "Invalid excl_prog_hash_size.\n");
err = -EINVAL;
@@ -1657,7 +1649,7 @@ static int map_create(union bpf_attr *attr, bpfptr_t uattr, struct bpf_common_at
err = security_bpf_map_create(map, attr, token, uattr.is_kernel);
if (err)
- goto free_map_sec;
+ goto free_map;
err = bpf_map_alloc_id(map);
if (err)
@@ -2886,64 +2878,6 @@ static bool is_perfmon_prog_type(enum bpf_prog_type prog_type)
}
}
-static enum bpf_sig_keyring bpf_classify_keyring(s32 keyring_id)
-{
- switch (keyring_id) {
- case 0:
- return BPF_SIG_KEYRING_BUILTIN;
- case (s32)(unsigned long)VERIFY_USE_SECONDARY_KEYRING:
- return BPF_SIG_KEYRING_SECONDARY;
- case (s32)(unsigned long)VERIFY_USE_PLATFORM_KEYRING:
- return BPF_SIG_KEYRING_PLATFORM;
- default:
- return BPF_SIG_KEYRING_USER;
- }
-}
-
-static int bpf_prog_verify_signature(struct bpf_prog *prog, union bpf_attr *attr,
- bool is_kernel, s32 *keyring_serial)
-{
- bpfptr_t usig = make_bpfptr(attr->signature, is_kernel);
- struct bpf_dynptr_kern sig_ptr, insns_ptr;
- struct bpf_key *key = NULL;
- void *sig;
- int err = 0;
-
- /*
- * Don't attempt to use kmalloc_large or vmalloc for signatures.
- * Practical signature for BPF program should be below this limit.
- */
- if (attr->signature_size > KMALLOC_MAX_CACHE_SIZE)
- return -EINVAL;
-
- if (system_keyring_id_check(attr->keyring_id) == 0)
- key = bpf_lookup_system_key(attr->keyring_id);
- else
- key = bpf_lookup_user_key(attr->keyring_id, 0);
-
- if (!key)
- return -EINVAL;
-
- sig = kvmemdup_bpfptr(usig, attr->signature_size);
- if (IS_ERR(sig)) {
- bpf_key_put(key);
- return PTR_ERR(sig);
- }
-
- bpf_dynptr_init(&sig_ptr, sig, BPF_DYNPTR_TYPE_LOCAL, 0,
- attr->signature_size);
- bpf_dynptr_init(&insns_ptr, prog->insnsi, BPF_DYNPTR_TYPE_LOCAL, 0,
- prog->len * sizeof(struct bpf_insn));
-
- err = bpf_verify_pkcs7_signature((struct bpf_dynptr *)&insns_ptr,
- (struct bpf_dynptr *)&sig_ptr, key);
- if (!err)
- *keyring_serial = bpf_key_serial(key);
- bpf_key_put(key);
- kvfree(sig);
- return err;
-}
-
static int bpf_prog_mark_insn_arrays_ready(struct bpf_prog *prog)
{
int err;
@@ -3133,17 +3067,8 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, struct bpf_log_at
/* eBPF programs must be GPL compatible to use GPL-ed functions */
prog->gpl_compatible = license_is_gpl_compatible(license) ? 1 : 0;
- if (attr->signature) {
- err = bpf_prog_verify_signature(prog, attr, uattr.is_kernel,
- &prog->aux->sig.keyring_serial);
- if (err)
- goto free_prog;
- prog->aux->sig.keyring_type = bpf_classify_keyring(attr->keyring_id);
- prog->aux->sig.verdict = BPF_SIG_VERIFIED;
- } else {
- prog->aux->sig.keyring_type = BPF_SIG_KEYRING_NONE;
- prog->aux->sig.verdict = BPF_SIG_UNSIGNED;
- }
+ prog->aux->sig.keyring_type = BPF_SIG_KEYRING_NONE;
+ prog->aux->sig.verdict = BPF_SIG_UNSIGNED;
prog->orig_prog = NULL;
prog->jited = 0;
@@ -3189,10 +3114,6 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, struct bpf_log_at
if (err < 0)
goto free_prog;
- err = security_bpf_prog_load(prog, attr, token, uattr.is_kernel);
- if (err)
- goto free_prog;
-
/* run eBPF verifier */
err = bpf_check(&prog, attr, uattr, attr_log);
if (err < 0)
diff --git a/kernel/bpf/task_iter.c b/kernel/bpf/task_iter.c
index e791ae065c39..b256fb9c1214 100644
--- a/kernel/bpf/task_iter.c
+++ b/kernel/bpf/task_iter.c
@@ -756,6 +756,7 @@ BPF_CALL_5(bpf_find_vma, struct task_struct *, task, u64, start,
struct mmap_unlock_irq_work *work = NULL;
struct vm_area_struct *vma;
bool irq_work_busy = false;
+ bool __maybe_unused mmput_needed = false;
struct mm_struct *mm;
int ret = -ENOENT;
@@ -765,14 +766,38 @@ BPF_CALL_5(bpf_find_vma, struct task_struct *, task, u64, start,
if (!task)
return -ENOENT;
- mm = task->mm;
+ if (task == current) {
+ mm = task->mm;
+ } else {
+ /*
+ * Foreign task: pin task->mm against a concurrent exit_mm().
+ * Use trylock on alloc_lock instead of get_task_mm()'s
+ * blocking task_lock() to avoid deadlocking the target task.
+ */
+ if (!IS_ENABLED(CONFIG_MMU))
+ return -EOPNOTSUPP;
+ if (irqs_disabled())
+ return -EBUSY;
+ if (!spin_trylock(&task->alloc_lock))
+ return -EBUSY;
+ mm = task->mm;
+ if (mm && !(task->flags & PF_KTHREAD)) {
+ mmget(mm);
+ mmput_needed = true;
+ } else {
+ mm = NULL;
+ }
+ spin_unlock(&task->alloc_lock);
+ }
if (!mm)
return -ENOENT;
irq_work_busy = bpf_mmap_unlock_get_irq_work(&work);
- if (irq_work_busy || !mmap_read_trylock(mm))
- return -EBUSY;
+ if (irq_work_busy || !mmap_read_trylock(mm)) {
+ ret = -EBUSY;
+ goto out;
+ }
vma = find_vma(mm, start);
@@ -782,6 +807,11 @@ BPF_CALL_5(bpf_find_vma, struct task_struct *, task, u64, start,
ret = 0;
}
bpf_mmap_unlock_mm(work, mm);
+out:
+#ifdef CONFIG_MMU
+ if (mmput_needed)
+ mmput_async(mm);
+#endif
return ret;
}
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 51f7965d42e3..03e2202cca13 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -22,6 +22,8 @@
#include <linux/ctype.h>
#include <linux/error-injection.h>
#include <linux/bpf_lsm.h>
+#include <linux/security.h>
+#include <linux/verification.h>
#include <linux/btf_ids.h>
#include <linux/poison.h>
#include <linux/module.h>
@@ -322,6 +324,7 @@ static const char *btf_type_name(const struct btf *btf, u32 id)
}
static DEFINE_MUTEX(bpf_verifier_lock);
+static DEFINE_MUTEX(btf_vmlinux_lock);
static DEFINE_MUTEX(bpf_percpu_ma_lock);
__printf(2, 3) static void verbose(void *private_data, const char *fmt, ...)
@@ -2490,6 +2493,83 @@ int bpf_get_kfunc_addr(const struct bpf_prog *prog, u32 func_id,
return 0;
}
+#define BPF_FD_SLOT_BTF 1UL
+
+static void fd_slot_set_map(struct bpf_fd_array *slot, struct bpf_map *map)
+{
+ slot->val = (unsigned long)map;
+}
+
+static void fd_slot_set_btf(struct bpf_fd_array *slot, struct btf *btf)
+{
+ slot->val = (unsigned long)btf | BPF_FD_SLOT_BTF;
+}
+
+static struct bpf_map *fd_slot_map(struct bpf_fd_array slot)
+{
+ if (slot.val & BPF_FD_SLOT_BTF)
+ return NULL;
+ return (struct bpf_map *)slot.val;
+}
+
+static struct btf *fd_slot_btf(struct bpf_fd_array slot)
+{
+ if (!(slot.val & BPF_FD_SLOT_BTF))
+ return NULL;
+ return (struct btf *)(slot.val & ~BPF_FD_SLOT_BTF);
+}
+
+static struct btf *
+fd_array_get_btf_continuous(struct bpf_verifier_env *env, u32 idx)
+{
+ struct btf *btf;
+
+ if (idx >= env->fd_array_cnt) {
+ verbose(env, "kfunc fd_idx %u out of bounds, fd_array_cnt %u\n",
+ idx, env->fd_array_cnt);
+ return ERR_PTR(-EINVAL);
+ }
+ btf = fd_slot_btf(env->fd_array[idx]);
+ if (!btf) {
+ verbose(env, "kfunc fd_idx %u is not a module BTF\n", idx);
+ return ERR_PTR(-EINVAL);
+ }
+ btf_get(btf);
+ return btf;
+}
+
+static struct btf *
+fd_array_get_btf_sparse(struct bpf_verifier_env *env, u32 idx)
+{
+ struct btf *btf;
+ int btf_fd;
+
+ if (copy_from_bpfptr_offset(&btf_fd, env->fd_array_raw,
+ (size_t)idx * sizeof(btf_fd), sizeof(btf_fd)))
+ return ERR_PTR(-EFAULT);
+ btf = btf_get_by_fd(btf_fd);
+ if (IS_ERR(btf)) {
+ verbose(env, "invalid module BTF fd specified\n");
+ return btf;
+ }
+ return btf;
+}
+
+static struct btf *fd_array_get_btf(struct bpf_verifier_env *env, u32 idx)
+{
+ if (env->signature) {
+ verbose(env, "signed program cannot bind any BTF\n");
+ return ERR_PTR(-EACCES);
+ }
+ if (env->fd_array)
+ return fd_array_get_btf_continuous(env, idx);
+ if (!bpfptr_is_null(env->fd_array_raw))
+ return fd_array_get_btf_sparse(env, idx);
+
+ verbose(env, "kfunc offset > 0 without fd_array is invalid\n");
+ return ERR_PTR(-EPROTO);
+}
+
static struct btf *__find_kfunc_desc_btf(struct bpf_verifier_env *env,
s16 offset)
{
@@ -2498,7 +2578,6 @@ static struct btf *__find_kfunc_desc_btf(struct bpf_verifier_env *env,
struct bpf_kfunc_btf *b;
struct module *mod;
struct btf *btf;
- int btf_fd;
tab = env->prog->aux->kfunc_btf_tab;
b = bsearch(&kf_btf, tab->descs, tab->nr_descs,
@@ -2509,22 +2588,9 @@ static struct btf *__find_kfunc_desc_btf(struct bpf_verifier_env *env,
return ERR_PTR(-E2BIG);
}
- if (bpfptr_is_null(env->fd_array)) {
- verbose(env, "kfunc offset > 0 without fd_array is invalid\n");
- return ERR_PTR(-EPROTO);
- }
-
- if (copy_from_bpfptr_offset(&btf_fd, env->fd_array,
- offset * sizeof(btf_fd),
- sizeof(btf_fd)))
- return ERR_PTR(-EFAULT);
-
- btf = btf_get_by_fd(btf_fd);
- if (IS_ERR(btf)) {
- verbose(env, "invalid module BTF fd specified\n");
+ btf = fd_array_get_btf(env, offset);
+ if (IS_ERR(btf))
return btf;
- }
-
if (!btf_is_module(btf)) {
verbose(env, "BTF fd for kfunc is not a module BTF\n");
btf_put(btf);
@@ -2714,6 +2780,8 @@ int bpf_add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, u16 offset)
prog_aux->kfunc_tab = tab;
}
+ env->prog->jit_required = 1;
+
/* func_id == 0 is always invalid, but instead of returning an error, be
* conservative and wait until the code elimination pass before returning
* error, so that invalid calls that get pruned out can be in BPF programs
@@ -2768,11 +2836,6 @@ int bpf_add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, u16 offset)
return 0;
}
-bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog)
-{
- return !!prog->aux->kfunc_tab;
-}
-
static int add_subprog_and_kfunc(struct bpf_verifier_env *env)
{
struct bpf_subprog_info *subprog = env->subprog_info;
@@ -5790,6 +5853,11 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env,
return -EACCES;
}
+ if (atype != BPF_READ && (type_flag(reg->type) & PTR_UNTRUSTED)) {
+ verbose(env, "only read is supported\n");
+ return -EACCES;
+ }
+
if (env->ops->btf_struct_access && !type_is_alloc(reg->type) && atype == BPF_WRITE) {
if (!btf_is_kernel(reg->btf)) {
verifier_bug(env, "reg->btf must be kernel btf");
@@ -5802,8 +5870,7 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env,
reg_arg_name(env, argno), tname, off, size);
} else {
/* Writes are permitted with default btf_struct_access for
- * program allocated objects (which always have id > 0),
- * but not for untrusted PTR_TO_BTF_ID | MEM_ALLOC.
+ * program allocated objects (which always have id > 0).
*/
if (atype != BPF_READ && !type_is_ptr_alloc_obj(reg->type)) {
verbose(env, "only read is supported\n");
@@ -6327,11 +6394,23 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, struct b
if (!err && size < BPF_REG_SIZE && value_regno >= 0 && t == BPF_READ &&
regs[value_regno].type == SCALAR_VALUE) {
- if (!is_ldsx)
+ if (!is_ldsx) {
/* b/h/w load zero-extends, mark upper bits as known 0 */
coerce_reg_to_size(&regs[value_regno], size);
- else
+ } else {
+ /*
+ * Sign-extension can change the register value relative
+ * to a scalar it is linked with by id (e.g. a zero-
+ * extending fill of the same spilled stack slot), thus
+ * drop the shared id in that case.
+ */
+ bool no_sext = reg_umax(&regs[value_regno]) <
+ (1ULL << (size * BITS_PER_BYTE - 1));
+
coerce_reg_to_size_sx(&regs[value_regno], size);
+ if (!no_sext)
+ clear_scalar_id(&regs[value_regno]);
+ }
}
return err;
}
@@ -12030,6 +12109,11 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
}
meta->r0_size = reg->var_off.value;
+ if (meta->r0_size > U32_MAX) {
+ verbose(env, "%s rdonly/rdwr_buf_size exceeds u32 max\n",
+ reg_arg_name(env, argno));
+ return -EINVAL;
+ }
if (regno >= 0)
ret = mark_chain_precision(env, regno);
else
@@ -17564,6 +17648,11 @@ static int __add_used_btf(struct bpf_verifier_env *env, struct btf *btf)
if (env->used_btfs[i].btf == btf)
goto ret_put;
+ if (env->signature) {
+ verbose(env, "signed program cannot bind any BTF\n");
+ ret = -EACCES;
+ goto ret_put;
+ }
if (env->used_btf_cnt >= MAX_USED_BTFS) {
verbose(env, "The total number of btfs per program has reached the limit of %u\n",
MAX_USED_BTFS);
@@ -17846,6 +17935,12 @@ static int __add_used_map(struct bpf_verifier_env *env, struct bpf_map *map)
if (env->used_maps[i] == map)
return i;
+ if (env->signature &&
+ env->prog->aux->sig.verdict == BPF_SIG_VERIFIED) {
+ verbose(env, "signed program cannot bind map '%s' not covered by the signature\n",
+ map->name);
+ return -EACCES;
+ }
if (env->used_map_cnt >= MAX_USED_MAPS) {
verbose(env, "The total number of maps per program has reached the limit of %u\n",
MAX_USED_MAPS);
@@ -17898,6 +17993,48 @@ static int add_used_map(struct bpf_verifier_env *env, int fd)
return __add_used_map(env, map);
}
+static int fd_array_get_map_idx_continuous(struct bpf_verifier_env *env, u32 idx)
+{
+ struct bpf_map *map;
+
+ if (idx >= env->fd_array_cnt) {
+ verbose(env, "fd_idx %u out of bounds, fd_array_cnt %u\n",
+ idx, env->fd_array_cnt);
+ return -EINVAL;
+ }
+ map = fd_slot_map(env->fd_array[idx]);
+ if (!map) {
+ verbose(env, "fd_idx %u is not a map\n", idx);
+ return -EINVAL;
+ }
+ return __add_used_map(env, map);
+}
+
+static int fd_array_get_map_idx_sparse(struct bpf_verifier_env *env, u32 idx)
+{
+ int fd;
+
+ if (copy_from_bpfptr_offset(&fd, env->fd_array_raw,
+ (size_t)idx * sizeof(fd), sizeof(fd)))
+ return -EFAULT;
+ return add_used_map(env, fd);
+}
+
+static int fd_array_get_map_idx(struct bpf_verifier_env *env, u32 idx)
+{
+ if (env->fd_array)
+ return fd_array_get_map_idx_continuous(env, idx);
+ if (env->signature) {
+ verbose(env, "signed program must bind maps via a continuous fd_array (fd_array_cnt)\n");
+ return -EACCES;
+ }
+ if (!bpfptr_is_null(env->fd_array_raw))
+ return fd_array_get_map_idx_sparse(env, idx);
+
+ verbose(env, "fd_idx without fd_array is invalid\n");
+ return -EPROTO;
+}
+
static int check_alu_fields(struct bpf_verifier_env *env, struct bpf_insn *insn)
{
u8 class = BPF_CLASS(insn->code);
@@ -18115,7 +18252,6 @@ static int check_and_resolve_insns(struct bpf_verifier_env *env)
struct bpf_map *map;
int map_idx;
u64 addr;
- u32 fd;
if (i == insn_cnt - 1 || insn[1].code != 0 ||
insn[1].dst_reg != 0 || insn[1].src_reg != 0 ||
@@ -18167,21 +18303,17 @@ static int check_and_resolve_insns(struct bpf_verifier_env *env)
switch (insn[0].src_reg) {
case BPF_PSEUDO_MAP_IDX_VALUE:
case BPF_PSEUDO_MAP_IDX:
- if (bpfptr_is_null(env->fd_array)) {
- verbose(env, "fd_idx without fd_array is invalid\n");
- return -EPROTO;
- }
- if (copy_from_bpfptr_offset(&fd, env->fd_array,
- insn[0].imm * sizeof(fd),
- sizeof(fd)))
- return -EFAULT;
+ map_idx = fd_array_get_map_idx(env, insn[0].imm);
break;
default:
- fd = insn[0].imm;
+ if (env->signature) {
+ verbose(env, "signed program cannot reference a map by fd, only via fd_array index\n");
+ return -EINVAL;
+ }
+ map_idx = add_used_map(env, insn[0].imm);
break;
}
- map_idx = add_used_map(env, fd);
if (map_idx < 0)
return map_idx;
map = env->used_maps[map_idx];
@@ -19442,13 +19574,25 @@ int bpf_check_attach_btf_id_multi(struct btf *btf, struct bpf_prog *prog, u32 bt
struct btf *bpf_get_btf_vmlinux(void)
{
- if (!btf_vmlinux && IS_ENABLED(CONFIG_DEBUG_INFO_BTF)) {
- mutex_lock(&bpf_verifier_lock);
- if (!btf_vmlinux)
- btf_vmlinux = btf_parse_vmlinux();
- mutex_unlock(&bpf_verifier_lock);
+ /* Pairs with the smp_store_release() on the parse path below. */
+ struct btf *btf = smp_load_acquire(&btf_vmlinux);
+
+ if (!btf && IS_ENABLED(CONFIG_DEBUG_INFO_BTF)) {
+ mutex_lock(&btf_vmlinux_lock);
+ btf = btf_vmlinux;
+ if (!btf) {
+ btf = btf_parse_vmlinux();
+ /*
+ * Order the parsed BTF contents and the globals the
+ * parse populated (e.g. bpf_ctx_convert.t) before
+ * the pointer publication. Pairs with the acquire
+ * on the lockless fast path above.
+ */
+ smp_store_release(&btf_vmlinux, btf);
+ }
+ mutex_unlock(&btf_vmlinux_lock);
}
- return btf_vmlinux;
+ return btf;
}
/*
@@ -19456,7 +19600,7 @@ struct btf *bpf_get_btf_vmlinux(void)
* this case expect that every file descriptor in the array is either a map or
* a BTF. Everything else is considered to be trash.
*/
-static int add_fd_from_fd_array(struct bpf_verifier_env *env, int fd)
+static int add_fd_from_fd_array(struct bpf_verifier_env *env, u32 idx, int fd)
{
struct bpf_map *map;
struct btf *btf;
@@ -19468,51 +19612,83 @@ static int add_fd_from_fd_array(struct bpf_verifier_env *env, int fd)
err = __add_used_map(env, map);
if (err < 0)
return err;
+ fd_slot_set_map(&env->fd_array[idx], map);
return 0;
}
btf = __btf_get_by_fd(f);
if (!IS_ERR(btf)) {
btf_get(btf);
- return __add_used_btf(env, btf);
+ err = __add_used_btf(env, btf);
+ if (err < 0)
+ return err;
+ fd_slot_set_btf(&env->fd_array[idx], btf);
+ return 0;
}
verbose(env, "fd %d is not pointing to valid bpf_map or btf\n", fd);
return PTR_ERR(map);
}
-static int process_fd_array(struct bpf_verifier_env *env, union bpf_attr *attr, bpfptr_t uattr)
+/*
+ * A continuous fd_array is resolved into an in-memory cache with one slot
+ * per entry. The bound here is deliberately generous and not derived from
+ * the per-program object limits: Duplicate entries /are/ permitted, and
+ * the number of distinct maps and BTFs a program can bind is enforced when
+ * each entry is resolved by __add_used_map() and __add_used_btf().
+ */
+#define MAX_FD_ARRAY_CNT 4096
+
+static int process_fd_array_continuous(struct bpf_verifier_env *env,
+ bpfptr_t fd_array, u32 cnt)
{
- size_t size = sizeof(int);
- int ret;
- int fd;
+ int fd, ret;
u32 i;
- env->fd_array = make_bpfptr(attr->fd_array, uattr.is_kernel);
-
- /*
- * The only difference between old (no fd_array_cnt is given) and new
- * APIs is that in the latter case the fd_array is expected to be
- * continuous and is scanned for map fds right away
- */
- if (!attr->fd_array_cnt)
- return 0;
-
- /* Check for integer overflow */
- if (attr->fd_array_cnt >= (U32_MAX / size)) {
- verbose(env, "fd_array_cnt is too big (%u)\n", attr->fd_array_cnt);
- return -EINVAL;
+ if (cnt > MAX_FD_ARRAY_CNT) {
+ verbose(env, "fd_array has too many entries (%u, max %u)\n",
+ cnt, MAX_FD_ARRAY_CNT);
+ return -E2BIG;
}
- for (i = 0; i < attr->fd_array_cnt; i++) {
- if (copy_from_bpfptr_offset(&fd, env->fd_array, i * size, size))
+ env->fd_array = kvcalloc(cnt, sizeof(*env->fd_array),
+ GFP_KERNEL_ACCOUNT);
+ if (!env->fd_array)
+ return -ENOMEM;
+ env->fd_array_cnt = cnt;
+ for (i = 0; i < cnt; i++) {
+ if (copy_from_bpfptr_offset(&fd, fd_array,
+ (size_t)i * sizeof(fd), sizeof(fd)))
return -EFAULT;
-
- ret = add_fd_from_fd_array(env, fd);
+ ret = add_fd_from_fd_array(env, i, fd);
if (ret)
return ret;
}
+ return 0;
+}
+static int process_fd_array(struct bpf_verifier_env *env,
+ union bpf_attr *attr, bpfptr_t uattr)
+{
+ bpfptr_t fd_array = make_bpfptr(attr->fd_array, uattr.is_kernel);
+
+ if (bpfptr_is_null(fd_array)) {
+ if (attr->fd_array_cnt) {
+ verbose(env, "fd_array_cnt %u without fd_array is invalid\n",
+ attr->fd_array_cnt);
+ return -EINVAL;
+ }
+ return 0;
+ }
+ /*
+ * New API: the caller passes fd_array_cnt and a continuous array that
+ * is resolved and bound up front. Legacy API (no fd_array_cnt): keep
+ * the caller's array and resolve entries on the spot at each reference.
+ */
+ if (attr->fd_array_cnt)
+ return process_fd_array_continuous(env, fd_array,
+ attr->fd_array_cnt);
+ env->fd_array_raw = fd_array;
return 0;
}
@@ -19727,6 +19903,146 @@ int bpf_fixup_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
return 0;
}
+static enum bpf_sig_keyring bpf_classify_keyring(s32 keyring_id)
+{
+ switch (keyring_id) {
+ case 0:
+ return BPF_SIG_KEYRING_BUILTIN;
+ case (s32)(unsigned long)VERIFY_USE_SECONDARY_KEYRING:
+ return BPF_SIG_KEYRING_SECONDARY;
+ case (s32)(unsigned long)VERIFY_USE_PLATFORM_KEYRING:
+ return BPF_SIG_KEYRING_PLATFORM;
+ default:
+ return BPF_SIG_KEYRING_USER;
+ }
+}
+
+/*
+ * Verify the PKCS#7 signature of a loaded program. Called from bpf_check()
+ * once the program's metadata maps have been resolved into used_maps, so
+ * the exact maps folded into the signature are the ones the program binds.
+ *
+ * The signature covers the instructions followed by the frozen contents of
+ * each map, in @maps order: insns || map_0 || map_1 || [...]. On success the
+ * verdict and keyring info are recorded on prog->aux.
+ */
+static int bpf_prog_verify_signature(struct bpf_verifier_env *env,
+ union bpf_attr *attr, bool is_kernel)
+{
+ bpfptr_t usig = make_bpfptr(attr->signature, is_kernel);
+ struct bpf_dynptr_kern sig_ptr, data_ptr;
+ struct bpf_prog *prog = env->prog;
+ struct bpf_map **maps = env->used_maps;
+ struct bpf_key *key = NULL;
+ void *sig, *data = NULL;
+ u32 map_cnt = env->used_map_cnt;
+ u32 i, off, insns_sz;
+ u64 data_sz;
+ int err = 0;
+
+ /*
+ * Don't attempt to use kmalloc_large or vmalloc for signatures.
+ * Practical signature for BPF program should be below this limit.
+ */
+ if (!attr->signature_size ||
+ attr->signature_size > KMALLOC_MAX_CACHE_SIZE)
+ return -EINVAL;
+ if (system_keyring_id_check(attr->keyring_id) == 0)
+ key = bpf_lookup_system_key(attr->keyring_id);
+ else
+ key = bpf_lookup_user_key(attr->keyring_id, 0);
+ if (!key) {
+ verbose(env, "cannot resolve signing keyring with keyring_id %d\n",
+ attr->keyring_id);
+ return -EINVAL;
+ }
+
+ sig = kvmemdup_bpfptr(usig, attr->signature_size);
+ if (IS_ERR(sig)) {
+ bpf_key_put(key);
+ return PTR_ERR(sig);
+ }
+
+ insns_sz = prog->len * sizeof(struct bpf_insn);
+ data_sz = insns_sz;
+ for (i = 0; i < map_cnt; i++) {
+ struct bpf_map *map = maps[i];
+
+ if (map->map_type != BPF_MAP_TYPE_ARRAY ||
+ !map->ops->map_direct_value_addr) {
+ verbose(env, "signed program metadata map '%s' must be an array\n",
+ map->name);
+ err = -EINVAL;
+ goto out;
+ }
+ if (!READ_ONCE(map->frozen)) {
+ verbose(env, "signed program metadata map '%s' must be frozen\n",
+ map->name);
+ err = -EPERM;
+ goto out;
+ }
+ if (bpf_map_write_active(map)) {
+ verbose(env, "signed program metadata map '%s' has active writers\n",
+ map->name);
+ err = -EBUSY;
+ goto out;
+ }
+ if (!map->excl_prog_sha) {
+ verbose(env, "signed program metadata map '%s' must be exclusive\n",
+ map->name);
+ err = -EPERM;
+ goto out;
+ }
+ data_sz += map->value_size;
+ }
+ if (bpf_dynptr_check_size(data_sz)) {
+ verbose(env, "signed payload too large: %llu bytes\n", data_sz);
+ err = -E2BIG;
+ goto out;
+ }
+ data = kvmalloc(data_sz, GFP_KERNEL_ACCOUNT | __GFP_ZERO);
+ if (!data) {
+ err = -ENOMEM;
+ goto out;
+ }
+ memcpy(data, prog->insnsi, insns_sz);
+ off = insns_sz;
+ for (i = 0; i < map_cnt; i++) {
+ struct bpf_map *map = maps[i];
+ u64 addr;
+
+ err = map->ops->map_direct_value_addr(map, &addr, 0);
+ if (err) {
+ verbose(env, "failed to read signed metadata map '%s': %d\n",
+ map->name, err);
+ goto out;
+ }
+ memcpy(data + off, (void *)(unsigned long)addr,
+ map->value_size);
+ off += map->value_size;
+ }
+
+ bpf_dynptr_init(&data_ptr, data, BPF_DYNPTR_TYPE_LOCAL, 0, data_sz);
+ bpf_dynptr_init(&sig_ptr, sig, BPF_DYNPTR_TYPE_LOCAL, 0,
+ attr->signature_size);
+
+ err = bpf_verify_pkcs7_signature((struct bpf_dynptr *)&data_ptr,
+ (struct bpf_dynptr *)&sig_ptr, key);
+ if (err) {
+ verbose(env, "signature verification failed: %d\n", err);
+ } else {
+ verbose(env, "signature verification passed\n");
+ prog->aux->sig.keyring_serial = bpf_key_serial(key);
+ prog->aux->sig.keyring_type = bpf_classify_keyring(attr->keyring_id);
+ prog->aux->sig.verdict = BPF_SIG_VERIFIED;
+ }
+out:
+ kvfree(data);
+ bpf_key_put(key);
+ kvfree(sig);
+ return err;
+}
+
int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr,
struct bpf_log_attr *attr_log)
{
@@ -19749,18 +20065,6 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr,
return -ENOMEM;
env->bt.env = env;
-
- len = (*prog)->len;
- env->insn_aux_data =
- vzalloc(array_size(sizeof(struct bpf_insn_aux_data), len));
- ret = -ENOMEM;
- if (!env->insn_aux_data)
- goto err_free_env;
- for (i = 0; i < len; i++)
- env->insn_aux_data[i].orig_idx = i;
- env->succ = bpf_iarray_realloc(NULL, 2);
- if (!env->succ)
- goto err_free_env;
env->prog = *prog;
env->ops = bpf_verifier_ops[env->prog->type];
@@ -19769,22 +20073,52 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr,
env->bypass_spec_v1 = bpf_bypass_spec_v1(env->prog->aux->token);
env->bypass_spec_v4 = bpf_bypass_spec_v4(env->prog->aux->token);
env->bpf_capable = is_priv = bpf_token_capable(env->prog->aux->token, CAP_BPF);
-
- bpf_get_btf_vmlinux();
-
- /* grab the mutex to protect few globals used by verifier */
- if (!is_priv)
- mutex_lock(&bpf_verifier_lock);
+ env->signature = attr->signature;
/* user could have requested verbose verifier output
* and supplied buffer to store the verification trace
*/
ret = bpf_vlog_init(&env->log, attr_log->level, attr_log->ubuf, attr_log->size);
if (ret)
- goto err_unlock;
+ goto err_free_env;
+ if (env->signature) {
+ ret = bpf_prog_calc_tag(env->prog);
+ if (ret < 0)
+ goto err_prep;
+ }
ret = process_fd_array(env, attr, uattr);
if (ret)
+ goto err_prep;
+
+ if (env->signature) {
+ ret = bpf_prog_verify_signature(env, attr, uattr.is_kernel);
+ if (ret)
+ goto err_prep;
+ }
+
+ ret = security_bpf_prog_load(env->prog, attr, env->prog->aux->token,
+ uattr.is_kernel);
+ if (ret)
+ goto err_prep;
+
+ bpf_get_btf_vmlinux();
+
+ /* Serialize verification of unprivileged programs. */
+ if (!is_priv)
+ mutex_lock(&bpf_verifier_lock);
+
+ len = env->prog->len;
+ env->insn_aux_data =
+ __vmalloc(array_size(sizeof(struct bpf_insn_aux_data), len),
+ GFP_KERNEL_ACCOUNT | __GFP_ZERO);
+ ret = -ENOMEM;
+ if (!env->insn_aux_data)
+ goto skip_full_check;
+ for (i = 0; i < len; i++)
+ env->insn_aux_data[i].orig_idx = i;
+ env->succ = bpf_iarray_realloc(NULL, 2);
+ if (!env->succ)
goto skip_full_check;
mark_verifier_state_clean(env);
@@ -20008,17 +20342,26 @@ err_release_maps:
*prog = env->prog;
module_put(env->attach_btf_mod);
-err_unlock:
if (!is_priv)
mutex_unlock(&bpf_verifier_lock);
- bpf_clear_insn_aux_data(env, 0, env->prog->len);
+ goto err_free_env;
+err_prep:
+ err = bpf_log_attr_finalize(attr_log, &env->log);
+ if (err)
+ ret = err;
+ release_insn_arrays(env);
+ release_maps(env);
+ release_btfs(env);
err_free_env:
+ if (env->insn_aux_data)
+ bpf_clear_insn_aux_data(env, 0, env->prog->len);
+ vfree(env->insn_aux_data);
+ kvfree(env->fd_array);
bpf_stack_liveness_free(env);
kvfree(env->cfg.insn_postorder);
kvfree(env->scc_info);
kvfree(env->succ);
kvfree(env->gotox_tmp_buf);
- vfree(env->insn_aux_data);
kvfree(env);
return ret;
}
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 427b0595cd78..51255b670a38 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -7150,6 +7150,8 @@ static int map_range(struct perf_buffer *rb, struct vm_area_struct *vma)
int err = 0;
unsigned long pagenum;
+ guard(mutex)(&rb->aux_mutex);
+
/*
* We map this as a VM_PFNMAP VMA.
*
diff --git a/kernel/module/dups.c b/kernel/module/dups.c
index 1d720a5311ba..8b6f8f177de4 100644
--- a/kernel/module/dups.c
+++ b/kernel/module/dups.c
@@ -129,7 +129,7 @@ bool kmod_dup_request_exists_wait(char *module_name, bool wait, int *dup_ret)
if (!new_kmod_req)
return false;
- memcpy(new_kmod_req->name, module_name, strlen(module_name));
+ strscpy(new_kmod_req->name, module_name);
INIT_WORK(&new_kmod_req->complete_work, kmod_dup_request_complete);
INIT_DELAYED_WORK(&new_kmod_req->delete_work, kmod_dup_request_delete);
init_completion(&new_kmod_req->first_req_done);
diff --git a/kernel/module/main.c b/kernel/module/main.c
index 46dd8d25a605..528690ba160b 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -1458,7 +1458,6 @@ static void free_module(struct module *mod)
/* This may be empty, but that's OK */
module_arch_freeing_init(mod);
- kfree(mod->args);
percpu_modfree(mod);
free_mod_mem(mod);
@@ -3425,7 +3424,7 @@ static int load_module(struct load_info *info, const char __user *uargs,
struct module *mod;
bool module_allocated = false;
long err = 0;
- char *after_dashes;
+ char *args = NULL, *after_dashes;
/*
* Do the signature check (if any) first. All that
@@ -3523,9 +3522,9 @@ static int load_module(struct load_info *info, const char __user *uargs,
flush_module_icache(mod);
/* Now copy in args */
- mod->args = strndup_user(uargs, ~0UL >> 1);
- if (IS_ERR(mod->args)) {
- err = PTR_ERR(mod->args);
+ args = strndup_user(uargs, ~0UL >> 1);
+ if (IS_ERR(args)) {
+ err = PTR_ERR(args);
goto free_arch_cleanup;
}
@@ -3546,7 +3545,7 @@ static int load_module(struct load_info *info, const char __user *uargs,
mod->async_probe_requested = async_probe;
/* Module is ready to execute: parsing args may do that. */
- after_dashes = parse_args(mod->name, mod->args, mod->kp, mod->num_kp,
+ after_dashes = parse_args(mod->name, args, mod->kp, mod->num_kp,
-32768, 32767, mod,
unknown_module_param_cb);
if (IS_ERR(after_dashes)) {
@@ -3556,6 +3555,8 @@ static int load_module(struct load_info *info, const char __user *uargs,
pr_warn("%s: parameters '%s' after `--' ignored\n",
mod->name, after_dashes);
}
+ kfree(args);
+ args = NULL;
/* Link in to sysfs. */
err = mod_sysfs_setup(mod, info, mod->kp, mod->num_kp);
@@ -3597,7 +3598,7 @@ static int load_module(struct load_info *info, const char __user *uargs,
ddebug_cleanup:
ftrace_release_mod(mod);
synchronize_rcu();
- kfree(mod->args);
+ kfree(args);
free_arch_cleanup:
module_arch_cleanup(mod);
free_modinfo:
diff --git a/kernel/module/procfs.c b/kernel/module/procfs.c
index 0a4841e88adb..90712aa9dd13 100644
--- a/kernel/module/procfs.c
+++ b/kernel/module/procfs.c
@@ -64,7 +64,7 @@ static void m_stop(struct seq_file *m, void *p)
static unsigned int module_total_size(struct module *mod)
{
- int size = 0;
+ unsigned int size = 0;
for_each_mod_mem_type(type)
size += mod->mem[type].size;
diff --git a/kernel/module/stats.c b/kernel/module/stats.c
index 3a9672f93a8e..78b59bc05387 100644
--- a/kernel/module/stats.c
+++ b/kernel/module/stats.c
@@ -253,7 +253,7 @@ int try_add_failed_module(const char *name, enum fail_dup_mod_reason reason)
mod_fail = kzalloc_obj(*mod_fail);
if (!mod_fail)
return -ENOMEM;
- memcpy(mod_fail->name, name, strlen(name));
+ strscpy(mod_fail->name, name);
__set_bit(reason, &mod_fail->dup_fail_mask);
atomic_long_inc(&mod_fail->count);
list_add_rcu(&mod_fail->list, &dup_failed_modules);
diff --git a/kernel/panic.c b/kernel/panic.c
index 53386f9c0f98..90e21f15fd7e 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -396,13 +396,16 @@ static bool panic_try_force_cpu(const char *fmt, va_list args)
return false;
}
- /* Bail only if a different CPU is already handling it. */
- if (panic_in_progress() && atomic_read(&panic_cpu) != this_cpu)
+ /* Another panic already in progress */
+ if (panic_in_progress())
return false;
- /* Which CPU won the race? */
+ /*
+ * Only one CPU can do the redirect. Use atomic cmpxchg to ensure
+ * we don't race with another CPU also trying to redirect.
+ */
if (!atomic_try_cmpxchg(&panic_redirect_cpu, &old_cpu, this_cpu))
- return old_cpu != this_cpu;
+ return false;
/*
* Use dynamically allocated buffer if available, otherwise
@@ -440,9 +443,6 @@ static bool panic_try_force_cpu(const char *fmt, va_list args)
return false;
}
- /* Hand panic_cpu to the target so it wins its own panic_try_start. */
- atomic_set(&panic_cpu, panic_force_cpu);
-
/* IPI/NMI sent, this CPU should stop */
return true;
}
diff --git a/kernel/params.c b/kernel/params.c
index 5c8a05921e28..d3a4ecab4f27 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -538,7 +538,7 @@ const struct kernel_param_ops param_ops_string = {
};
EXPORT_SYMBOL(param_ops_string);
-/* sysfs output in /sys/modules/XYZ/parameters/ */
+/* sysfs output in /sys/module/XYZ/parameters/ */
#define to_module_attr(n) container_of_const(n, struct module_attribute, attr)
#define to_module_kobject(n) container_of(n, struct module_kobject, kobj)
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 2fe9a963c823..6d363e42e2a0 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -3264,10 +3264,8 @@ static bool console_flush_one_record(bool do_cond_resched, u64 *next_seq, bool *
if (flags & CON_NBCON) {
progress = nbcon_legacy_emit_next_record(con, handover, cookie,
!do_cond_resched);
- printk_seq = nbcon_seq_read(con);
} else {
progress = console_emit_next_record(con, handover, cookie);
- printk_seq = con->seq;
}
/*
@@ -3277,6 +3275,15 @@ static bool console_flush_one_record(bool do_cond_resched, u64 *next_seq, bool *
if (*handover)
goto fail;
+ /*
+ * @con can be used here now that it is certain that this
+ * context is still holding the SRCU read lock.
+ */
+ if (flags & CON_NBCON)
+ printk_seq = nbcon_seq_read(con);
+ else
+ printk_seq = con->seq;
+
/* Track the next of the highest seq flushed. */
if (printk_seq > *next_seq)
*next_seq = printk_seq;
diff --git a/kernel/sched/ext/cid.c b/kernel/sched/ext/cid.c
index af83084ec740..f31113b080e9 100644
--- a/kernel/sched/ext/cid.c
+++ b/kernel/sched/ext/cid.c
@@ -395,17 +395,15 @@ __bpf_kfunc s32 scx_bpf_cpu_to_cid(s32 cpu, const struct bpf_prog_aux *aux)
* bits outside stay untouched. In particular, scx_cmask_copy() does NOT zero
* @dst bits that lie outside @src's range.
*
- * The _RACY variants are otherwise identical to their non-racy counterpart but
- * read @src word-by-word via data_race(). Memory ordering with concurrent
- * writers is the caller's responsibility.
+ * Word accesses use READ_ONCE/WRITE_ONCE so a caller may read @src
+ * locklessly. Memory ordering against concurrent writers is the caller's
+ * responsibility.
*/
enum cmask_op2 {
/* mutating */
CMASK_OP2_AND,
CMASK_OP2_OR,
- CMASK_OP2_OR_RACY,
CMASK_OP2_COPY,
- CMASK_OP2_COPY_RACY,
CMASK_OP2_ANDNOT,
/* predicates - short-circuit when the per-word result is true */
CMASK_OP2_SUBSET,
@@ -422,28 +420,22 @@ static __always_inline bool cmask_word_op2(u64 *av, const u64 *bp, u64 mask,
{
switch (op) {
case CMASK_OP2_AND:
- *av &= ~mask | *bp;
+ WRITE_ONCE(*av, *av & (~mask | READ_ONCE(*bp)));
return false;
case CMASK_OP2_OR:
- *av |= *bp & mask;
- return false;
- case CMASK_OP2_OR_RACY:
- *av |= data_race(*bp) & mask;
+ WRITE_ONCE(*av, *av | (READ_ONCE(*bp) & mask));
return false;
case CMASK_OP2_COPY:
- *av = (*av & ~mask) | (*bp & mask);
- return false;
- case CMASK_OP2_COPY_RACY:
- *av = (*av & ~mask) | (data_race(*bp) & mask);
+ WRITE_ONCE(*av, (*av & ~mask) | (READ_ONCE(*bp) & mask));
return false;
case CMASK_OP2_ANDNOT:
- *av &= ~(*bp & mask);
+ WRITE_ONCE(*av, *av & ~(READ_ONCE(*bp) & mask));
return false;
case CMASK_OP2_SUBSET:
/* stop on the first bit in @sub not set in @super */
- return (*bp & ~*av) & mask;
+ return (READ_ONCE(*bp) & ~READ_ONCE(*av)) & mask;
case CMASK_OP2_INTERSECTS:
- return (*av & *bp) & mask;
+ return (READ_ONCE(*av) & READ_ONCE(*bp)) & mask;
}
unreachable();
}
@@ -504,7 +496,7 @@ static __always_inline bool cmask_word_op1(const u64 *ap, u64 mask,
{
switch (op) {
case CMASK_OP1_ANY_SET:
- return *ap & mask;
+ return READ_ONCE(*ap) & mask;
}
unreachable();
}
@@ -556,39 +548,12 @@ void scx_cmask_or(struct scx_cmask *dst, const struct scx_cmask *src)
src->bits, src->base, src->nr_cids, CMASK_OP2_OR);
}
-/**
- * scx_cmask_or_racy - OR @src into @dst, reading @src without locking
- *
- * @src is read word-by-word through data_race(). Same per-bit independence
- * rationale as scx_cmask_copy_racy(). Memory ordering with writers is the
- * caller's responsibility.
- */
-void scx_cmask_or_racy(struct scx_cmask *dst, const struct scx_cmask *src)
-{
- cmask_walk_op2(dst->bits, dst->base, dst->nr_cids,
- src->bits, src->base, src->nr_cids, CMASK_OP2_OR_RACY);
-}
-
void scx_cmask_copy(struct scx_cmask *dst, const struct scx_cmask *src)
{
cmask_walk_op2(dst->bits, dst->base, dst->nr_cids,
src->bits, src->base, src->nr_cids, CMASK_OP2_COPY);
}
-/**
- * scx_cmask_copy_racy - Snapshot @src into @dst without locking
- *
- * @src is read word-by-word through data_race(). Head/tail masking matches
- * scx_cmask_copy(). Each bit in a cmask is independent, so partial updates
- * just leave some bits fresher than others. Memory ordering with writers is
- * the caller's responsibility.
- */
-void scx_cmask_copy_racy(struct scx_cmask *dst, const struct scx_cmask *src)
-{
- cmask_walk_op2(dst->bits, dst->base, dst->nr_cids,
- src->bits, src->base, src->nr_cids, CMASK_OP2_COPY_RACY);
-}
-
void scx_cmask_andnot(struct scx_cmask *dst, const struct scx_cmask *src)
{
cmask_walk_op2(dst->bits, dst->base, dst->nr_cids,
diff --git a/kernel/sched/ext/cid.h b/kernel/sched/ext/cid.h
index 9c4f4b907f12..54b10df32fd5 100644
--- a/kernel/sched/ext/cid.h
+++ b/kernel/sched/ext/cid.h
@@ -57,9 +57,7 @@ void scx_cmask_clear(struct scx_cmask *m);
void scx_cmask_fill(struct scx_cmask *m);
void scx_cmask_and(struct scx_cmask *dst, const struct scx_cmask *src);
void scx_cmask_or(struct scx_cmask *dst, const struct scx_cmask *src);
-void scx_cmask_or_racy(struct scx_cmask *dst, const struct scx_cmask *src);
void scx_cmask_copy(struct scx_cmask *dst, const struct scx_cmask *src);
-void scx_cmask_copy_racy(struct scx_cmask *dst, const struct scx_cmask *src);
void scx_cmask_andnot(struct scx_cmask *dst, const struct scx_cmask *src);
bool scx_cmask_subset(const struct scx_cmask *sub, const struct scx_cmask *super);
bool scx_cmask_intersects(const struct scx_cmask *a, const struct scx_cmask *b);
diff --git a/kernel/sched/ext/ext.c b/kernel/sched/ext/ext.c
index 1a0ec985da77..5241b55a58ec 100644
--- a/kernel/sched/ext/ext.c
+++ b/kernel/sched/ext/ext.c
@@ -389,6 +389,18 @@ static bool rq_is_open(struct rq *rq, u64 enq_flags)
*/
DEFINE_PER_CPU(struct rq *, scx_locked_rq_state);
+static void switch_rq_lock(struct rq *from, struct rq *to)
+{
+ bool tracked = scx_locked_rq() == from;
+
+ if (tracked)
+ update_locked_rq(NULL);
+ raw_spin_rq_unlock(from);
+ raw_spin_rq_lock(to);
+ if (tracked)
+ update_locked_rq(to);
+}
+
/*
* Flipped on enable per sch->is_cid_type. Declared in internal.h so
* subsystem inlines can read it.
@@ -410,11 +422,6 @@ static inline void scx_call_op_set_cpumask(struct scx_sched *sch, struct rq *rq,
struct task_struct *task,
const struct cpumask *cpumask)
{
- WARN_ON_ONCE(current->scx.kf_tasks[0]);
- current->scx.kf_tasks[0] = task;
- if (rq)
- update_locked_rq(rq);
-
if (scx_is_cid_type()) {
struct scx_cmask *kern_va = *this_cpu_ptr(sch->set_cmask_scratch);
/*
@@ -423,14 +430,11 @@ static inline void scx_call_op_set_cpumask(struct scx_sched *sch, struct rq *rq,
* the sole user of the scratch area.
*/
scx_cpumask_to_cmask(cpumask, kern_va);
- sch->ops_cid.set_cmask(task, scx_kaddr_to_arena(sch, kern_va));
+ SCX_CALL_CID_OP_TASK(sch, set_cmask, rq, task,
+ scx_kaddr_to_arena(sch, kern_va));
} else {
- sch->ops.set_cpumask(task, cpumask);
+ SCX_CALL_OP_TASK(sch, set_cpumask, rq, task, cpumask);
}
-
- if (rq)
- update_locked_rq(NULL);
- current->scx.kf_tasks[0] = NULL;
}
enum scx_dsq_iter_flags {
@@ -1832,7 +1836,7 @@ static void enqueue_task_scx(struct rq *rq, struct task_struct *p, int core_enq_
{
struct scx_sched *sch = scx_task_sched(p);
int sticky_cpu = p->scx.sticky_cpu;
- u64 enq_flags = core_enq_flags | rq->scx.extra_enq_flags;
+ u64 enq_flags = core_enq_flags | rq->scx.remote_activate_enq_flags;
if (enq_flags & ENQUEUE_WAKEUP)
rq->scx.flags |= SCX_RQ_IN_WAKEUP;
@@ -2099,19 +2103,18 @@ static void move_remote_task_to_local_dsq(struct task_struct *p, u64 enq_flags,
deactivate_task(src_rq, p, 0);
set_task_cpu(p, cpu_of(dst_rq));
- raw_spin_rq_unlock(src_rq);
- raw_spin_rq_lock(dst_rq);
+ switch_rq_lock(src_rq, dst_rq);
/*
* We want to pass scx-specific enq_flags but activate_task() will
* truncate the upper 32 bit. As we own @rq, we can pass them through
- * @rq->scx.extra_enq_flags instead.
+ * @rq->scx.remote_activate_enq_flags instead.
*/
WARN_ON_ONCE(!cpumask_test_cpu(cpu_of(dst_rq), p->cpus_ptr));
- WARN_ON_ONCE(dst_rq->scx.extra_enq_flags);
- dst_rq->scx.extra_enq_flags = enq_flags;
+ WARN_ON_ONCE(dst_rq->scx.remote_activate_enq_flags);
+ dst_rq->scx.remote_activate_enq_flags = enq_flags;
activate_task(dst_rq, p, 0);
- dst_rq->scx.extra_enq_flags = 0;
+ dst_rq->scx.remote_activate_enq_flags = 0;
}
/*
@@ -2192,13 +2195,14 @@ static bool task_can_run_on_remote_rq(struct scx_sched *sch,
}
/**
- * unlink_dsq_and_lock_src_rq() - Unlink task from its DSQ and lock its task_rq
+ * unlink_dsq_and_switch_rq_lock() - Unlink task and switch to its rq lock
* @p: target task
* @dsq: locked DSQ @p is currently on
+ * @locked_rq: currently locked rq
* @src_rq: rq @p is currently on, stable with @dsq locked
*
- * Called with @dsq locked but no rq's locked. We want to move @p to a different
- * DSQ, including any local DSQ, but are not locking @src_rq. Locking @src_rq is
+ * Called with @dsq and @locked_rq locked. We want to move @p to a different DSQ,
+ * including any local DSQ, but are not locking @src_rq. Locking @src_rq is
* required when transferring into a local DSQ. Even when transferring into a
* non-local DSQ, it's better to use the same mechanism to protect against
* dequeues and maintain the invariant that @p->scx.dsq can only change while
@@ -2220,20 +2224,22 @@ static bool task_can_run_on_remote_rq(struct scx_sched *sch,
* On return, @dsq is unlocked and @src_rq is locked. Returns %true if @p is
* still valid. %false if lost to dequeue.
*/
-static bool unlink_dsq_and_lock_src_rq(struct task_struct *p,
- struct scx_dispatch_q *dsq,
- struct rq *src_rq)
+static bool unlink_dsq_and_switch_rq_lock(struct task_struct *p,
+ struct scx_dispatch_q *dsq,
+ struct rq *locked_rq,
+ struct rq *src_rq)
{
s32 cpu = raw_smp_processor_id();
lockdep_assert_held(&dsq->lock);
+ lockdep_assert_rq_held(locked_rq);
WARN_ON_ONCE(p->scx.holding_cpu >= 0);
task_unlink_from_dsq(p, dsq);
p->scx.holding_cpu = cpu;
raw_spin_unlock(&dsq->lock);
- raw_spin_rq_lock(src_rq);
+ switch_rq_lock(locked_rq, src_rq);
/* task_rq couldn't have changed if we're still the holding cpu */
return likely(p->scx.holding_cpu == cpu) &&
@@ -2244,14 +2250,11 @@ static bool consume_remote_task(struct rq *this_rq,
struct task_struct *p, u64 enq_flags,
struct scx_dispatch_q *dsq, struct rq *src_rq)
{
- raw_spin_rq_unlock(this_rq);
-
- if (unlink_dsq_and_lock_src_rq(p, dsq, src_rq)) {
+ if (unlink_dsq_and_switch_rq_lock(p, dsq, this_rq, src_rq)) {
move_remote_task_to_local_dsq(p, enq_flags, src_rq, this_rq);
return true;
} else {
- raw_spin_rq_unlock(src_rq);
- raw_spin_rq_lock(this_rq);
+ switch_rq_lock(src_rq, this_rq);
return false;
}
}
@@ -2424,7 +2427,7 @@ static void dispatch_to_local_dsq(struct scx_sched *sch, struct rq *rq,
* As DISPATCHING guarantees that @p is wholly ours, we can pretend that
* we're moving from a DSQ and use the same mechanism - mark the task
* under transfer with holding_cpu, release DISPATCHING and then follow
- * the same protocol. See unlink_dsq_and_lock_src_rq().
+ * the same protocol. See unlink_dsq_and_switch_rq_lock().
*/
p->scx.holding_cpu = raw_smp_processor_id();
@@ -2433,9 +2436,8 @@ static void dispatch_to_local_dsq(struct scx_sched *sch, struct rq *rq,
/* switch to @src_rq lock */
if (locked_rq != src_rq) {
- raw_spin_rq_unlock(locked_rq);
+ switch_rq_lock(locked_rq, src_rq);
locked_rq = src_rq;
- raw_spin_rq_lock(src_rq);
}
/* task_rq couldn't have changed if we're still the holding cpu */
@@ -2469,10 +2471,8 @@ static void dispatch_to_local_dsq(struct scx_sched *sch, struct rq *rq,
}
/* switch back to @rq lock */
- if (locked_rq != rq) {
- raw_spin_rq_unlock(locked_rq);
- raw_spin_rq_lock(rq);
- }
+ if (locked_rq != rq)
+ switch_rq_lock(locked_rq, rq);
}
/**
@@ -2694,24 +2694,38 @@ static void set_next_task_scx(struct rq *rq, struct task_struct *p, bool first)
/*
* @p is getting newly scheduled or got kicked after someone updated its
- * slice. Refresh whether tick can be stopped. See scx_can_stop_tick().
+ * slice. Update SCX_RQ_CAN_STOP_TICK to reflect whether the tick can be
+ * stopped. See scx_can_stop_tick().
+ *
+ * Moreover, refresh the load_avgs just when transitioning in and out of
+ * nohz. In the future, we might want to add a mechanism to update
+ * load_avgs periodically on tick-stopped CPUs.
*/
- if ((p->scx.slice == SCX_SLICE_INF) !=
- (bool)(rq->scx.flags & SCX_RQ_CAN_STOP_TICK)) {
- if (p->scx.slice == SCX_SLICE_INF)
+ if (p->scx.slice == SCX_SLICE_INF) {
+ if (!(rq->scx.flags & SCX_RQ_CAN_STOP_TICK)) {
+ /*
+ * Bypass mode always assigns finite slices, so @p
+ * can't have an infinite slice while bypassing.
+ * Therefore, sched_update_tick_dependency() can safely
+ * evaluate the outgoing task.
+ */
rq->scx.flags |= SCX_RQ_CAN_STOP_TICK;
- else
- rq->scx.flags &= ~SCX_RQ_CAN_STOP_TICK;
+ sched_update_tick_dependency(rq);
- sched_update_tick_dependency(rq);
+ update_other_load_avgs(rq);
+ }
+ } else {
+ if (rq->scx.flags & SCX_RQ_CAN_STOP_TICK) {
+ rq->scx.flags &= ~SCX_RQ_CAN_STOP_TICK;
+ update_other_load_avgs(rq);
+ }
/*
- * For now, let's refresh the load_avgs just when transitioning
- * in and out of nohz. In the future, we might want to add a
- * mechanism which calls the following periodically on
- * tick-stopped CPUs.
+ * @rq still references the outgoing scheduling context. A finite
+ * slice is sufficient by itself to require the tick.
*/
- update_other_load_avgs(rq);
+ if (tick_nohz_full_cpu(cpu_of(rq)))
+ tick_nohz_dep_set_cpu(cpu_of(rq), TICK_DEP_BIT_SCHED);
}
}
@@ -4035,6 +4049,15 @@ bool scx_can_stop_tick(struct rq *rq)
if (p->sched_class != &ext_sched_class)
return true;
+ /*
+ * @rq->curr may still reference an outgoing EXT task after it has been
+ * dequeued. If no EXT tasks are accounted on @rq, ignore its stale
+ * slice state. If another task is dispatched from a DSQ,
+ * set_next_task_scx() will update the dependency for the incoming task.
+ */
+ if (!rq->scx.nr_running)
+ return true;
+
if (scx_bypassing(sch, cpu_of(rq)))
return false;
@@ -6363,11 +6386,6 @@ struct scx_sched *scx_alloc_and_add_sched(struct scx_enable_cmd *cmd,
sch->ops = *cmd->ops;
}
- rcu_assign_pointer(ops->priv, sch);
-
- sch->kobj.kset = scx_kset;
- INIT_LIST_HEAD(&sch->all);
-
#ifdef CONFIG_EXT_SUB_SCHED
char *buf = kzalloc(PATH_MAX, GFP_KERNEL);
if (!buf) {
@@ -6385,7 +6403,19 @@ struct scx_sched *scx_alloc_and_add_sched(struct scx_enable_cmd *cmd,
sch->cgrp = cgrp;
INIT_LIST_HEAD(&sch->children);
INIT_LIST_HEAD(&sch->sibling);
+#endif /* CONFIG_EXT_SUB_SCHED */
+
+ /*
+ * Publishing makes @sch visible to scx_prog_sched() readers. Failure
+ * paths after this point must free @sch through kobject_put() whose
+ * release path defers the actual freeing by an RCU grace period.
+ */
+ rcu_assign_pointer(ops->priv, sch);
+ sch->kobj.kset = scx_kset;
+ INIT_LIST_HEAD(&sch->all);
+
+#ifdef CONFIG_EXT_SUB_SCHED
if (parent) {
/*
* Pin @parent for @sch's lifetime. The kobject hierarchy pins
@@ -6440,7 +6470,6 @@ struct scx_sched *scx_alloc_and_add_sched(struct scx_enable_cmd *cmd,
#ifdef CONFIG_EXT_SUB_SCHED
err_free_lb_resched:
- RCU_INIT_POINTER(ops->priv, NULL);
free_cpumask_var(sch->stall_cpus);
#endif
err_free_lb_resched_cpumask:
@@ -6997,6 +7026,21 @@ static bool bpf_scx_is_valid_access(int off, int size,
return btf_ctx_access(off, size, type, prog, info);
}
+/* common to both forms: only scx.disallow is writable */
+static int bpf_scx_btf_struct_access_common(const struct bpf_reg_state *reg,
+ int off, int size)
+{
+ const struct btf_type *t;
+
+ t = btf_type_by_id(reg->btf, reg->btf_id);
+ if (t == task_struct_type &&
+ off >= offsetof(struct task_struct, scx.disallow) &&
+ off + size <= offsetofend(struct task_struct, scx.disallow))
+ return SCALAR_VALUE;
+
+ return -EACCES;
+}
+
static int bpf_scx_btf_struct_access(struct bpf_verifier_log *log,
const struct bpf_reg_state *reg, int off,
int size)
@@ -7005,23 +7049,22 @@ static int bpf_scx_btf_struct_access(struct bpf_verifier_log *log,
t = btf_type_by_id(reg->btf, reg->btf_id);
if (t == task_struct_type) {
- /*
- * COMPAT: Will be removed in v6.23.
- */
if ((off >= offsetof(struct task_struct, scx.slice) &&
off + size <= offsetofend(struct task_struct, scx.slice)) ||
(off >= offsetof(struct task_struct, scx.dsq_vtime) &&
- off + size <= offsetofend(struct task_struct, scx.dsq_vtime))) {
- pr_warn_ratelimited("sched_ext: Writing directly to p->scx.slice/dsq_vtime is deprecated, use scx_bpf_task_set_slice/dsq_vtime()\n");
- return SCALAR_VALUE;
- }
-
- if (off >= offsetof(struct task_struct, scx.disallow) &&
- off + size <= offsetofend(struct task_struct, scx.disallow))
+ off + size <= offsetofend(struct task_struct, scx.dsq_vtime)))
return SCALAR_VALUE;
}
- return -EACCES;
+ return bpf_scx_btf_struct_access_common(reg, off, size);
+}
+
+/* cid-form rejects direct slice and dsq_vtime writes in favor of the kfuncs */
+static int bpf_scx_cid_btf_struct_access(struct bpf_verifier_log *log,
+ const struct bpf_reg_state *reg, int off,
+ int size)
+{
+ return bpf_scx_btf_struct_access_common(reg, off, size);
}
static const struct bpf_verifier_ops bpf_scx_verifier_ops = {
@@ -7030,6 +7073,12 @@ static const struct bpf_verifier_ops bpf_scx_verifier_ops = {
.btf_struct_access = bpf_scx_btf_struct_access,
};
+static const struct bpf_verifier_ops bpf_scx_cid_verifier_ops = {
+ .get_func_proto = bpf_base_func_proto,
+ .is_valid_access = bpf_scx_is_valid_access,
+ .btf_struct_access = bpf_scx_cid_btf_struct_access,
+};
+
static int bpf_scx_init_member(const struct btf_type *t,
const struct btf_member *member,
void *kdata, const void *udata)
@@ -7370,7 +7419,7 @@ static struct sched_ext_ops_cid __bpf_ops_sched_ext_ops_cid = {
* verified to match by the BUILD_BUG_ON checks in scx_init().
*/
static struct bpf_struct_ops bpf_sched_ext_ops_cid = {
- .verifier_ops = &bpf_scx_verifier_ops,
+ .verifier_ops = &bpf_scx_cid_verifier_ops,
.reg = bpf_scx_reg_cid,
.unreg = bpf_scx_unreg,
.check_member = bpf_scx_check_member,
@@ -7764,7 +7813,7 @@ __bpf_kfunc_start_defs();
* When called from ops.select_cpu() or ops.enqueue(), it's for direct dispatch
* and @p must match the task being enqueued.
*
- * When called from ops.select_cpu(), @enq_flags and @dsp_id are stored, and @p
+ * When called from ops.select_cpu(), @enq_flags and @dsq_id are stored, and @p
* will be directly inserted into the corresponding dispatch queue after
* ops.select_cpu() returns. If @p is inserted into SCX_DSQ_LOCAL, it will be
* inserted into the local DSQ of the CPU returned by ops.select_cpu().
@@ -7988,10 +8037,8 @@ static bool scx_dsq_move(struct bpf_iter_scx_dsq_kern *kit,
in_balance = this_rq->scx.flags & SCX_RQ_IN_BALANCE;
if (in_balance) {
- if (this_rq != src_rq) {
- raw_spin_rq_unlock(this_rq);
- raw_spin_rq_lock(src_rq);
- }
+ if (this_rq != src_rq)
+ switch_rq_lock(this_rq, src_rq);
} else {
raw_spin_rq_lock(src_rq);
}
@@ -8023,10 +8070,8 @@ static bool scx_dsq_move(struct bpf_iter_scx_dsq_kern *kit,
dispatched = true;
out:
if (in_balance) {
- if (this_rq != locked_rq) {
- raw_spin_rq_unlock(locked_rq);
- raw_spin_rq_lock(this_rq);
- }
+ if (this_rq != locked_rq)
+ switch_rq_lock(locked_rq, this_rq);
} else {
raw_spin_rq_unlock_irqrestore(locked_rq, flags);
}
@@ -8515,10 +8560,10 @@ __bpf_kfunc void scx_bpf_kick_cpu(s32 cpu, u64 flags, const struct bpf_prog_aux
* @flags: %SCX_KICK_* flags
* @aux: implicit BPF argument to access bpf_prog_aux hidden from BPF progs
*
- * cid-addressed equivalent of scx_bpf_kick_cpu(). Return 0 on success,
- * -errno otherwise.
+ * cid-addressed equivalent of scx_bpf_kick_cpu(). An invalid @cid aborts the
+ * scheduler via scx_cid_to_cpu().
*/
-__bpf_kfunc s32 scx_bpf_kick_cid(s32 cid, u64 flags, const struct bpf_prog_aux *aux)
+__bpf_kfunc void scx_bpf_kick_cid(s32 cid, u64 flags, const struct bpf_prog_aux *aux)
{
struct scx_sched *sch;
s32 cpu;
@@ -8526,12 +8571,11 @@ __bpf_kfunc s32 scx_bpf_kick_cid(s32 cid, u64 flags, const struct bpf_prog_aux *
guard(rcu)();
sch = scx_prog_sched(aux);
if (unlikely(!sch))
- return -ENODEV;
+ return;
cpu = scx_cid_to_cpu(sch, cid);
if (cpu < 0)
- return cpu;
+ return;
scx_kick_cpu(sch, cpu, flags);
- return 0;
}
/**
diff --git a/kernel/sched/ext/internal.h b/kernel/sched/ext/internal.h
index f9fe7c6ebc4b..5ca44ad88786 100644
--- a/kernel/sched/ext/internal.h
+++ b/kernel/sched/ext/internal.h
@@ -1751,8 +1751,11 @@ static inline void update_locked_rq(struct rq *rq)
/*
* SCX ops can recurse via scx_bpf_sub_dispatch() - the inner call must not
* clobber the outer's scx_locked_rq_state. Save it on entry, restore on exit.
+ *
+ * @ops is the ops table to dispatch through: ops for the cpu form, ops_cid
+ * for the cid form.
*/
-#define SCX_CALL_OP(sch, op, locked_rq, args...) \
+#define __SCX_CALL_OP(sch, ops, op, locked_rq, args...) \
do { \
struct rq *__prev_locked_rq; \
\
@@ -1765,6 +1768,9 @@ do { \
update_locked_rq(__prev_locked_rq); \
} while (0)
+#define SCX_CALL_OP(sch, op, locked_rq, args...) \
+ __SCX_CALL_OP(sch, ops, op, locked_rq, ##args)
+
#define SCX_CALL_OP_RET(sch, op, locked_rq, args...) \
({ \
struct rq *__prev_locked_rq; \
@@ -1796,14 +1802,25 @@ do { \
* WARN_ON_ONCE() in each macro catches a re-entry of any of the three variants
* while a previous one is still in progress.
*/
-#define SCX_CALL_OP_TASK(sch, op, locked_rq, task, args...) \
+#define __SCX_CALL_OP_TASK(sch, ops, op, locked_rq, task, args...) \
do { \
WARN_ON_ONCE(current->scx.kf_tasks[0]); \
current->scx.kf_tasks[0] = task; \
- SCX_CALL_OP((sch), op, locked_rq, task, ##args); \
+ __SCX_CALL_OP((sch), ops, op, locked_rq, task, ##args); \
current->scx.kf_tasks[0] = NULL; \
} while (0)
+#define SCX_CALL_OP_TASK(sch, op, locked_rq, task, args...) \
+ __SCX_CALL_OP_TASK(sch, ops, op, locked_rq, task, ##args)
+
+/*
+ * Dispatch a task op through the cid-form ops_cid table. Only set_cmask() needs
+ * this: it takes an arena cmask address instead of a cpumask, so it cannot be
+ * invoked via its cpu-form set_cpumask() slot.
+ */
+#define SCX_CALL_CID_OP_TASK(sch, op, locked_rq, task, args...) \
+ __SCX_CALL_OP_TASK(sch, ops_cid, op, locked_rq, task, ##args)
+
#define SCX_CALL_OP_TASK_RET(sch, op, locked_rq, task, args...) \
({ \
__typeof__((sch)->ops.op(task, ##args)) __ret; \
diff --git a/kernel/sched/ext/sub.c b/kernel/sched/ext/sub.c
index 050420427273..ce76ae141e0a 100644
--- a/kernel/sched/ext/sub.c
+++ b/kernel/sched/ext/sub.c
@@ -570,6 +570,12 @@ err_unlock_and_disable:
percpu_up_write(&scx_fork_rwsem);
err_disable:
mutex_unlock(&scx_enable_mutex);
+ /*
+ * Some enable failures only return an errno (e.g. -ENOMEM from an
+ * allocation) without calling scx_error(). Record it so
+ * scx_flush_disable_work() runs the disable and ops.exit() fires.
+ */
+ scx_error(sch, "scx_sub_enable() failed (%d)", ret);
scx_flush_disable_work(sch);
cmd->ret = 0;
}
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 26ae13c86b69..0905a4a9681c 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -800,7 +800,8 @@ struct scx_rq {
struct list_head runnable_list; /* runnable tasks on this rq */
struct list_head ddsp_deferred_locals; /* deferred ddsps from enq */
unsigned long ops_qseq;
- u64 extra_enq_flags; /* see move_task_to_local_dsq() */
+ /* see move_remote_task_to_local_dsq() */
+ u64 remote_activate_enq_flags;
u32 nr_running;
u32 cpuperf_target; /* [0, SCHED_CAPACITY_SCALE] */
bool in_select_cpu;
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index c9efb17cc255..0cb5d1759d42 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -148,7 +148,7 @@ static void warn_sysctl_write(const struct ctl_table *table)
* @ppos: file position
* @table: the sysctl table
*
- * Returns true if the first position is non-zero and the sysctl_writes_strict
+ * Returns: true if the first position is non-zero and the sysctl_writes_strict
* mode indicates this is not allowed for numeric input types. String proc
* handlers can ignore the return value.
*/
@@ -184,7 +184,7 @@ static bool proc_first_pos_non_zero_ignore(loff_t *ppos,
* and a newline '\n' is added. It is truncated if the buffer is
* not large enough.
*
- * Returns 0 on success.
+ * Returns: %0 on success.
*/
int proc_dostring(const struct ctl_table *table, int dir,
void *buffer, size_t *lenp, loff_t *ppos)
@@ -225,11 +225,14 @@ static void proc_skip_char(char **buf, size_t *size, const char v)
* @base: the base to use
* @res: where the parsed integer will be stored
*
- * In case of success 0 is returned and @res will contain the parsed integer,
- * @endp will hold any trailing characters.
* This function will fail the parse on overflow. If there wasn't an overflow
* the function will defer the decision what characters count as invalid to the
* caller.
+ *
+ * Returns:
+ * * %0 on success and @res will contain the parsed integer,
+ * @endp will hold any trailing characters.
+ * * %-ERANGE on overflow.
*/
static int strtoul_lenient(const char *cp, char **endp, unsigned int base,
unsigned long *res)
@@ -263,10 +266,12 @@ static int strtoul_lenient(const char *cp, char **endp, unsigned int base,
* @perm_tr_len: size of the perm_tr vector
* @tr: pointer to store the trailer character
*
- * In case of success %0 is returned and @buf and @size are updated with
- * the amount of bytes read. If @tr is non-NULL and a trailing
- * character exists (size is non-zero after returning from this
- * function), @tr is updated with the trailing character.
+ * Returns:
+ * * %0 on success and @buf and @size are updated with
+ * the amount of bytes read. If @tr is non-NULL and a trailing
+ * character exists (size is non-zero after returning from this
+ * function), @tr is updated with the trailing character.
+ * * %-EINVAL on failure.
*/
static int proc_get_long(char **buf, size_t *size,
unsigned long *val, bool *neg,
@@ -365,7 +370,7 @@ static void proc_put_char(void **buf, size_t *size, char c)
* not NULL. Check that the values are less than UINT_MAX to avoid
* having to support wrap around from userspace.
*
- * returns 0 on success.
+ * Returns: %0 on success.
*/
int proc_uint_u2k_conv_uop(const ulong *u_ptr, uint *k_ptr,
ulong (*u_ptr_op)(const ulong))
@@ -386,7 +391,7 @@ int proc_uint_u2k_conv_uop(const ulong *u_ptr, uint *k_ptr,
*
* Uses READ_ONCE to assign value to u_ptr.
*
- * returns 0 on success.
+ * Returns: %0 on success.
*/
int proc_uint_k2u_conv(ulong *u_ptr, const uint *k_ptr)
{
@@ -409,7 +414,7 @@ int proc_uint_k2u_conv(ulong *u_ptr, const uint *k_ptr)
* When direction is kernel to user, then the u_ptr is modified.
* When direction is user to kernel, then the k_ptr is modified.
*
- * Returns 0 on success
+ * Returns: %0 on success
*/
int proc_uint_conv(ulong *u_ptr, uint *k_ptr, int dir,
const struct ctl_table *tbl, bool k_ptr_range_check,
@@ -444,15 +449,15 @@ static int proc_uint_u2k_conv(const ulong *u_ptr, uint *k_ptr)
return proc_uint_u2k_conv_uop(u_ptr, k_ptr, NULL);
}
-static int do_proc_uint_conv(ulong *u_ptr, uint *k_ptr, int dir,
+static int do_proc_uint_conv(bool *negp, ulong *u_ptr, uint *k_ptr, int dir,
const struct ctl_table *tbl)
{
return proc_uint_conv(u_ptr, k_ptr, dir, tbl, false,
proc_uint_u2k_conv, proc_uint_k2u_conv);
}
-static int do_proc_uint_conv_minmax(ulong *u_ptr, uint *k_ptr, int dir,
- const struct ctl_table *tbl)
+static int do_proc_uint_conv_minmax(bool *negp, ulong *u_ptr, uint *k_ptr,
+ int dir, const struct ctl_table *tbl)
{
return proc_uint_conv(u_ptr, k_ptr, dir, tbl, true,
proc_uint_u2k_conv, proc_uint_k2u_conv);
@@ -515,6 +520,23 @@ int proc_int_u2k_conv_uop(const ulong *u_ptr, int *k_ptr, const bool *negp,
return 0;
}
+/**
+ * proc_int_conv - Change user or kernel pointer based on direction
+ *
+ * @negp: will be passed to uni-directional converters
+ * @u_ptr: pointer to user variable
+ * @k_ptr: pointer to kernel variable
+ * @dir: %TRUE if this is a write to the sysctl file
+ * @tbl: the sysctl table
+ * @k_ptr_range_check: Check range for k_ptr when %TRUE
+ * @user_to_kern: Callback used to assign value from user to kernel var
+ * @kern_to_user: Callback used to assign value from kernel to user var
+ *
+ * When direction is kernel to user, then the u_ptr is modified.
+ * When direction is user to kernel, then the k_ptr is modified.
+ *
+ * Returns: 0 on success
+ */
int proc_int_conv(bool *negp, ulong *u_ptr, int *k_ptr, int dir,
const struct ctl_table *tbl, bool k_ptr_range_check,
int (*user_to_kern)(const bool *negp, const ulong *u_ptr, int *k_ptr),
@@ -572,14 +594,80 @@ static int do_proc_int_conv_minmax(bool *negp, unsigned long *u_ptr, int *k_ptr,
static const char proc_wspace_sep[] = { ' ', '\t', '\n' };
-static int do_proc_dointvec(const struct ctl_table *table, int dir,
- void *buffer, size_t *lenp, loff_t *ppos,
- int (*conv)(bool *negp, unsigned long *u_ptr, int *k_ptr,
- int dir, const struct ctl_table *table))
+/*
+ * Element type processed by do_proc_vec(). The tag selects the element size
+ * and signedness, and it selects which member of union proc_vec_conv is live.
+ */
+enum proc_vec_type {
+ PROC_VEC_INT,
+ PROC_VEC_UINT,
+ PROC_VEC_ULONG,
+};
+
+/*
+ * Converter passed to do_proc_vec(). Only the member matching the
+ * enum proc_vec_type tag is ever read, so every dispatch stays fully typed and
+ * no void * converter pointer is needed.
+ */
+union proc_vec_conv {
+ int (*int_conv)(bool *negp, ulong *u_ptr, int *k_ptr,
+ int dir, const struct ctl_table *table);
+ int (*uint_conv)(bool *negp, ulong *u_ptr, uint *k_ptr,
+ int dir, const struct ctl_table *table);
+ int (*ulong_conv)(bool *negp, ulong *u_ptr, ulong *k_ptr,
+ int dir, const struct ctl_table *table);
+};
+
+/*
+ * Dispatch to the converter member selected by @type. @k_ptr walks
+ * table->data as raw bytes and is cast back to the element type here.
+ */
+static int proc_vec_conv(enum proc_vec_type type, union proc_vec_conv conv,
+ bool *negp, ulong *u_ptr, char *k_ptr, int dir,
+ const struct ctl_table *table)
+{
+ switch (type) {
+ case PROC_VEC_INT:
+ return conv.int_conv(negp, u_ptr, (int *)k_ptr, dir, table);
+ case PROC_VEC_UINT:
+ return conv.uint_conv(negp, u_ptr, (uint *)k_ptr, dir, table);
+ case PROC_VEC_ULONG:
+ return conv.ulong_conv(negp, u_ptr, (ulong *)k_ptr, dir, table);
+ }
+ return -EINVAL;
+}
+
+/*
+ * Read/write a vector of @type elements. The element size and signedness are
+ * derived from @type, so a single runtime function replaces the per-type
+ * variants. table->data is walked as raw bytes (@i) advanced by @size; the
+ * converter performs the actual typed load/store.
+ */
+static int do_proc_vec(const struct ctl_table *table, int dir,
+ void *buffer, size_t *lenp, loff_t *ppos,
+ enum proc_vec_type type, union proc_vec_conv conv)
{
- int *i, vleft, first = 1, err = 0;
- size_t left;
- char *p;
+ int vleft, first = 1, err = 0;
+ size_t left, size;
+ bool is_unsigned;
+ char *i, *p;
+
+ switch (type) {
+ case PROC_VEC_INT:
+ size = sizeof(int);
+ is_unsigned = false;
+ break;
+ case PROC_VEC_UINT:
+ size = sizeof(uint);
+ is_unsigned = true;
+ break;
+ case PROC_VEC_ULONG:
+ size = sizeof(ulong);
+ is_unsigned = true;
+ break;
+ default:
+ return -EINVAL;
+ }
if (!table->data || !table->maxlen || !*lenp ||
(*ppos && SYSCTL_KERN_TO_USER(dir))) {
@@ -587,12 +675,13 @@ static int do_proc_dointvec(const struct ctl_table *table, int dir,
return 0;
}
- i = (int *) table->data;
- vleft = table->maxlen / sizeof(*i);
+ i = table->data;
+ vleft = table->maxlen / size;
left = *lenp;
- if (!conv)
- conv = do_proc_int_conv;
+ /* uint arrays are not supported, *Do not* add support for them. */
+ if (type == PROC_VEC_UINT && vleft != 1)
+ return -EINVAL;
if (SYSCTL_USER_TO_KERN(dir)) {
if (proc_first_pos_non_zero_ignore(ppos, table))
@@ -603,9 +692,9 @@ static int do_proc_dointvec(const struct ctl_table *table, int dir,
p = buffer;
}
- for (; left && vleft--; i++, first=0) {
+ for (; left && vleft--; i += size, first = 0) {
unsigned long lval;
- bool neg;
+ bool neg = false;
if (SYSCTL_USER_TO_KERN(dir)) {
proc_skip_spaces(&p, &left);
@@ -613,16 +702,18 @@ static int do_proc_dointvec(const struct ctl_table *table, int dir,
if (!left)
break;
err = proc_get_long(&p, &left, &lval, &neg,
- proc_wspace_sep,
- sizeof(proc_wspace_sep), NULL);
+ proc_wspace_sep,
+ sizeof(proc_wspace_sep), NULL);
+ if (!err && neg && is_unsigned)
+ err = -EINVAL;
if (err)
break;
- if (conv(&neg, &lval, i, 1, table)) {
+ if (proc_vec_conv(type, conv, &neg, &lval, i, dir, table)) {
err = -EINVAL;
break;
}
} else {
- if (conv(&neg, &lval, i, 0, table)) {
+ if (proc_vec_conv(type, conv, &neg, &lval, i, dir, table)) {
err = -EINVAL;
break;
}
@@ -644,122 +735,6 @@ out:
return err;
}
-static int do_proc_douintvec_w(const struct ctl_table *table, void *buffer,
- size_t *lenp, loff_t *ppos,
- int (*conv)(unsigned long *u_ptr,
- unsigned int *k_ptr, int dir,
- const struct ctl_table *table))
-{
- unsigned long lval;
- int err = 0;
- size_t left;
- bool neg;
- char *p = buffer;
-
- left = *lenp;
-
- if (proc_first_pos_non_zero_ignore(ppos, table))
- goto bail_early;
-
- if (left > PAGE_SIZE - 1)
- left = PAGE_SIZE - 1;
-
- proc_skip_spaces(&p, &left);
- if (!left) {
- err = -EINVAL;
- goto out_free;
- }
-
- err = proc_get_long(&p, &left, &lval, &neg,
- proc_wspace_sep,
- sizeof(proc_wspace_sep), NULL);
- if (err || neg) {
- err = -EINVAL;
- goto out_free;
- }
-
- if (conv(&lval, (unsigned int *) table->data, 1, table)) {
- err = -EINVAL;
- goto out_free;
- }
-
- if (!err && left)
- proc_skip_spaces(&p, &left);
-
-out_free:
- if (err)
- return -EINVAL;
-
- return 0;
-
-bail_early:
- *ppos += *lenp;
- return err;
-}
-
-static int do_proc_douintvec_r(const struct ctl_table *table, void *buffer,
- size_t *lenp, loff_t *ppos,
- int (*conv)(unsigned long *u_ptr,
- unsigned int *k_ptr, int dir,
- const struct ctl_table *table))
-{
- unsigned long lval;
- int err = 0;
- size_t left;
-
- left = *lenp;
-
- if (conv(&lval, (unsigned int *) table->data, 0, table)) {
- err = -EINVAL;
- goto out;
- }
-
- proc_put_long(&buffer, &left, lval, false);
- if (!left)
- goto out;
-
- proc_put_char(&buffer, &left, '\n');
-
-out:
- *lenp -= left;
- *ppos += *lenp;
-
- return err;
-}
-
-static int do_proc_douintvec(const struct ctl_table *table, int dir,
- void *buffer, size_t *lenp, loff_t *ppos,
- int (*conv)(unsigned long *u_ptr,
- unsigned int *k_ptr, int dir,
- const struct ctl_table *table))
-{
- unsigned int vleft;
-
- if (!table->data || !table->maxlen || !*lenp ||
- (*ppos && SYSCTL_KERN_TO_USER(dir))) {
- *lenp = 0;
- return 0;
- }
-
- vleft = table->maxlen / sizeof(unsigned int);
-
- /*
- * Arrays are not supported, keep this simple. *Do not* add
- * support for them.
- */
- if (vleft != 1) {
- *lenp = 0;
- return -EINVAL;
- }
-
- if (!conv)
- conv = do_proc_uint_conv;
-
- if (SYSCTL_USER_TO_KERN(dir))
- return do_proc_douintvec_w(table, buffer, lenp, ppos, conv);
- return do_proc_douintvec_r(table, buffer, lenp, ppos, conv);
-}
-
/**
* proc_douintvec_conv - read a vector of unsigned ints with a custom converter
*
@@ -774,14 +749,19 @@ static int do_proc_douintvec(const struct ctl_table *table, int dir,
* values from/to the user buffer, treated as an ASCII string. Negative
* strings are not allowed.
*
- * Returns 0 on success
+ * Returns: %0 on success
*/
int proc_douintvec_conv(const struct ctl_table *table, int dir, void *buffer,
size_t *lenp, loff_t *ppos,
- int (*conv)(unsigned long *u_ptr, unsigned int *k_ptr,
+ int (*conv)(bool *negp, ulong *u_ptr, uint *k_ptr,
int dir, const struct ctl_table *table))
{
- return do_proc_douintvec(table, dir, buffer, lenp, ppos, conv);
+
+ if (!conv)
+ conv = do_proc_uint_conv;
+
+ return do_proc_vec(table, dir, buffer, lenp, ppos, PROC_VEC_UINT,
+ (union proc_vec_conv){ .uint_conv = conv });
}
/**
@@ -798,7 +778,7 @@ int proc_douintvec_conv(const struct ctl_table *table, int dir, void *buffer,
* table->data must point to a bool variable and table->maxlen must
* be sizeof(bool).
*
- * Returns 0 on success.
+ * Returns: %0 on success.
*/
int proc_dobool(const struct ctl_table *table, int dir, void *buffer,
size_t *lenp, loff_t *ppos)
@@ -835,12 +815,13 @@ int proc_dobool(const struct ctl_table *table, int dir, void *buffer,
* Reads/writes up to table->maxlen/sizeof(unsigned int) integer
* values from/to the user buffer, treated as an ASCII string.
*
- * Returns 0 on success.
+ * Returns: %0 on success.
*/
int proc_dointvec(const struct ctl_table *table, int dir, void *buffer,
size_t *lenp, loff_t *ppos)
{
- return do_proc_dointvec(table, dir, buffer, lenp, ppos, NULL);
+ return do_proc_vec(table, dir, buffer, lenp, ppos, PROC_VEC_INT,
+ (union proc_vec_conv){ .int_conv = do_proc_int_conv });
}
/**
@@ -854,13 +835,13 @@ int proc_dointvec(const struct ctl_table *table, int dir, void *buffer,
* Reads/writes up to table->maxlen/sizeof(unsigned int) unsigned integer
* values from/to the user buffer, treated as an ASCII string.
*
- * Returns 0 on success.
+ * Returns: %0 on success.
*/
int proc_douintvec(const struct ctl_table *table, int dir, void *buffer,
size_t *lenp, loff_t *ppos)
{
- return do_proc_douintvec(table, dir, buffer, lenp, ppos,
- do_proc_uint_conv);
+ return do_proc_vec(table, dir, buffer, lenp, ppos, PROC_VEC_UINT,
+ (union proc_vec_conv){ .uint_conv = do_proc_uint_conv });
}
/**
@@ -877,14 +858,14 @@ int proc_douintvec(const struct ctl_table *table, int dir, void *buffer,
* This routine will ensure the values are within the range specified by
* table->extra1 (min) and table->extra2 (max).
*
- * Returns 0 on success or -EINVAL when the range check fails and
+ * Returns: %0 on success or -EINVAL when the range check fails and
* SYSCTL_USER_TO_KERN(dir) == true
*/
int proc_dointvec_minmax(const struct ctl_table *table, int dir,
void *buffer, size_t *lenp, loff_t *ppos)
{
- return do_proc_dointvec(table, dir, buffer, lenp, ppos,
- do_proc_int_conv_minmax);
+ return do_proc_vec(table, dir, buffer, lenp, ppos, PROC_VEC_INT,
+ (union proc_vec_conv){ .int_conv = do_proc_int_conv_minmax });
}
/**
@@ -904,14 +885,14 @@ int proc_dointvec_minmax(const struct ctl_table *table, int dir,
* (max). And Check that the values are less than UINT_MAX to avoid having to
* support wrap around uses from userspace.
*
- * Returns 0 on success or -ERANGE when range check failes and
+ * Returns: %0 on success or -ERANGE when range check failes and
* SYSCTL_USER_TO_KERN(dir) == true
*/
int proc_douintvec_minmax(const struct ctl_table *table, int dir,
void *buffer, size_t *lenp, loff_t *ppos)
{
- return do_proc_douintvec(table, dir, buffer, lenp, ppos,
- do_proc_uint_conv_minmax);
+ return do_proc_vec(table, dir, buffer, lenp, ppos, PROC_VEC_UINT,
+ (union proc_vec_conv){ .uint_conv = do_proc_uint_conv_minmax });
}
/**
@@ -929,7 +910,7 @@ int proc_douintvec_minmax(const struct ctl_table *table, int dir,
* This routine will ensure the values are within the range specified by
* table->extra1 (min) and table->extra2 (max).
*
- * Returns 0 on success or an error on SYSCTL_USER_TO_KERN(dir) == true
+ * Returns: %0 on success or an error on SYSCTL_USER_TO_KERN(dir) == true
* and the range check fails.
*/
int proc_dou8vec_minmax(const struct ctl_table *table, int dir,
@@ -954,8 +935,8 @@ int proc_dou8vec_minmax(const struct ctl_table *table, int dir,
tmp.extra2 = (unsigned int *) &max;
val = READ_ONCE(*data);
- res = do_proc_douintvec(&tmp, dir, buffer, lenp, ppos,
- do_proc_uint_conv_minmax);
+ res = do_proc_vec(&tmp, dir, buffer, lenp, ppos, PROC_VEC_UINT,
+ (union proc_vec_conv){ .uint_conv = do_proc_uint_conv_minmax });
if (res)
return res;
if (SYSCTL_USER_TO_KERN(dir))
@@ -964,87 +945,129 @@ int proc_dou8vec_minmax(const struct ctl_table *table, int dir,
}
EXPORT_SYMBOL_GPL(proc_dou8vec_minmax);
-static int do_proc_doulongvec_minmax(const struct ctl_table *table, int dir,
- void *buffer, size_t *lenp, loff_t *ppos,
- unsigned long convmul,
- unsigned long convdiv)
+/**
+ * proc_ulong_conv - Change user or kernel pointer based on direction
+ *
+ * @u_ptr: pointer to user variable
+ * @k_ptr: pointer to kernel variable
+ * @dir: %TRUE if this is a write to the sysctl file
+ * @tbl: the sysctl table
+ * @k_ptr_range_check: Check range for k_ptr when %TRUE
+ * @user_to_kern: Callback used to assign value from user to kernel var
+ * @kern_to_user: Callback used to assign value from kernel to user var
+ *
+ * When direction is kernel to user, then the u_ptr is modified.
+ * When direction is user to kernel, then the k_ptr is modified.
+ *
+ * Returns: 0 on success
+ */
+int proc_ulong_conv(ulong *u_ptr, ulong *k_ptr, int dir,
+ const struct ctl_table *tbl, bool k_ptr_range_check,
+ int (*user_to_kern)(const ulong *u_ptr, ulong *k_ptr),
+ int (*kern_to_user)(ulong *u_ptr, const ulong *k_ptr))
{
- unsigned long *i, *min, *max;
- int vleft, first = 1, err = 0;
- size_t left;
- char *p;
-
- if (!table->data || !table->maxlen || !*lenp ||
- (*ppos && SYSCTL_KERN_TO_USER(dir))) {
- *lenp = 0;
- return 0;
- }
-
- i = table->data;
- min = table->extra1;
- max = table->extra2;
- vleft = table->maxlen / sizeof(unsigned long);
- left = *lenp;
+ if (SYSCTL_KERN_TO_USER(dir))
+ return kern_to_user(u_ptr, k_ptr);
- if (SYSCTL_USER_TO_KERN(dir)) {
- if (proc_first_pos_non_zero_ignore(ppos, table))
- goto out;
+ if (k_ptr_range_check) {
+ ulong tmp_k;
+ int ret;
- if (left > PAGE_SIZE - 1)
- left = PAGE_SIZE - 1;
- p = buffer;
- }
+ if (!tbl)
+ return -EINVAL;
+ ret = user_to_kern(u_ptr, &tmp_k);
+ if (ret)
+ return ret;
+ if ((tbl->extra1 && *(ulong *)tbl->extra1 > tmp_k) ||
+ (tbl->extra2 && *(ulong *)tbl->extra2 < tmp_k))
+ return -ERANGE;
+ WRITE_ONCE(*k_ptr, tmp_k);
+ } else
+ return user_to_kern(u_ptr, k_ptr);
+ return 0;
+}
- for (; left && vleft--; i++, first = 0) {
- unsigned long val;
+/**
+ * proc_ulong_u2k_conv_uop - Assign user value to a kernel pointer
+ *
+ * @u_ptr: pointer to user space variable
+ * @k_ptr: pointer to kernel variable
+ * @u_ptr_op: execute this function before assigning to k_ptr
+ *
+ * Uses WRITE_ONCE to assign value to k_ptr. Executes u_ptr_op if
+ * not NULL.
+ *
+ * Returns: 0 on success.
+ */
+int proc_ulong_u2k_conv_uop(const ulong *u_ptr, ulong *k_ptr,
+ ulong (*u_ptr_op)(const ulong))
+{
+ ulong u = u_ptr_op ? u_ptr_op(*u_ptr) : *u_ptr;
- if (SYSCTL_USER_TO_KERN(dir)) {
- bool neg;
+ WRITE_ONCE(*k_ptr, u);
+ return 0;
+}
- proc_skip_spaces(&p, &left);
- if (!left)
- break;
+static int proc_ulong_u2k_conv(const ulong *u_ptr, ulong *k_ptr)
+{
+ return proc_ulong_u2k_conv_uop(u_ptr, k_ptr, NULL);
+}
- err = proc_get_long(&p, &left, &val, &neg,
- proc_wspace_sep,
- sizeof(proc_wspace_sep), NULL);
- if (err || neg) {
- err = -EINVAL;
- break;
- }
+/**
+ * proc_ulong_k2u_conv_kop - Assign kernel value to a user space pointer
+ *
+ * @u_ptr: pointer to user space variable
+ * @k_ptr: pointer to kernel variable
+ * @k_ptr_op: Operation applied to k_ptr before assignment
+ *
+ * Uses READ_ONCE to assign value to u_ptr. Executes k_ptr_op if
+ * not NULL.
+ *
+ * Returns: 0 on success.
+ */
+int proc_ulong_k2u_conv_kop(ulong *u_ptr, const ulong *k_ptr,
+ ulong (*k_ptr_op)(const ulong))
+{
+ ulong val = k_ptr_op ? k_ptr_op(READ_ONCE(*k_ptr)) : READ_ONCE(*k_ptr);
+ *u_ptr = (ulong)val;
+ return 0;
+}
- val = convmul * val / convdiv;
- if ((min && val < *min) || (max && val > *max)) {
- err = -EINVAL;
- break;
- }
- WRITE_ONCE(*i, val);
- } else {
- val = convdiv * READ_ONCE(*i) / convmul;
- if (!first)
- proc_put_char(&buffer, &left, '\t');
- proc_put_long(&buffer, &left, val, false);
- }
- }
+static int proc_ulong_k2u_conv(ulong *u_ptr, const ulong *k_ptr)
+{
+ return proc_ulong_k2u_conv_kop(u_ptr, k_ptr, NULL);
+}
- if (SYSCTL_KERN_TO_USER(dir) && !first && left && !err)
- proc_put_char(&buffer, &left, '\n');
- if (SYSCTL_USER_TO_KERN(dir) && !err)
- proc_skip_spaces(&p, &left);
- if (SYSCTL_USER_TO_KERN(dir) && first)
- return err ? : -EINVAL;
- *lenp -= left;
-out:
- *ppos += *lenp;
- return err;
+static int do_proc_ulong_conv(bool *negp, ulong *u_ptr, ulong *k_ptr, int dir,
+ const struct ctl_table *tbl)
+{
+ return proc_ulong_conv(u_ptr, k_ptr, dir, tbl, true,
+ proc_ulong_u2k_conv, proc_ulong_k2u_conv);
}
-int proc_doulongvec_minmax_conv(const struct ctl_table *table, int dir,
+/**
+ * proc_doulongvec_conv - read a vector of unsigned longs with a custom converter
+ *
+ * @table: the sysctl table
+ * @dir: %TRUE if this is a write to the sysctl file
+ * @buffer: the user buffer
+ * @lenp: the size of the user buffer
+ * @ppos: file position
+ * @conv: Custom converter call back
+ *
+ * Reads/writes up to table->maxlen/sizeof(unsigned long) unsigned long
+ * values from/to the user buffer, treated as an ASCII string. Negative
+ * strings are not allowed.
+ *
+ * Returns: 0 on success
+ */
+int proc_doulongvec_conv(const struct ctl_table *table, int dir,
void *buffer, size_t *lenp, loff_t *ppos,
- unsigned long convmul, unsigned long convdiv)
+ int (*conv)(bool *negp, ulong *u_ptr, ulong *k_ptr,
+ int dir, const struct ctl_table *table))
{
- return do_proc_doulongvec_minmax(table, dir, buffer, lenp, ppos,
- convmul, convdiv);
+ return do_proc_vec(table, dir, buffer, lenp, ppos, PROC_VEC_ULONG,
+ (union proc_vec_conv){ .ulong_conv = conv });
}
/**
@@ -1061,12 +1084,13 @@ int proc_doulongvec_minmax_conv(const struct ctl_table *table, int dir,
* This routine will ensure the values are within the range specified by
* table->extra1 (min) and table->extra2 (max).
*
- * Returns 0 on success.
+ * Returns: %0 on success.
*/
int proc_doulongvec_minmax(const struct ctl_table *table, int dir,
void *buffer, size_t *lenp, loff_t *ppos)
{
- return proc_doulongvec_minmax_conv(table, dir, buffer, lenp, ppos, 1l, 1l);
+ return do_proc_vec(table, dir, buffer, lenp, ppos, PROC_VEC_ULONG,
+ (union proc_vec_conv){ .ulong_conv = do_proc_ulong_conv });
}
/**
@@ -1076,21 +1100,22 @@ int proc_doulongvec_minmax(const struct ctl_table *table, int dir,
* @buffer: the user buffer
* @lenp: the size of the user buffer
* @ppos: file position
- * @conv: Custom converter call back
+ * @conv: Custom converter call back. Defaults to do_proc_int_conv
*
- * Reads/writes up to table->maxlen/sizeof(unsigned int) unsigned integer
- * values from/to the user buffer, treated as an ASCII string. Negative
- * strings are not allowed.
+ * Reads/writes up to table->maxlen/sizeof(int) integer values from/to the
+ * user buffer, treated as an ASCII string.
*
* Returns: 0 on success
*/
-
int proc_dointvec_conv(const struct ctl_table *table, int dir, void *buffer,
size_t *lenp, loff_t *ppos,
int (*conv)(bool *negp, unsigned long *u_ptr, int *k_ptr,
int dir, const struct ctl_table *table))
{
- return do_proc_dointvec(table, dir, buffer, lenp, ppos, conv);
+ if (!conv)
+ conv = do_proc_int_conv;
+ return do_proc_vec(table, dir, buffer, lenp, ppos, PROC_VEC_INT,
+ (union proc_vec_conv){ .int_conv = conv });
}
/**
@@ -1108,7 +1133,7 @@ int proc_dointvec_conv(const struct ctl_table *table, int dir, void *buffer,
* large bitmaps may be represented in a compact manner. Writing into
* the file will clear the bitmap then update it with the given input.
*
- * Returns 0 on success.
+ * Returns: %0 on success.
*/
int proc_do_large_bitmap(const struct ctl_table *table, int dir,
void *buffer, size_t *lenp, loff_t *ppos)
@@ -1280,7 +1305,7 @@ int proc_douintvec_minmax(const struct ctl_table *table, int dir,
int proc_douintvec_conv(const struct ctl_table *table, int write, void *buffer,
size_t *lenp, loff_t *ppos,
- int (*conv)(unsigned long *lvalp, unsigned int *valp,
+ int (*conv)(bool *negp, ulong *lvalp, uint *valp,
int write, const struct ctl_table *table))
{
return -ENOSYS;
@@ -1317,9 +1342,10 @@ int proc_doulongvec_minmax(const struct ctl_table *table, int dir,
return -ENOSYS;
}
-int proc_doulongvec_minmax_conv(const struct ctl_table *table, int dir,
+int proc_doulongvec_conv(const struct ctl_table *table, int dir,
void *buffer, size_t *lenp, loff_t *ppos,
- unsigned long convmul, unsigned long convdiv)
+ int (*conv)(bool *negp, ulong *u_ptr, ulong *k_ptr,
+ int dir, const struct ctl_table *table))
{
return -ENOSYS;
}
diff --git a/kernel/time/jiffies.c b/kernel/time/jiffies.c
index d51428867a33..af529d558fa9 100644
--- a/kernel/time/jiffies.c
+++ b/kernel/time/jiffies.c
@@ -185,6 +185,24 @@ static int do_proc_int_conv_ms_jiffies_minmax(bool *negp, ulong *u_ptr,
sysctl_u2k_int_conv_ms, sysctl_k2u_int_conv_ms);
}
+static int sysctl_u2k_ulong_conv_ms(const ulong *u_ptr, ulong *k_ptr)
+{
+ return proc_ulong_u2k_conv_uop(u_ptr, k_ptr, sysctl_msecs_to_jiffies);
+}
+
+static int sysctl_k2u_ulong_conv_ms(ulong *u_ptr, const ulong *k_ptr)
+{
+ return proc_ulong_k2u_conv_kop(u_ptr, k_ptr, sysctl_jiffies_to_msecs);
+}
+
+static int do_proc_ulong_conv_ms_jiffies(bool *negp, ulong *u_ptr, ulong *k_ptr,
+ int dir, const struct ctl_table *tbl)
+{
+ return proc_ulong_conv(u_ptr, k_ptr, dir, tbl, false,
+ sysctl_u2k_ulong_conv_ms, sysctl_k2u_ulong_conv_ms);
+}
+
+
#else // CONFIG_PROC_SYSCTL
static int do_proc_int_conv_jiffies(bool *negp, ulong *u_ptr, int *k_ptr,
int dir, const struct ctl_table *tbl)
@@ -211,6 +229,12 @@ static int do_proc_int_conv_ms_jiffies_minmax(bool *negp, ulong *u_ptr,
{
return -ENOSYS;
}
+
+static int do_proc_ulong_conv_ms_jiffies(bool *negp, ulong *u_ptr, ulong *k_ptr,
+ int dir, const struct ctl_table *tbl)
+{
+ return -ENOSYS;
+}
#endif
/**
@@ -309,8 +333,8 @@ int proc_dointvec_ms_jiffies_minmax(const struct ctl_table *table, int dir,
int proc_doulongvec_ms_jiffies_minmax(const struct ctl_table *table, int dir,
void *buffer, size_t *lenp, loff_t *ppos)
{
- return proc_doulongvec_minmax_conv(table, dir, buffer, lenp, ppos,
- HZ, 1000l);
+ return proc_doulongvec_conv(table, dir, buffer, lenp, ppos,
+ do_proc_ulong_conv_ms_jiffies);
}
EXPORT_SYMBOL(proc_doulongvec_ms_jiffies_minmax);
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 98a9cae915c0..6c3fea386713 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -828,8 +828,7 @@ static ktime_t tick_nohz_next_event(struct tick_sched *ts, int cpu)
ts->timer_expires_base = basemono;
/*
- * Keep the periodic tick, when RCU, architecture or irq_work
- * requests it.
+ * Keep the periodic tick, when RCU or irq_work requests it.
* Aside of that, check whether the local timer softirq is
* pending. If so, its a bad idea to call get_next_timer_interrupt(),
* because there is an already expired timer, so it will request
@@ -837,8 +836,8 @@ static ktime_t tick_nohz_next_event(struct tick_sched *ts, int cpu)
* minimal delta, which brings us back to this place
* immediately. Lather, rinse and repeat...
*/
- if (rcu_needs_cpu() || arch_needs_cpu() ||
- irq_work_needs_cpu() || local_timer_softirq_pending()) {
+ if (rcu_needs_cpu() || irq_work_needs_cpu() ||
+ local_timer_softirq_pending()) {
next_tick = basemono + TICK_NSEC;
} else {
/*
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 6e95bd480608..97db2e9393f9 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -352,8 +352,8 @@ static void tk_setup_internals(struct timekeeper *tk, struct clocksource *clock)
tk->tkr_raw.cycle_last = tk->tkr_mono.cycle_last;
/* Do the ns -> cycle conversion first, using original mult */
- interval = NTP_INTERVAL_LENGTH << clock->shift;
- interval += clock->mult/2;
+ interval = (u64)NTP_INTERVAL_LENGTH << clock->shift;
+ interval += clock->mult / 2;
do_div(interval, clock->mult);
if (interval == 0)
interval = 1;
diff --git a/lib/bug.c b/lib/bug.c
index b9820a0226f5..7c1c2c27f58e 100644
--- a/lib/bug.c
+++ b/lib/bug.c
@@ -219,14 +219,12 @@ static enum bug_trap_type __report_bug(struct bug_entry *bug, unsigned long buga
no_cut = bug->flags & BUGFLAG_NO_CUT_HERE;
has_args = bug->flags & BUGFLAG_ARGS;
-#if IS_ENABLED(CONFIG_KUNIT)
/*
* Before the once logic so suppressed warnings do not consume
* the single-fire budget of WARN_ON_ONCE().
*/
if (warning && kunit_is_suppressed_warning(true))
return BUG_TRAP_TYPE_WARN;
-#endif
disable_trace_on_warning();
diff --git a/lib/test_bitmap.c b/lib/test_bitmap.c
index 8665df77c960..56bd23059b26 100644
--- a/lib/test_bitmap.c
+++ b/lib/test_bitmap.c
@@ -429,6 +429,7 @@ static void __init test_bitmap_sg(void)
/* Scatter/gather relationship */
bitmap_zero(bmap_tmp, 100);
+ bitmap_zero(bmap_res, 100);
bitmap_gather(bmap_tmp, bmap_scatter, sg_mask, nbits);
bitmap_scatter(bmap_res, bmap_tmp, sg_mask, nbits);
expect_eq_bitmap(bmap_scatter, bmap_res, 100);
diff --git a/localversion-next b/localversion-next
new file mode 100644
index 000000000000..ce70639551de
--- /dev/null
+++ b/localversion-next
@@ -0,0 +1 @@
+-next-20260710
diff --git a/mm/Kconfig b/mm/Kconfig
index f794a341d742..9dcbf461f57c 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -596,7 +596,7 @@ config MEMORY_HOTREMOVE
config MHP_MEMMAP_ON_MEMORY
def_bool y
- depends on MEMORY_HOTPLUG && SPARSEMEM_VMEMMAP
+ depends on MEMORY_HOTPLUG
depends on ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE
endif # MEMORY_HOTPLUG
@@ -1235,9 +1235,7 @@ config ZONE_DMA32
config ZONE_DEVICE
bool "Device memory (pmem, HMM, etc...) hotplug support"
- depends on MEMORY_HOTPLUG
depends on MEMORY_HOTREMOVE
- depends on SPARSEMEM_VMEMMAP
select XARRAY_MULTI
help
@@ -1386,6 +1384,15 @@ config HAVE_ARCH_USERFAULTFD_MINOR
help
Arch has userfaultfd minor fault support
+config USERFAULTFD_RWP
+ def_bool y
+ depends on 64BIT && ARCH_HAS_PTE_PROTNONE && HAVE_ARCH_USERFAULTFD_WP
+ help
+ Userfaultfd read-write protection (UFFDIO_RWPROTECT) delivers a
+ userfaultfd notification on every access -- read or write -- to a
+ protected range, letting userspace observe the working set of a
+ process.
+
menuconfig USERFAULTFD
bool "Enable userfaultfd() system call"
depends on MMU
diff --git a/mm/Makefile b/mm/Makefile
index 4fc713867b9b..8e7e964b99a4 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -50,7 +50,7 @@ endif
obj-y := filemap.o mempool.o oom_kill.o fadvise.o \
maccess.o page-writeback.o folio-compat.o \
- readahead.o swap.o truncate.o vmscan.o shrinker.o \
+ readahead.o folio.o truncate.o vmscan.o shrinker.o \
shmem.o util.o mmzone.o vmstat.o backing-dev.o \
mm_init.o percpu.o slab_common.o \
compaction.o show_mem.o \
diff --git a/mm/compaction.c b/mm/compaction.c
index 4b2318fad4eb..9f81055a358e 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -645,7 +645,6 @@ static unsigned long isolate_freepages_block(struct compact_control *cc,
isolated = __isolate_free_page(page, order);
if (!isolated)
break;
- set_page_private(page, order);
nr_scanned += isolated - 1;
total_isolated += isolated;
@@ -1618,7 +1617,6 @@ static void fast_isolate_freepages(struct compact_control *cc)
/* Isolate the page if available */
if (page) {
if (__isolate_free_page(page, order)) {
- set_page_private(page, order);
nr_isolated = 1 << order;
nr_scanned += nr_isolated - 1;
total_isolated += nr_isolated;
@@ -1847,7 +1845,6 @@ again:
size >>= 1;
list_add(&freepage[size].lru, &cc->freepages[start_order]);
- set_page_private(&freepage[size], start_order);
}
dst = (struct folio *)freepage;
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 3c5a46e1c079..390e00b3685e 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -1917,16 +1917,17 @@ int damon_start(struct damon_ctx **ctxs, int nr_ctxs, bool exclusive)
running_exclusive_ctxs = true;
mutex_unlock(&damon_lock);
+ if (i != nr_ctxs)
+ damon_stop(ctxs, i);
+
return err;
}
/*
* __damon_stop() - Stops monitoring of a given context.
* @ctx: monitoring context
- *
- * Return: 0 on success, negative error code otherwise.
*/
-static int __damon_stop(struct damon_ctx *ctx)
+static void __damon_stop(struct damon_ctx *ctx)
{
struct task_struct *tsk;
@@ -1936,31 +1937,23 @@ static int __damon_stop(struct damon_ctx *ctx)
get_task_struct(tsk);
mutex_unlock(&ctx->kdamond_lock);
kthread_stop_put(tsk);
- return 0;
+ return;
}
mutex_unlock(&ctx->kdamond_lock);
-
- return -EPERM;
}
/**
* damon_stop() - Stops the monitorings for a given group of contexts.
* @ctxs: an array of the pointers for contexts to stop monitoring
* @nr_ctxs: size of @ctxs
- *
- * Return: 0 on success, negative error code otherwise.
*/
-int damon_stop(struct damon_ctx **ctxs, int nr_ctxs)
+void damon_stop(struct damon_ctx **ctxs, int nr_ctxs)
{
- int i, err = 0;
+ int i;
- for (i = 0; i < nr_ctxs; i++) {
+ for (i = 0; i < nr_ctxs; i++)
/* nr_running_ctxs is decremented in kdamond_fn */
- err = __damon_stop(ctxs[i]);
- if (err)
- break;
- }
- return err;
+ __damon_stop(ctxs[i]);
}
/**
@@ -2017,6 +2010,8 @@ int damon_kdamond_pid(struct damon_ctx *ctx)
* @ctx has succeeded. Otherwise, this function could fall into an indefinite
* wait.
*
+ * When this function is failed, the @ctx is guaranteed to be stopped.
+ *
* Return: 0 on success, negative error code otherwise.
*/
int damon_call(struct damon_ctx *ctx, struct damon_call_control *control)
@@ -2029,7 +2024,7 @@ int damon_call(struct damon_ctx *ctx, struct damon_call_control *control)
mutex_lock(&ctx->call_controls_lock);
if (ctx->call_controls_obsolete) {
mutex_unlock(&ctx->call_controls_lock);
- return -ECANCELED;
+ goto canceled;
}
list_add_tail(&control->list, &ctx->call_controls);
mutex_unlock(&ctx->call_controls_lock);
@@ -2037,8 +2032,14 @@ int damon_call(struct damon_ctx *ctx, struct damon_call_control *control)
return 0;
wait_for_completion(&control->completion);
if (control->canceled)
- return -ECANCELED;
+ goto canceled;
return 0;
+
+canceled:
+ while (damon_is_running(ctx))
+ schedule_timeout_idle(msecs_to_jiffies(100));
+ return -ECANCELED;
+
}
/**
diff --git a/mm/damon/lru_sort.c b/mm/damon/lru_sort.c
index 2dd0cd0d2627..e8c389ad3226 100644
--- a/mm/damon/lru_sort.c
+++ b/mm/damon/lru_sort.c
@@ -409,8 +409,10 @@ static int damon_lru_sort_turn(bool on)
{
int err;
- if (!on)
- return damon_stop(&ctx, 1);
+ if (!on) {
+ damon_stop(&ctx, 1);
+ return 0;
+ }
err = damon_lru_sort_apply_parameters();
if (err)
diff --git a/mm/damon/reclaim.c b/mm/damon/reclaim.c
index 6469b25cc34f..09e941d75f67 100644
--- a/mm/damon/reclaim.c
+++ b/mm/damon/reclaim.c
@@ -332,8 +332,10 @@ static int damon_reclaim_turn(bool on)
{
int err;
- if (!on)
- return damon_stop(&ctx, 1);
+ if (!on) {
+ damon_stop(&ctx, 1);
+ return 0;
+ }
err = damon_reclaim_apply_parameters();
if (err)
diff --git a/mm/damon/sysfs.c b/mm/damon/sysfs.c
index b65651498e0d..6d7e36c9e509 100644
--- a/mm/damon/sysfs.c
+++ b/mm/damon/sysfs.c
@@ -2262,12 +2262,13 @@ static int damon_sysfs_turn_damon_off(struct damon_sysfs_kdamond *kdamond)
{
if (!kdamond->damon_ctx)
return -EINVAL;
- return damon_stop(&kdamond->damon_ctx, 1);
+ damon_stop(&kdamond->damon_ctx, 1);
/*
* To allow users show final monitoring results of already turned-off
* DAMON, we free kdamond->damon_ctx in next
* damon_sysfs_turn_damon_on(), or kdamonds_nr_store()
*/
+ return 0;
}
static int damon_sysfs_damon_call(int (*fn)(void *data),
diff --git a/mm/debug_vm_pgtable.c b/mm/debug_vm_pgtable.c
index 7987962950c1..2875fd22d7bb 100644
--- a/mm/debug_vm_pgtable.c
+++ b/mm/debug_vm_pgtable.c
@@ -672,7 +672,7 @@ static void __init pte_protnone_tests(struct pgtable_debug_args *args)
{
pte_t pte = pfn_pte(args->fixed_pte_pfn, args->page_prot_none);
- if (!IS_ENABLED(CONFIG_NUMA_BALANCING))
+ if (!IS_ENABLED(CONFIG_ARCH_HAS_PTE_PROTNONE))
return;
pr_debug("Validating PTE protnone\n");
@@ -685,7 +685,7 @@ static void __init pmd_protnone_tests(struct pgtable_debug_args *args)
{
pmd_t pmd;
- if (!IS_ENABLED(CONFIG_NUMA_BALANCING))
+ if (!IS_ENABLED(CONFIG_ARCH_HAS_PTE_PROTNONE))
return;
if (!has_transparent_hugepage())
diff --git a/mm/swap.c b/mm/folio.c
index d25131305c94..d2937600cf72 100644
--- a/mm/swap.c
+++ b/mm/folio.c
@@ -1,17 +1,13 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * linux/mm/swap.c
+ * linux/mm/folio.c
*
* Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
*/
/*
- * This file contains the default values for the operation of the
- * Linux VM subsystem. Fine-tuning documentation can be found in
- * Documentation/admin-guide/sysctl/vm.rst.
- * Started 18.12.91
- * Swap aging added 23.2.95, Stephen Tweedie.
- * Buffermem limits added 12.3.98, Rik van Riel.
+ * Folio LRU helpers: add/remove folios from LRU lists, batching,
+ * activation/deactivation, and page cache release paths.
*/
#include <linux/mm.h>
@@ -44,10 +40,6 @@
#define CREATE_TRACE_POINTS
#include <trace/events/pagemap.h>
-/* How many pages do we try to swap or page in/out together? As a power of 2 */
-int page_cluster;
-static const int page_cluster_max = 31;
-
struct cpu_fbatches {
/*
* The following folio batches are grouped together because they are protected
@@ -1177,35 +1169,3 @@ void lru_reparent_memcg(struct mem_cgroup *memcg, struct mem_cgroup *parent, int
lruvec_reparent_lru(child_lruvec, parent_lruvec, lru, nid);
}
#endif
-
-static const struct ctl_table swap_sysctl_table[] = {
- {
- .procname = "page-cluster",
- .data = &page_cluster,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = SYSCTL_ZERO,
- .extra2 = (void *)&page_cluster_max,
- }
-};
-
-/*
- * Perform any setup for the swap system
- */
-void __init swap_setup(void)
-{
- unsigned long megs = PAGES_TO_MB(totalram_pages());
-
- /* Use a smaller cluster for small-memory machines */
- if (megs < 16)
- page_cluster = 2;
- else
- page_cluster = 3;
- /*
- * Right now other parts of the system means that we
- * _really_ don't want to cluster much more
- */
-
- register_sysctl_init("vm", swap_sysctl_table);
-}
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index fb2d7dd17de0..25612af72dca 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -1822,8 +1822,8 @@ static void copy_huge_non_present_pmd(
pmd = softleaf_to_pmd(entry);
if (pmd_swp_soft_dirty(*src_pmd))
pmd = pmd_swp_mksoft_dirty(pmd);
- if (pmd_swp_uffd_wp(*src_pmd))
- pmd = pmd_swp_mkuffd_wp(pmd);
+ if (pmd_swp_uffd(*src_pmd))
+ pmd = pmd_swp_mkuffd(pmd);
set_pmd_at(src_mm, addr, src_pmd, pmd);
} else if (softleaf_is_device_private(entry)) {
/*
@@ -1836,8 +1836,8 @@ static void copy_huge_non_present_pmd(
if (pmd_swp_soft_dirty(*src_pmd))
pmd = pmd_swp_mksoft_dirty(pmd);
- if (pmd_swp_uffd_wp(*src_pmd))
- pmd = pmd_swp_mkuffd_wp(pmd);
+ if (pmd_swp_uffd(*src_pmd))
+ pmd = pmd_swp_mkuffd(pmd);
set_pmd_at(src_mm, addr, src_pmd, pmd);
}
@@ -1856,8 +1856,8 @@ static void copy_huge_non_present_pmd(
add_mm_counter(dst_mm, MM_ANONPAGES, HPAGE_PMD_NR);
mm_inc_nr_ptes(dst_mm);
pgtable_trans_huge_deposit(dst_mm, dst_pmd, pgtable);
- if (!userfaultfd_wp(dst_vma))
- pmd = pmd_swp_clear_uffd_wp(pmd);
+ if (!userfaultfd_protected(dst_vma))
+ pmd = pmd_swp_clear_uffd(pmd);
set_pmd_at(dst_mm, addr, dst_pmd, pmd);
}
@@ -1951,9 +1951,15 @@ int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm,
out_zero_page:
mm_inc_nr_ptes(dst_mm);
pgtable_trans_huge_deposit(dst_mm, dst_pmd, pgtable);
+
+ /* See __copy_present_ptes(): restore accessible protection. */
+ if (!userfaultfd_protected(dst_vma)) {
+ if (userfaultfd_rwp(src_vma) && pmd_uffd(pmd))
+ pmd = pmd_modify(pmd, dst_vma->vm_page_prot);
+ pmd = pmd_clear_uffd(pmd);
+ }
+
pmdp_set_wrprotect(src_mm, addr, src_pmd);
- if (!userfaultfd_wp(dst_vma))
- pmd = pmd_clear_uffd_wp(pmd);
pmd = pmd_wrprotect(pmd);
set_pmd:
pmd = pmd_mkold(pmd);
@@ -2196,6 +2202,34 @@ static inline bool can_change_pmd_writable(struct vm_area_struct *vma,
return pmd_dirty(pmd);
}
+vm_fault_t do_huge_pmd_uffd_rwp(struct vm_fault *vmf)
+{
+ struct vm_area_struct *vma = vmf->vma;
+ pmd_t pmd;
+
+ if (!userfaultfd_rwp_async(vma))
+ return handle_userfault(vmf, VM_UFFD_RWP);
+
+ vmf->ptl = pmd_lock(vma->vm_mm, vmf->pmd);
+ if (unlikely(!pmd_same(pmdp_get(vmf->pmd), vmf->orig_pmd))) {
+ spin_unlock(vmf->ptl);
+ return 0;
+ }
+ pmd = pmd_modify(vmf->orig_pmd, vma->vm_page_prot);
+ /* pmd_modify() preserves _PAGE_UFFD; drop it on resolution */
+ pmd = pmd_clear_uffd(pmd);
+ pmd = pmd_mkyoung(pmd);
+ if (!pmd_write(pmd) &&
+ vma_wants_manual_pte_write_upgrade(vma) &&
+ can_change_pmd_writable(vma, vmf->address, pmd))
+ pmd = pmd_mkwrite(pmd, vma);
+ set_pmd_at(vma->vm_mm, vmf->address & HPAGE_PMD_MASK,
+ vmf->pmd, pmd);
+ update_mmu_cache_pmd(vma, vmf->address, vmf->pmd);
+ spin_unlock(vmf->ptl);
+ return 0;
+}
+
/* NUMA hinting page fault entry point for trans huge pmds */
vm_fault_t do_huge_pmd_numa_page(struct vm_fault *vmf)
{
@@ -2494,9 +2528,9 @@ static pmd_t clear_uffd_wp_pmd(pmd_t pmd)
if (pmd_none(pmd))
return pmd;
if (pmd_present(pmd))
- pmd = pmd_clear_uffd_wp(pmd);
+ pmd = pmd_clear_uffd(pmd);
else
- pmd = pmd_swp_clear_uffd_wp(pmd);
+ pmd = pmd_swp_clear_uffd(pmd);
return pmd;
}
@@ -2539,8 +2573,19 @@ bool move_huge_pmd(struct vm_area_struct *vma, unsigned long old_addr,
pgtable_trans_huge_deposit(mm, new_pmd, pgtable);
}
pmd = move_soft_dirty_pmd(pmd);
- if (vma_has_uffd_without_event_remap(vma))
+ if (vma_has_uffd_without_event_remap(vma)) {
+ /*
+ * See __copy_present_ptes(): normalise the RWP marker
+ * so the destination starts accessible instead of
+ * taking a numa-hinting fault on first access. Only the
+ * marker (protnone + uffd) needs it; leave other present
+ * PMDs in the VMA untouched.
+ */
+ if (pmd_present(pmd) && userfaultfd_rwp(vma) &&
+ pmd_uffd(pmd))
+ pmd = pmd_modify(pmd, vma->vm_page_prot);
pmd = clear_uffd_wp_pmd(pmd);
+ }
set_pmd_at(mm, new_addr, new_pmd, pmd);
if (force_flush)
flush_pmd_tlb_range(vma, old_addr, old_addr + PMD_SIZE);
@@ -2553,8 +2598,8 @@ bool move_huge_pmd(struct vm_area_struct *vma, unsigned long old_addr,
}
static void change_non_present_huge_pmd(struct mm_struct *mm,
- unsigned long addr, pmd_t *pmd, bool uffd_wp,
- bool uffd_wp_resolve)
+ unsigned long addr, pmd_t *pmd, bool uffd_prot,
+ bool uffd_prot_resolve)
{
softleaf_t entry = softleaf_from_pmd(*pmd);
pmd_t newpmd;
@@ -2577,16 +2622,16 @@ static void change_non_present_huge_pmd(struct mm_struct *mm,
} else if (softleaf_is_device_private_write(entry)) {
entry = make_readable_device_private_entry(swp_offset(entry));
newpmd = softleaf_to_pmd(entry);
- if (pmd_swp_uffd_wp(*pmd))
- newpmd = pmd_swp_mkuffd_wp(newpmd);
+ if (pmd_swp_uffd(*pmd))
+ newpmd = pmd_swp_mkuffd(newpmd);
} else {
newpmd = *pmd;
}
- if (uffd_wp)
- newpmd = pmd_swp_mkuffd_wp(newpmd);
- else if (uffd_wp_resolve)
- newpmd = pmd_swp_clear_uffd_wp(newpmd);
+ if (uffd_prot)
+ newpmd = pmd_swp_mkuffd(newpmd);
+ else if (uffd_prot_resolve)
+ newpmd = pmd_swp_clear_uffd(newpmd);
if (!pmd_same(*pmd, newpmd))
set_pmd_at(mm, addr, pmd, newpmd);
}
@@ -2606,8 +2651,9 @@ int change_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,
spinlock_t *ptl;
pmd_t oldpmd, entry;
bool prot_numa = cp_flags & MM_CP_PROT_NUMA;
- bool uffd_wp = cp_flags & MM_CP_UFFD_WP;
- bool uffd_wp_resolve = cp_flags & MM_CP_UFFD_WP_RESOLVE;
+ bool uffd_prot = cp_flags & (MM_CP_UFFD_WP | MM_CP_UFFD_RWP);
+ bool uffd_prot_resolve = cp_flags &
+ (MM_CP_UFFD_WP_RESOLVE | MM_CP_UFFD_RWP_RESOLVE);
int ret = 1;
tlb_change_page_size(tlb, HPAGE_PMD_SIZE);
@@ -2620,11 +2666,17 @@ int change_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,
return 0;
if (thp_migration_supported() && pmd_is_valid_softleaf(*pmd)) {
- change_non_present_huge_pmd(mm, addr, pmd, uffd_wp,
- uffd_wp_resolve);
+ change_non_present_huge_pmd(mm, addr, pmd, uffd_prot,
+ uffd_prot_resolve);
goto unlock;
}
+ /* Already in the desired state */
+ if (prot_numa && pmd_protnone(*pmd))
+ goto unlock;
+ if ((cp_flags & MM_CP_UFFD_RWP) && pmd_protnone(*pmd) && pmd_uffd(*pmd))
+ goto unlock;
+
if (prot_numa) {
/*
@@ -2635,9 +2687,6 @@ int change_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,
if (is_huge_zero_pmd(*pmd))
goto unlock;
- if (pmd_protnone(*pmd))
- goto unlock;
-
if (!folio_can_map_prot_numa(pmd_folio(*pmd), vma,
vma_is_single_threaded_private(vma)))
goto unlock;
@@ -2666,15 +2715,19 @@ int change_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,
oldpmd = pmdp_invalidate_ad(vma, addr, pmd);
entry = pmd_modify(oldpmd, newprot);
- if (uffd_wp)
- entry = pmd_mkuffd_wp(entry);
- else if (uffd_wp_resolve)
+ if (uffd_prot)
+ entry = pmd_mkuffd(entry);
+ else if (uffd_prot_resolve)
/*
* Leave the write bit to be handled by PF interrupt
* handler, then things like COW could be properly
* handled.
*/
- entry = pmd_clear_uffd_wp(entry);
+ entry = pmd_clear_uffd(entry);
+
+ /* See change_pte_range(): preserve RWP protection across mprotect() */
+ if (userfaultfd_rwp(vma) && pmd_uffd(entry))
+ entry = pmd_modify(entry, PAGE_NONE);
/* See change_pte_range(). */
if ((cp_flags & MM_CP_TRY_CHANGE_WRITABLE) && !pmd_write(entry) &&
@@ -2714,10 +2767,10 @@ int change_huge_pud(struct mmu_gather *tlb, struct vm_area_struct *vma,
return 1;
/*
- * Huge entries on userfault-wp only works with anonymous, while we
- * don't have anonymous PUDs yet.
+ * Huge entries on userfault-wp or userfault-rwp only work with
+ * anonymous, while we don't have anonymous PUDs yet.
*/
- if (WARN_ON_ONCE(cp_flags & MM_CP_UFFD_WP_ALL))
+ if (WARN_ON_ONCE(cp_flags & (MM_CP_UFFD_WP_ALL | MM_CP_UFFD_RWP_ALL)))
return 1;
ptl = __pud_trans_huge_lock(pudp, vma);
@@ -2843,6 +2896,13 @@ int move_pages_huge_pmd(struct mm_struct *mm, pmd_t *dst_pmd, pmd_t *src_pmd, pm
_dst_pmd = move_soft_dirty_pmd(src_pmdval);
_dst_pmd = clear_uffd_wp_pmd(_dst_pmd);
}
+
+ /* Re-arm RWP on the moved PMD if dst_vma is RWP-registered. */
+ if (userfaultfd_rwp(dst_vma)) {
+ _dst_pmd = pmd_modify(_dst_pmd, PAGE_NONE);
+ _dst_pmd = pmd_mkuffd(_dst_pmd);
+ }
+
set_pmd_at(mm, dst_addr, dst_pmd, _dst_pmd);
src_pgtable = pgtable_trans_huge_withdraw(mm, src_pmd);
@@ -3017,8 +3077,13 @@ static void __split_huge_zero_page_pmd(struct vm_area_struct *vma,
entry = pfn_pte(zero_pfn(addr), vma->vm_page_prot);
entry = pte_mkspecial(entry);
- if (pmd_uffd_wp(old_pmd))
- entry = pte_mkuffd_wp(entry);
+ if (pmd_uffd(old_pmd))
+ entry = pte_mkuffd(entry);
+
+ /* Restore PAGE_NONE so an RWP marker keeps trapping */
+ if (userfaultfd_rwp(vma) && pmd_uffd(old_pmd))
+ entry = pte_modify(entry, PAGE_NONE);
+
VM_BUG_ON(!pte_none(ptep_get(pte)));
set_pte_at(mm, addr, pte, entry);
pte++;
@@ -3104,7 +3169,7 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
folio = page_folio(page);
soft_dirty = pmd_swp_soft_dirty(old_pmd);
- uffd_wp = pmd_swp_uffd_wp(old_pmd);
+ uffd_wp = pmd_swp_uffd(old_pmd);
write = softleaf_is_migration_write(entry);
if (PageAnon(page))
@@ -3120,7 +3185,7 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
folio = page_folio(page);
soft_dirty = pmd_swp_soft_dirty(old_pmd);
- uffd_wp = pmd_swp_uffd_wp(old_pmd);
+ uffd_wp = pmd_swp_uffd(old_pmd);
write = softleaf_is_device_private_write(entry);
anon_exclusive = PageAnonExclusive(page);
@@ -3177,7 +3242,7 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
write = pmd_write(old_pmd);
young = pmd_young(old_pmd);
soft_dirty = pmd_soft_dirty(old_pmd);
- uffd_wp = pmd_uffd_wp(old_pmd);
+ uffd_wp = pmd_uffd(old_pmd);
VM_WARN_ON_FOLIO(!folio_ref_count(folio), folio);
VM_WARN_ON_FOLIO(!folio_test_anon(folio), folio);
@@ -3248,7 +3313,7 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
if (soft_dirty)
entry = pte_swp_mksoft_dirty(entry);
if (uffd_wp)
- entry = pte_swp_mkuffd_wp(entry);
+ entry = pte_swp_mkuffd(entry);
VM_WARN_ON(!pte_none(ptep_get(pte + i)));
set_pte_at(mm, addr, pte + i, entry);
}
@@ -3275,7 +3340,7 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
if (soft_dirty)
entry = pte_swp_mksoft_dirty(entry);
if (uffd_wp)
- entry = pte_swp_mkuffd_wp(entry);
+ entry = pte_swp_mkuffd(entry);
VM_WARN_ON(!pte_none(ptep_get(pte + i)));
set_pte_at(mm, addr, pte + i, entry);
}
@@ -3293,7 +3358,11 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
if (soft_dirty)
entry = pte_mksoft_dirty(entry);
if (uffd_wp)
- entry = pte_mkuffd_wp(entry);
+ entry = pte_mkuffd(entry);
+
+ /* Restore PAGE_NONE so an RWP marker keeps trapping */
+ if (userfaultfd_rwp(vma) && uffd_wp)
+ entry = pte_modify(entry, PAGE_NONE);
for (i = 0; i < HPAGE_PMD_NR; i++)
VM_WARN_ON(!pte_none(ptep_get(pte + i)));
@@ -3591,6 +3660,13 @@ static void __split_folio_to_order(struct folio *folio, int old_order,
new_folio->mapping = folio->mapping;
new_folio->index = folio->index + i;
+ /*
+ * page->private should not be set in tail pages. Warn once
+ * if private is unexpectedly set. Do it before swap.val assignment
+ * since private overlaps with swap.val.
+ */
+ VM_WARN_ON_ONCE_PAGE(new_folio->private, new_head);
+
if (folio_test_swapcache(folio))
new_folio->swap.val = folio->swap.val + i;
@@ -4892,7 +4968,7 @@ int set_pmd_migration_entry(struct page_vma_mapped_walk *pvmw,
writable = pmd_write(pmdval);
softdirty = pmd_soft_dirty(pmdval);
- uffd_wp = pmd_uffd_wp(pmdval);
+ uffd_wp = pmd_uffd(pmdval);
} else {
softleaf_t old_entry;
@@ -4901,7 +4977,7 @@ int set_pmd_migration_entry(struct page_vma_mapped_walk *pvmw,
writable = softleaf_is_device_private_write(old_entry);
softdirty = pmd_swp_soft_dirty(pmdval);
- uffd_wp = pmd_swp_uffd_wp(pmdval);
+ uffd_wp = pmd_swp_uffd(pmdval);
}
/* See folio_try_share_anon_rmap_pmd(): invalidate PMD first. */
@@ -4932,7 +5008,7 @@ int set_pmd_migration_entry(struct page_vma_mapped_walk *pvmw,
if (softdirty)
pmdswp = pmd_swp_mksoft_dirty(pmdswp);
if (uffd_wp)
- pmdswp = pmd_swp_mkuffd_wp(pmdswp);
+ pmdswp = pmd_swp_mkuffd(pmdswp);
set_pmd_at(mm, address, pvmw->pmd, pmdswp);
/* Migration entry installed: cleanup rmap, folio. */
@@ -4964,8 +5040,13 @@ void remove_migration_pmd(struct page_vma_mapped_walk *pvmw, struct page *new)
pmde = pmd_mksoft_dirty(pmde);
if (softleaf_is_migration_write(entry))
pmde = pmd_mkwrite(pmde, vma);
- if (pmd_swp_uffd_wp(*pvmw->pmd))
- pmde = pmd_mkuffd_wp(pmde);
+ if (pmd_swp_uffd(*pvmw->pmd))
+ pmde = pmd_mkuffd(pmde);
+
+ /* See do_swap_page(): restore PAGE_NONE for RWP */
+ if (pmd_swp_uffd(*pvmw->pmd) && userfaultfd_rwp(vma))
+ pmde = pmd_modify(pmde, PAGE_NONE);
+
if (!softleaf_is_migration_young(entry))
pmde = pmd_mkold(pmde);
/* NOTE: this may contain setting soft-dirty on some archs */
@@ -4985,8 +5066,8 @@ void remove_migration_pmd(struct page_vma_mapped_walk *pvmw, struct page *new)
if (pmd_swp_soft_dirty(*pvmw->pmd))
pmde = pmd_swp_mksoft_dirty(pmde);
- if (pmd_swp_uffd_wp(*pvmw->pmd))
- pmde = pmd_swp_mkuffd_wp(pmde);
+ if (pmd_swp_uffd(*pvmw->pmd))
+ pmde = pmd_swp_mkuffd(pmde);
}
if (folio_test_anon(folio)) {
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 910719c7f561..d6c812d1857b 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -4880,8 +4880,16 @@ hugetlb_install_folio(struct vm_area_struct *vma, pte_t *ptep, unsigned long add
__folio_mark_uptodate(new_folio);
hugetlb_add_new_anon_rmap(new_folio, vma, addr);
- if (userfaultfd_wp(vma) && huge_pte_uffd_wp(old))
- newpte = huge_pte_mkuffd_wp(newpte);
+ if (userfaultfd_protected(vma) && huge_pte_uffd(old)) {
+ newpte = huge_pte_mkuffd(newpte);
+ /* Restore PAGE_NONE so the RWP marker keeps trapping. */
+ if (userfaultfd_rwp(vma)) {
+ unsigned int shift = huge_page_shift(hstate_vma(vma));
+
+ newpte = huge_pte_modify(newpte, PAGE_NONE);
+ newpte = arch_make_huge_pte(newpte, shift, vma->vm_flags);
+ }
+ }
set_huge_pte_at(vma->vm_mm, addr, ptep, newpte, sz);
hugetlb_count_add(pages_per_huge_page(hstate_vma(vma)), vma->vm_mm);
folio_set_hugetlb_migratable(new_folio);
@@ -4954,11 +4962,15 @@ again:
softleaf = softleaf_from_pte(entry);
if (unlikely(softleaf_is_hwpoison(softleaf))) {
- if (!userfaultfd_wp(dst_vma))
- entry = pte_swp_clear_uffd_wp(entry);
+ /*
+ * A hwpoison entry never carries the uffd-wp bit: it is
+ * installed fresh by make_hwpoison_entry() and
+ * hugetlb_change_protection() leaves it untouched, so
+ * there is nothing to clear for the child.
+ */
set_huge_pte_at(dst, addr, dst_pte, entry, sz);
} else if (unlikely(softleaf_is_migration(softleaf))) {
- bool uffd_wp = pte_swp_uffd_wp(entry);
+ bool uffd = pte_swp_uffd(entry);
if (!softleaf_is_migration_read(softleaf) && cow) {
/*
@@ -4968,12 +4980,12 @@ again:
softleaf = make_readable_migration_entry(
swp_offset(softleaf));
entry = swp_entry_to_pte(softleaf);
- if (userfaultfd_wp(src_vma) && uffd_wp)
- entry = pte_swp_mkuffd_wp(entry);
+ if (userfaultfd_protected(src_vma) && uffd)
+ entry = pte_swp_mkuffd(entry);
set_huge_pte_at(src, addr, src_pte, entry, sz);
}
- if (!userfaultfd_wp(dst_vma))
- entry = pte_swp_clear_uffd_wp(entry);
+ if (!userfaultfd_protected(dst_vma))
+ entry = pte_swp_clear_uffd(entry);
set_huge_pte_at(dst, addr, dst_pte, entry, sz);
} else if (unlikely(pte_is_marker(entry))) {
const pte_marker marker = copy_pte_marker(softleaf, dst_vma);
@@ -5037,6 +5049,16 @@ again:
goto next;
}
+ /* See __copy_present_ptes(): restore accessible protection. */
+ if (!userfaultfd_protected(dst_vma)) {
+ if (userfaultfd_rwp(src_vma) && huge_pte_uffd(entry)) {
+ entry = huge_pte_modify(entry, dst_vma->vm_page_prot);
+ entry = arch_make_huge_pte(entry, huge_page_shift(h),
+ dst_vma->vm_flags);
+ }
+ entry = huge_pte_clear_uffd(entry);
+ }
+
if (cow) {
/*
* No need to notify as we are downgrading page
@@ -5049,9 +5071,6 @@ again:
entry = huge_pte_wrprotect(entry);
}
- if (!userfaultfd_wp(dst_vma))
- entry = huge_pte_clear_uffd_wp(entry);
-
set_huge_pte_at(dst, addr, dst_pte, entry, sz);
hugetlb_count_add(npages, dst);
}
@@ -5097,10 +5116,23 @@ static void move_huge_pte(struct vm_area_struct *vma, unsigned long old_addr,
huge_pte_clear(mm, new_addr, dst_pte, sz);
} else {
if (need_clear_uffd_wp) {
- if (pte_present(pte))
- pte = huge_pte_clear_uffd_wp(pte);
- else
- pte = pte_swp_clear_uffd_wp(pte);
+ if (pte_present(pte)) {
+ /*
+ * See __copy_present_ptes(): normalise the RWP
+ * marker so the destination starts accessible
+ * instead of taking a numa-hinting fault on
+ * first access. Only the marker (protnone + uffd)
+ * needs it; leave other present PTEs untouched.
+ */
+ if (userfaultfd_rwp(vma) && huge_pte_uffd(pte)) {
+ pte = huge_pte_modify(pte, vma->vm_page_prot);
+ pte = arch_make_huge_pte(pte, huge_page_shift(h),
+ vma->vm_flags);
+ }
+ pte = huge_pte_clear_uffd(pte);
+ } else {
+ pte = pte_swp_clear_uffd(pte);
+ }
}
set_huge_pte_at(mm, new_addr, dst_pte, pte, sz);
}
@@ -5234,7 +5266,7 @@ void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
* drop the uffd-wp bit in this zap, then replace the
* pte with a marker.
*/
- if (pte_swp_uffd_wp_any(pte) &&
+ if (pte_swp_uffd_any(pte) &&
!(zap_flags & ZAP_FLAG_DROP_MARKER))
set_huge_pte_at(mm, address, ptep,
make_pte_marker(PTE_MARKER_UFFD_WP),
@@ -5270,7 +5302,7 @@ void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
if (huge_pte_dirty(pte))
folio_mark_dirty(folio);
/* Leave a uffd-wp pte marker if needed */
- if (huge_pte_uffd_wp(pte) &&
+ if (huge_pte_uffd(pte) &&
!(zap_flags & ZAP_FLAG_DROP_MARKER))
set_huge_pte_at(mm, address, ptep,
make_pte_marker(PTE_MARKER_UFFD_WP),
@@ -5474,7 +5506,7 @@ static vm_fault_t hugetlb_wp(struct vm_fault *vmf)
* can trigger this, because hugetlb_fault() will always resolve
* uffd-wp bit first.
*/
- if (!unshare && huge_pte_uffd_wp(pte))
+ if (!unshare && huge_pte_uffd(pte))
return 0;
/* Let's take out MAP_SHARED mappings first. */
@@ -5618,8 +5650,8 @@ retry_avoidcopy:
huge_ptep_clear_flush(vma, vmf->address, vmf->pte);
hugetlb_remove_rmap(old_folio);
hugetlb_add_new_anon_rmap(new_folio, vma, vmf->address);
- if (huge_pte_uffd_wp(pte))
- newpte = huge_pte_mkuffd_wp(newpte);
+ if (huge_pte_uffd(pte))
+ newpte = huge_pte_mkuffd(newpte);
set_huge_pte_at(mm, vmf->address, vmf->pte, newpte,
huge_page_size(h));
folio_set_hugetlb_migratable(new_folio);
@@ -5897,7 +5929,7 @@ static vm_fault_t hugetlb_no_page(struct address_space *mapping,
* if populated.
*/
if (unlikely(pte_is_uffd_wp_marker(vmf->orig_pte)))
- new_pte = huge_pte_mkuffd_wp(new_pte);
+ new_pte = huge_pte_mkuffd(new_pte);
set_huge_pte_at(mm, vmf->address, vmf->pte, new_pte, huge_page_size(h));
hugetlb_count_add(pages_per_huge_page(h), mm);
@@ -6073,6 +6105,47 @@ vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
}
/*
+ * Protnone hugetlb PTEs with the uffd bit are used by
+ * userfaultfd RWP for access tracking. Plain PROT_NONE (without the
+ * marker) is not an RWP fault and is not expected on hugetlb (no
+ * NUMA hinting), so let normal hugetlb fault handling proceed.
+ */
+ if (pte_protnone(vmf.orig_pte) && vma_is_accessible(vma) &&
+ userfaultfd_rwp(vma) && huge_pte_uffd(vmf.orig_pte)) {
+ spinlock_t *ptl;
+ pte_t pte;
+
+ /* Sync: drop hugetlb locks before blocking in handle_userfault() */
+ if (!userfaultfd_rwp_async(vma))
+ return hugetlb_handle_userfault(&vmf, mapping, VM_UFFD_RWP);
+
+ ptl = huge_pte_lock(h, mm, vmf.pte);
+ pte = huge_ptep_get(mm, vmf.address, vmf.pte);
+ if (pte_protnone(pte) && huge_pte_uffd(pte)) {
+ unsigned int shift = huge_page_shift(h);
+
+ pte = huge_pte_modify(pte, vma->vm_page_prot);
+ pte = arch_make_huge_pte(pte, shift, vma->vm_flags);
+ /* huge_pte_modify() preserves _PAGE_UFFD; drop it on resolution */
+ pte = huge_pte_clear_uffd(pte);
+ pte = pte_mkyoung(pte);
+ /*
+ * Unlike do_uffd_rwp(), do not upgrade to writable
+ * here. Hugetlb lacks a can_change_huge_pte_writable()
+ * equivalent, so a write access will take a separate
+ * COW fault — acceptable for the rare private hugetlb
+ * case.
+ */
+ set_huge_pte_at(mm, vmf.address, vmf.pte, pte,
+ huge_page_size(h));
+ update_mmu_cache(vma, vmf.address, vmf.pte);
+ }
+ spin_unlock(ptl);
+ ret = 0;
+ goto out_mutex;
+ }
+
+ /*
* If we are going to COW/unshare the mapping later, we examine the
* pending reservations for this page now. This will ensure that any
* allocations necessary to record that reservation occur outside the
@@ -6095,7 +6168,7 @@ vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
goto out_ptl;
/* Handle userfault-wp first, before trying to lock more pages */
- if (userfaultfd_wp(vma) && huge_pte_uffd_wp(huge_ptep_get(mm, vmf.address, vmf.pte)) &&
+ if (userfaultfd_wp(vma) && huge_pte_uffd(huge_ptep_get(mm, vmf.address, vmf.pte)) &&
(flags & FAULT_FLAG_WRITE) && !huge_pte_write(vmf.orig_pte)) {
if (!userfaultfd_wp_async(vma)) {
spin_unlock(vmf.ptl);
@@ -6104,7 +6177,7 @@ vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
return handle_userfault(&vmf, VM_UFFD_WP);
}
- vmf.orig_pte = huge_pte_clear_uffd_wp(vmf.orig_pte);
+ vmf.orig_pte = huge_pte_clear_uffd(vmf.orig_pte);
set_huge_pte_at(mm, vmf.address, vmf.pte, vmf.orig_pte,
huge_page_size(hstate_vma(vma)));
/* Fallthrough to CoW */
@@ -6389,7 +6462,7 @@ int hugetlb_mfill_atomic_pte(pte_t *dst_pte,
_dst_pte = pte_mkyoung(_dst_pte);
if (wp_enabled)
- _dst_pte = huge_pte_mkuffd_wp(_dst_pte);
+ _dst_pte = huge_pte_mkuffd(_dst_pte);
set_huge_pte_at(dst_mm, dst_addr, dst_pte, _dst_pte, size);
@@ -6432,6 +6505,8 @@ long hugetlb_change_protection(struct vm_area_struct *vma,
unsigned long last_addr_mask;
bool uffd_wp = cp_flags & MM_CP_UFFD_WP;
bool uffd_wp_resolve = cp_flags & MM_CP_UFFD_WP_RESOLVE;
+ bool uffd_rwp = cp_flags & MM_CP_UFFD_RWP;
+ bool uffd_rwp_resolve = cp_flags & MM_CP_UFFD_RWP_RESOLVE;
struct mmu_gather tlb;
/*
@@ -6457,6 +6532,11 @@ long hugetlb_change_protection(struct vm_area_struct *vma,
ptep = hugetlb_walk(vma, address, psize);
if (!ptep) {
+ /*
+ * uffd_wp installs a pte marker on the unpopulated
+ * entry; uffd_rwp does not install markers so the
+ * allocation is unnecessary for it.
+ */
if (!uffd_wp) {
address |= last_addr_mask;
continue;
@@ -6478,7 +6558,8 @@ long hugetlb_change_protection(struct vm_area_struct *vma,
* shouldn't happen at all. Warn about it if it
* happened due to some reason.
*/
- WARN_ON_ONCE(uffd_wp || uffd_wp_resolve);
+ WARN_ON_ONCE(uffd_wp || uffd_wp_resolve ||
+ uffd_rwp || uffd_rwp_resolve);
pages++;
spin_unlock(ptl);
address |= last_addr_mask;
@@ -6512,10 +6593,10 @@ long hugetlb_change_protection(struct vm_area_struct *vma,
pages++;
}
- if (uffd_wp)
- newpte = pte_swp_mkuffd_wp(newpte);
- else if (uffd_wp_resolve)
- newpte = pte_swp_clear_uffd_wp(newpte);
+ if (uffd_wp || uffd_rwp)
+ newpte = pte_swp_mkuffd(newpte);
+ else if (uffd_wp_resolve || uffd_rwp_resolve)
+ newpte = pte_swp_clear_uffd(newpte);
if (!pte_same(pte, newpte))
set_huge_pte_at(mm, address, ptep, newpte, psize);
} else if (unlikely(pte_is_marker(pte))) {
@@ -6525,20 +6606,32 @@ long hugetlb_change_protection(struct vm_area_struct *vma,
* pte_marker_uffd_wp()==true implies !poison
* because they're mutual exclusive.
*/
- if (pte_is_uffd_wp_marker(pte) && uffd_wp_resolve)
+ if (pte_is_uffd_wp_marker(pte) &&
+ (uffd_wp_resolve || uffd_rwp_resolve))
/* Safe to modify directly (non-present->none). */
huge_pte_clear(mm, address, ptep, psize);
} else {
pte_t old_pte;
unsigned int shift = huge_page_shift(hstate_vma(vma));
+ /* Already protnone with uffd bit set? Nothing to do. */
+ if (uffd_rwp && pte_protnone(pte) && huge_pte_uffd(pte))
+ goto next;
+
old_pte = huge_ptep_modify_prot_start(vma, address, ptep);
pte = huge_pte_modify(old_pte, newprot);
pte = arch_make_huge_pte(pte, shift, vma->vm_flags);
- if (uffd_wp)
- pte = huge_pte_mkuffd_wp(pte);
- else if (uffd_wp_resolve)
- pte = huge_pte_clear_uffd_wp(pte);
+ if (uffd_wp || uffd_rwp)
+ pte = huge_pte_mkuffd(pte);
+ else if (uffd_wp_resolve || uffd_rwp_resolve)
+ pte = huge_pte_clear_uffd(pte);
+
+ /* Preserve RWP protection across mprotect() */
+ if (userfaultfd_rwp(vma) && huge_pte_uffd(pte)) {
+ pte = huge_pte_modify(pte, PAGE_NONE);
+ pte = arch_make_huge_pte(pte, shift, vma->vm_flags);
+ }
+
huge_ptep_modify_prot_commit(vma, address, ptep, old_pte, pte);
pages++;
tlb_remove_huge_tlb_entry(h, &tlb, ptep, address);
@@ -7249,14 +7342,14 @@ void move_hugetlb_state(struct folio *old_folio, struct folio *new_folio,
* There is no need to transfer the per-node surplus state
* when we do not cross the node.
*/
- if (new_nid == old_nid)
- return;
- spin_lock_irq(&hugetlb_lock);
- if (h->surplus_huge_pages_node[old_nid]) {
- h->surplus_huge_pages_node[old_nid]--;
- h->surplus_huge_pages_node[new_nid]++;
+ if (new_nid != old_nid) {
+ spin_lock_irq(&hugetlb_lock);
+ if (h->surplus_huge_pages_node[old_nid]) {
+ h->surplus_huge_pages_node[old_nid]--;
+ h->surplus_huge_pages_node[new_nid]++;
+ }
+ spin_unlock_irq(&hugetlb_lock);
}
- spin_unlock_irq(&hugetlb_lock);
}
/*
diff --git a/mm/internal.h b/mm/internal.h
index 841c27611627..3d30650a8440 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -31,6 +31,73 @@ struct huge_bootmem_page {
unsigned long flags;
};
+/* mm/workingset.c */
+bool workingset_test_recent(void *shadow, bool file, bool *workingset,
+ bool flush);
+void workingset_age_nonresident(struct lruvec *lruvec, unsigned long nr_pages);
+void *workingset_eviction(struct folio *folio,
+ struct mem_cgroup *target_memcg);
+void workingset_refault(struct folio *folio, void *shadow);
+void workingset_activation(struct folio *folio);
+
+/* mm/folio.c */
+void lru_note_cost_unlock_irq(struct lruvec *lruvec, bool file,
+ unsigned int nr_io, unsigned int nr_rotated);
+void lru_note_cost_refault(struct folio *folio);
+void folio_add_lru_vma(struct folio *folio, struct vm_area_struct *vma);
+
+static inline bool folio_may_be_lru_cached(struct folio *folio)
+{
+ /*
+ * Holding PMD-sized folios in per-CPU LRU cache unbalances accounting.
+ * Holding small numbers of low-order mTHP folios in per-CPU LRU cache
+ * will be sensible, but nobody has implemented and tested that yet.
+ */
+ return !folio_test_large(folio);
+}
+
+static inline void lru_cache_enable(void)
+{
+ atomic_dec(&lru_disable_count);
+}
+
+void lru_cache_disable(void);
+void lru_add_drain(void);
+void lru_add_drain_cpu(int cpu);
+void lru_add_drain_cpu_zone(struct zone *zone);
+void folio_deactivate(struct folio *folio);
+void folio_mark_lazyfree(struct folio *folio);
+
+/* mm/vmscan.c */
+unsigned long zone_reclaimable_pages(struct zone *zone);
+unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
+ gfp_t gfp_mask, const nodemask_t *mask);
+unsigned long lruvec_lru_size(struct lruvec *lruvec, enum lru_list lru,
+ int zone_idx);
+
+#define MEMCG_RECLAIM_MAY_SWAP (1 << 1)
+#define MEMCG_RECLAIM_PROACTIVE (1 << 2)
+#define MIN_SWAPPINESS 0
+#define MAX_SWAPPINESS 200
+
+/* Just reclaim from anon folios in proactive memory reclaim */
+#define SWAPPINESS_ANON_ONLY (MAX_SWAPPINESS + 1)
+
+unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg,
+ unsigned long nr_pages,
+ gfp_t gfp_mask,
+ unsigned int reclaim_options,
+ int *swappiness);
+unsigned long mem_cgroup_shrink_node(struct mem_cgroup *memcg,
+ gfp_t gfp_mask, bool noswap,
+ pg_data_t *pgdat,
+ unsigned long *nr_scanned);
+
+#ifdef CONFIG_NUMA
+extern int sysctl_min_unmapped_ratio;
+extern int sysctl_min_slab_ratio;
+#endif
+
/*
* Maintains state across a page table move. The operation assumes both source
* and destination VMAs already exist and are specified by the user.
@@ -419,8 +486,8 @@ static inline pte_t pte_move_swp_offset(pte_t pte, long delta)
new = pte_swp_mksoft_dirty(new);
if (pte_swp_exclusive(pte))
new = pte_swp_mkexclusive(new);
- if (pte_swp_uffd_wp(pte))
- new = pte_swp_mkuffd_wp(new);
+ if (pte_swp_uffd(pte))
+ new = pte_swp_mkuffd(new);
return new;
}
@@ -741,7 +808,7 @@ static inline void prep_compound_tail(struct page *tail,
{
tail->mapping = TAIL_MAPPING;
set_compound_head(tail, head, order);
- set_page_private(tail, 0);
+ VM_WARN_ON_ONCE(tail->private);
}
static inline void init_compound_tail(struct page *tail,
diff --git a/mm/khugepaged.c b/mm/khugepaged.c
index 58e14d1543ec..55157567dc4c 100644
--- a/mm/khugepaged.c
+++ b/mm/khugepaged.c
@@ -38,7 +38,7 @@ enum scan_result {
SCAN_EXCEED_SWAP_PTE,
SCAN_EXCEED_SHARED_PTE,
SCAN_PTE_NON_PRESENT,
- SCAN_PTE_UFFD_WP,
+ SCAN_PTE_UFFD,
SCAN_PTE_MAPPED_HUGEPAGE,
SCAN_LACK_REFERENCED_PAGE,
SCAN_PAGE_NULL,
@@ -696,8 +696,8 @@ static enum scan_result __collapse_huge_page_isolate(struct vm_area_struct *vma,
result = SCAN_PTE_NON_PRESENT;
goto out;
}
- if (pte_uffd_wp(pteval)) {
- result = SCAN_PTE_UFFD_WP;
+ if (pte_uffd(pteval)) {
+ result = SCAN_PTE_UFFD;
goto out;
}
page = vm_normal_page(vma, addr, pteval);
@@ -1544,7 +1544,7 @@ static enum scan_result mthp_collapse(struct mm_struct *mm,
case SCAN_PAGE_NULL:
case SCAN_DEL_PAGE_LRU:
case SCAN_PTE_NON_PRESENT:
- case SCAN_PTE_UFFD_WP:
+ case SCAN_PTE_UFFD:
case SCAN_PAGE_LAZYFREE:
last_result = ret;
goto next_order;
@@ -1665,15 +1665,15 @@ static enum scan_result collapse_scan_pmd(struct mm_struct *mm,
/*
* Always be strict with uffd-wp
* enabled swap entries. Please see
- * comment below for pte_uffd_wp().
+ * comment below for pte_uffd().
*/
- if (pte_swp_uffd_wp_any(pteval)) {
- result = SCAN_PTE_UFFD_WP;
+ if (pte_swp_uffd_any(pteval)) {
+ result = SCAN_PTE_UFFD;
goto out_unmap;
}
continue;
}
- if (pte_uffd_wp(pteval)) {
+ if (pte_uffd(pteval)) {
/*
* Don't collapse the page if any of the small
* PTEs are armed with uffd write protection.
@@ -1683,7 +1683,7 @@ static enum scan_result collapse_scan_pmd(struct mm_struct *mm,
* userfault messages that falls outside of
* the registered range. So, just be simple.
*/
- result = SCAN_PTE_UFFD_WP;
+ result = SCAN_PTE_UFFD;
goto out_unmap;
}
@@ -1893,9 +1893,12 @@ static enum scan_result try_collapse_pte_mapped_thp(struct mm_struct *mm, unsign
if (!thp_vma_allowable_order(vma, vma->vm_flags, TVA_FORCED_COLLAPSE, PMD_ORDER))
return SCAN_VMA_CHECK;
- /* Keep pmd pgtable for uffd-wp; see comment in retract_page_tables() */
- if (userfaultfd_wp(vma))
- return SCAN_PTE_UFFD_WP;
+ /*
+ * Keep pmd pgtable while the uffd bit is in use; see comment in
+ * retract_page_tables().
+ */
+ if (userfaultfd_protected(vma))
+ return SCAN_PTE_UFFD;
folio = filemap_lock_folio(vma->vm_file->f_mapping,
linear_page_index(vma, haddr));
@@ -2107,13 +2110,14 @@ static bool file_backed_vma_is_retractable(struct vm_area_struct *vma)
return false;
/*
- * When a vma is registered with uffd-wp, we cannot recycle
+ * When a vma is registered with uffd-wp or RWP, we cannot recycle
* the page table because there may be pte markers installed.
- * Other vmas can still have the same file mapped hugely, but
- * skip this one: it will always be mapped in small page size
- * for uffd-wp registered ranges.
+ * VM_UFFD_RWP ranges similarly rely on per-PTE uffd state
+ * and cannot be recycled to a shared PMD. Other vmas can still
+ * have the same file mapped hugely, but skip this one: it will
+ * always be mapped in small page size for these registrations.
*/
- if (userfaultfd_wp(vma))
+ if (userfaultfd_protected(vma))
return false;
/*
@@ -3242,7 +3246,7 @@ int madvise_collapse(struct vm_area_struct *vma, unsigned long start,
/* Whitelisted set of results where continuing OK */
case SCAN_NO_PTE_TABLE:
case SCAN_PTE_NON_PRESENT:
- case SCAN_PTE_UFFD_WP:
+ case SCAN_PTE_UFFD:
case SCAN_LACK_REFERENCED_PAGE:
case SCAN_PAGE_NULL:
case SCAN_PAGE_COUNT:
diff --git a/mm/memfd.c b/mm/memfd.c
index abe13b291ddc..6c72fe6caef7 100644
--- a/mm/memfd.c
+++ b/mm/memfd.c
@@ -19,6 +19,7 @@
#include <linux/memfd.h>
#include <linux/pid_namespace.h>
#include <uapi/linux/memfd.h>
+#include "internal.h"
#include "swap.h"
/*
diff --git a/mm/memory.c b/mm/memory.c
index 6637c5b13c9b..87db93f35bcf 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -893,8 +893,12 @@ static void restore_exclusive_pte(struct vm_area_struct *vma,
if (pte_swp_soft_dirty(orig_pte))
pte = pte_mksoft_dirty(pte);
- if (pte_swp_uffd_wp(orig_pte))
- pte = pte_mkuffd_wp(pte);
+ if (pte_swp_uffd(orig_pte))
+ pte = pte_mkuffd(pte);
+
+ /* See do_swap_page(): restore PAGE_NONE for RWP */
+ if (pte_swp_uffd(orig_pte) && userfaultfd_rwp(vma))
+ pte = pte_modify(pte, PAGE_NONE);
if ((vma->vm_flags & VM_WRITE) &&
can_change_pte_writable(vma, address, pte)) {
@@ -977,8 +981,8 @@ copy_nonpresent_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,
pte = softleaf_to_pte(entry);
if (pte_swp_soft_dirty(orig_pte))
pte = pte_swp_mksoft_dirty(pte);
- if (pte_swp_uffd_wp(orig_pte))
- pte = pte_swp_mkuffd_wp(pte);
+ if (pte_swp_uffd(orig_pte))
+ pte = pte_swp_mkuffd(pte);
set_pte_at(src_mm, addr, src_pte, pte);
}
} else if (softleaf_is_device_private(entry)) {
@@ -1011,8 +1015,8 @@ copy_nonpresent_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,
entry = make_readable_device_private_entry(
swp_offset(entry));
pte = swp_entry_to_pte(entry);
- if (pte_swp_uffd_wp(orig_pte))
- pte = pte_swp_mkuffd_wp(pte);
+ if (pte_swp_uffd(orig_pte))
+ pte = pte_swp_mkuffd(pte);
set_pte_at(src_mm, addr, src_pte, pte);
}
} else if (softleaf_is_device_exclusive(entry)) {
@@ -1034,8 +1038,8 @@ copy_nonpresent_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,
make_pte_marker(marker));
return 0;
}
- if (!userfaultfd_wp(dst_vma))
- pte = pte_swp_clear_uffd_wp(pte);
+ if (!userfaultfd_protected(dst_vma))
+ pte = pte_swp_clear_uffd(pte);
set_pte_at(dst_mm, addr, dst_pte, pte);
return 0;
}
@@ -1081,9 +1085,13 @@ copy_present_page(struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma
/* All done, just insert the new page copy in the child */
pte = folio_mk_pte(new_folio, dst_vma->vm_page_prot);
pte = maybe_mkwrite(pte_mkdirty(pte), dst_vma);
- if (userfaultfd_pte_wp(dst_vma, ptep_get(src_pte)))
- /* Uffd-wp needs to be delivered to dest pte as well */
- pte = pte_mkuffd_wp(pte);
+ if (userfaultfd_protected(dst_vma) && pte_uffd(ptep_get(src_pte))) {
+ /* The uffd bit needs to be delivered to the dest pte as well */
+ pte = pte_mkuffd(pte);
+ /* Restore PAGE_NONE so the RWP marker keeps trapping */
+ if (userfaultfd_rwp(dst_vma))
+ pte = pte_modify(pte, PAGE_NONE);
+ }
set_pte_at(dst_vma->vm_mm, addr, dst_pte, pte);
return 0;
}
@@ -1093,9 +1101,31 @@ static __always_inline void __copy_present_ptes(struct vm_area_struct *dst_vma,
pte_t pte, unsigned long addr, int nr)
{
struct mm_struct *src_mm = src_vma->vm_mm;
+ bool writable;
+
+ /*
+ * Snapshot writability before the RWP-disarm rewrite below: when the
+ * child is not RWP-armed, pte_modify(pte, dst_vma->vm_page_prot) can
+ * silently drop _PAGE_RW from a resolved (no-marker) writable PTE,
+ * so a later pte_write(pte) check would skip the COW wrprotect and
+ * leave the parent writable over a folio shared with the child.
+ */
+ writable = pte_write(pte);
+
+ /*
+ * Child is not RWP-armed: restore accessible protection so the
+ * inherited PAGE_NONE does not cost a fault on first read. Gate on
+ * pte_uffd(pte) so unrelated PAGE_NONE markers (e.g. NUMA balancing)
+ * are not normalised away.
+ */
+ if (!userfaultfd_protected(dst_vma)) {
+ if (userfaultfd_rwp(src_vma) && pte_uffd(pte))
+ pte = pte_modify(pte, dst_vma->vm_page_prot);
+ pte = pte_clear_uffd(pte);
+ }
/* If it's a COW mapping, write protect it both processes. */
- if (is_cow_mapping(src_vma->vm_flags) && pte_write(pte)) {
+ if (is_cow_mapping(src_vma->vm_flags) && writable) {
wrprotect_ptes(src_mm, addr, src_pte, nr);
pte = pte_wrprotect(pte);
}
@@ -1105,9 +1135,6 @@ static __always_inline void __copy_present_ptes(struct vm_area_struct *dst_vma,
pte = pte_mkclean(pte);
pte = pte_mkold(pte);
- if (!userfaultfd_wp(dst_vma))
- pte = pte_clear_uffd_wp(pte);
-
set_ptes(dst_vma->vm_mm, addr, dst_pte, pte, nr);
}
@@ -3918,8 +3945,8 @@ static vm_fault_t wp_page_copy(struct vm_fault *vmf)
if (unlikely(unshare)) {
if (pte_soft_dirty(vmf->orig_pte))
entry = pte_mksoft_dirty(entry);
- if (pte_uffd_wp(vmf->orig_pte))
- entry = pte_mkuffd_wp(entry);
+ if (pte_uffd(vmf->orig_pte))
+ entry = pte_mkuffd(entry);
} else {
entry = maybe_mkwrite(pte_mkdirty(entry), vma);
}
@@ -4174,6 +4201,9 @@ static bool __wp_can_reuse_large_anon_folio(struct folio *folio,
static bool wp_can_reuse_anon_folio(struct folio *folio,
struct vm_area_struct *vma)
{
+ const bool maybe_in_lru_cache = !folio_test_lru(folio);
+ const bool in_swapcache = folio_test_swapcache(folio);
+
if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) && folio_test_large(folio))
return __wp_can_reuse_large_anon_folio(folio, vma);
@@ -4184,15 +4214,16 @@ static bool wp_can_reuse_anon_folio(struct folio *folio,
*
* KSM doesn't necessarily raise the folio refcount.
*/
- if (folio_test_ksm(folio) || folio_ref_count(folio) > 3)
+ if (folio_test_ksm(folio) ||
+ folio_ref_count(folio) > 1 + maybe_in_lru_cache + in_swapcache)
return false;
- if (!folio_test_lru(folio))
+ if (maybe_in_lru_cache)
/*
* We cannot easily detect+handle references from
* remote LRU caches or references to LRU folios.
*/
lru_add_drain();
- if (folio_ref_count(folio) > 1 + folio_test_swapcache(folio))
+ if (folio_ref_count(folio) > 1 + in_swapcache)
return false;
if (!folio_trylock(folio))
return false;
@@ -4254,7 +4285,7 @@ static vm_fault_t do_wp_page(struct vm_fault *vmf)
* etc.) because we're only removing the uffd-wp bit,
* which is completely invisible to the user.
*/
- pte = pte_clear_uffd_wp(ptep_get(vmf->pte));
+ pte = pte_clear_uffd(ptep_get(vmf->pte));
set_pte_at(vma->vm_mm, vmf->address, vmf->pte, pte);
/*
@@ -4505,7 +4536,7 @@ static vm_fault_t remove_device_exclusive_entry(struct vm_fault *vmf)
static inline bool should_try_to_free_swap(struct swap_info_struct *si,
struct folio *folio,
struct vm_area_struct *vma,
- unsigned int extra_refs,
+ bool exclusive,
unsigned int fault_flags)
{
if (!folio_test_swapcache(folio))
@@ -4521,14 +4552,12 @@ static inline bool should_try_to_free_swap(struct swap_info_struct *si,
if (mem_cgroup_swap_full(folio) || (vma->vm_flags & VM_LOCKED) ||
folio_test_mlocked(folio))
return true;
+
/*
- * If we want to map a page that's in the swapcache writable, we
- * have to detect via the refcount if we're really the exclusive
- * user. Try freeing the swapcache to get rid of the swapcache
- * reference only in case it's likely that we'll be the exclusive user.
+ * Free the swapcache only if we are the exclusive user and
+ * this is a write fault.
*/
- return (fault_flags & FAULT_FLAG_WRITE) && !folio_test_ksm(folio) &&
- folio_ref_count(folio) == (extra_refs + folio_nr_pages(folio));
+ return (fault_flags & FAULT_FLAG_WRITE) && exclusive;
}
static vm_fault_t pte_marker_clear(struct vm_fault *vmf)
@@ -4745,6 +4774,7 @@ vm_fault_t do_swap_page(struct vm_fault *vmf)
struct swap_info_struct *si = NULL;
rmap_t rmap_flags = RMAP_NONE;
bool exclusive = false;
+ bool rwp_restore = false;
softleaf_t entry;
pte_t pte;
vm_fault_t ret = 0;
@@ -4890,16 +4920,6 @@ vm_fault_t do_swap_page(struct vm_fault *vmf)
} else if (folio != swapcache)
page = folio_page(folio, 0);
- /*
- * If we want to map a page that's in the swapcache writable, we
- * have to detect via the refcount if we're really the exclusive
- * owner. Try removing the extra reference from the local LRU
- * caches if required.
- */
- if ((vmf->flags & FAULT_FLAG_WRITE) &&
- !folio_test_ksm(folio) && !folio_test_lru(folio))
- lru_add_drain();
-
folio_throttle_swaprate(folio, GFP_KERNEL);
/*
@@ -5031,24 +5051,34 @@ check_folio:
pte = mk_pte(page, vma->vm_page_prot);
if (pte_swp_soft_dirty(vmf->orig_pte))
pte = pte_mksoft_dirty(pte);
- if (pte_swp_uffd_wp(vmf->orig_pte))
- pte = pte_mkuffd_wp(pte);
+ if (pte_swp_uffd(vmf->orig_pte))
+ pte = pte_mkuffd(pte);
+
+ /*
+ * A page reclaimed while RWP-protected carries the uffd bit on
+ * its swap entry. Re-apply PAGE_NONE on swap-in so the first access
+ * still traps as an RWP fault. pte_modify() preserves _PAGE_UFFD.
+ */
+ if (pte_swp_uffd(vmf->orig_pte) && userfaultfd_rwp(vma)) {
+ pte = pte_modify(pte, PAGE_NONE);
+ rwp_restore = true;
+ }
/*
- * Same logic as in do_wp_page(); however, optimize for pages that are
- * certainly not shared either because we just allocated them without
- * exposing them to the swapcache or because the swap entry indicates
- * exclusivity.
+ * Similar logic as in do_wp_page(); however, optimize for pages that
+ * are certainly exclusive.
+ *
+ * Skip the write upgrade for an RWP-restored pte: it must stay
+ * PROT_NONE so the access retries through the RWP fault path
+ * (do_uffd_rwp()) rather than being made writable here.
*/
- if (!folio_test_ksm(folio) &&
- (exclusive || folio_ref_count(folio) == 1)) {
- if ((vma->vm_flags & VM_WRITE) && !userfaultfd_pte_wp(vma, pte) &&
+ if (exclusive) {
+ if (!rwp_restore &&
+ (vma->vm_flags & VM_WRITE) && !userfaultfd_pte_wp(vma, pte) &&
!pte_needs_soft_dirty_wp(vma, pte)) {
pte = pte_mkwrite(pte, vma);
- if (vmf->flags & FAULT_FLAG_WRITE) {
+ if (vmf->flags & FAULT_FLAG_WRITE)
pte = pte_mkdirty(pte);
- vmf->flags &= ~FAULT_FLAG_WRITE;
- }
}
rmap_flags |= RMAP_EXCLUSIVE;
}
@@ -5088,7 +5118,7 @@ check_folio:
* Do it after mapping, so raced page faults will likely see the folio
* in swap cache and wait on the folio lock.
*/
- if (should_try_to_free_swap(si, folio, vma, nr_pages, vmf->flags))
+ if (should_try_to_free_swap(si, folio, vma, exclusive, vmf->flags))
folio_free_swap(folio);
folio_unlock(folio);
@@ -5105,7 +5135,12 @@ check_folio:
folio_put(swapcache);
}
- if (vmf->flags & FAULT_FLAG_WRITE) {
+ /*
+ * For an RWP-restored pte, leave it PROT_NONE and let the write
+ * retry through the RWP fault path; do not COW it here, which would
+ * drop the marker for a non-exclusive page.
+ */
+ if ((vmf->flags & FAULT_FLAG_WRITE) && !pte_write(pte) && !rwp_restore) {
ret |= do_wp_page(vmf);
if (ret & VM_FAULT_ERROR)
ret &= VM_FAULT_ERROR;
@@ -5252,7 +5287,7 @@ void map_anon_folio_pte_nopf(struct folio *folio, pte_t *pte,
if (vma->vm_flags & VM_WRITE)
entry = pte_mkwrite(pte_mkdirty(entry), vma);
if (uffd_wp)
- entry = pte_mkuffd_wp(entry);
+ entry = pte_mkuffd(entry);
folio_ref_add(folio, nr_pages - 1);
folio_add_new_anon_rmap(folio, vma, addr, RMAP_EXCLUSIVE);
@@ -5319,7 +5354,7 @@ static vm_fault_t do_anonymous_page(struct vm_fault *vmf)
return handle_userfault(vmf, VM_UFFD_MISSING);
}
if (vmf_orig_pte_uffd_wp(vmf))
- entry = pte_mkuffd_wp(entry);
+ entry = pte_mkuffd(entry);
set_pte_at(vma->vm_mm, addr, vmf->pte, entry);
/* No need to invalidate - it was non-present before */
@@ -5569,7 +5604,7 @@ void set_pte_range(struct vm_fault *vmf, struct folio *folio,
else if (pte_write(entry) && folio_test_dirty(folio))
entry = pte_mkdirty(entry);
if (unlikely(vmf_orig_pte_uffd_wp(vmf)))
- entry = pte_mkuffd_wp(entry);
+ entry = pte_mkuffd(entry);
/* copy-on-write page */
if (write && !(vma->vm_flags & VM_SHARED)) {
VM_BUG_ON_FOLIO(nr != 1, folio);
@@ -6084,6 +6119,16 @@ static void numa_rebuild_large_mapping(struct vm_fault *vmf, struct vm_area_stru
if (!pte_present(ptent) || !pte_protnone(ptent))
continue;
+ /*
+ * RWP-armed PTEs are also protnone but carry _PAGE_UFFD as a
+ * marker. Leave them alone -- rewriting to vm_page_prot would
+ * stop the RWP trap. Gate on userfaultfd_rwp(vma) too:
+ * NUMA balancing preserves _PAGE_UFFD on UFFD_WP-marked PTEs
+ * when applying PROT_NONE, and those still need rebuilding.
+ */
+ if (userfaultfd_rwp(vma) && pte_uffd(ptent))
+ continue;
+
if (pfn_folio(pte_pfn(ptent)) != folio)
continue;
@@ -6099,6 +6144,35 @@ static void numa_rebuild_large_mapping(struct vm_fault *vmf, struct vm_area_stru
}
}
+static vm_fault_t do_uffd_rwp(struct vm_fault *vmf)
+{
+ pte_t pte;
+
+ if (!userfaultfd_rwp_async(vmf->vma)) {
+ /* Sync mode: unmap PTE and deliver to userfaultfd handler */
+ pte_unmap(vmf->pte);
+ return handle_userfault(vmf, VM_UFFD_RWP);
+ }
+
+ spin_lock(vmf->ptl);
+ if (unlikely(!pte_same(ptep_get(vmf->pte), vmf->orig_pte))) {
+ pte_unmap_unlock(vmf->pte, vmf->ptl);
+ return 0;
+ }
+ pte = pte_modify(vmf->orig_pte, vmf->vma->vm_page_prot);
+ /* pte_modify() preserves _PAGE_UFFD; drop it on resolution */
+ pte = pte_clear_uffd(pte);
+ pte = pte_mkyoung(pte);
+ if (!pte_write(pte) &&
+ vma_wants_manual_pte_write_upgrade(vmf->vma) &&
+ can_change_pte_writable(vmf->vma, vmf->address, pte))
+ pte = pte_mkwrite(pte, vmf->vma);
+ set_pte_at(vmf->vma->vm_mm, vmf->address, vmf->pte, pte);
+ update_mmu_cache(vmf->vma, vmf->address, vmf->pte);
+ pte_unmap_unlock(vmf->pte, vmf->ptl);
+ return 0;
+}
+
static vm_fault_t do_numa_page(struct vm_fault *vmf)
{
struct vm_area_struct *vma = vmf->vma;
@@ -6374,8 +6448,16 @@ static vm_fault_t handle_pte_fault(struct vm_fault *vmf)
if (!pte_present(vmf->orig_pte))
return do_swap_page(vmf);
- if (pte_protnone(vmf->orig_pte) && vma_is_accessible(vmf->vma))
+ if (pte_protnone(vmf->orig_pte) && vma_is_accessible(vmf->vma)) {
+ /*
+ * RWP-protected PTEs are protnone plus the uffd bit. On a
+ * VM_UFFD_RWP VMA, a protnone PTE without the uffd bit is
+ * NUMA hinting and must still fall through to do_numa_page().
+ */
+ if (userfaultfd_pte_rwp(vmf->vma, vmf->orig_pte))
+ return do_uffd_rwp(vmf);
return do_numa_page(vmf);
+ }
spin_lock(vmf->ptl);
entry = vmf->orig_pte;
@@ -6489,8 +6571,11 @@ retry_pud:
return 0;
}
if (pmd_trans_huge(vmf.orig_pmd)) {
- if (pmd_protnone(vmf.orig_pmd) && vma_is_accessible(vma))
+ if (pmd_protnone(vmf.orig_pmd) && vma_is_accessible(vma)) {
+ if (userfaultfd_huge_pmd_rwp(vma, vmf.orig_pmd))
+ return do_huge_pmd_uffd_rwp(&vmf);
return do_huge_pmd_numa_page(&vmf);
+ }
if ((flags & (FAULT_FLAG_WRITE|FAULT_FLAG_UNSHARE)) &&
!pmd_write(vmf.orig_pmd)) {
diff --git a/mm/migrate.c b/mm/migrate.c
index bcf98653740f..222c8c15f782 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -327,8 +327,12 @@ static bool try_to_map_unused_to_zeropage(struct page_vma_mapped_walk *pvmw,
if (pte_swp_soft_dirty(old_pte))
newpte = pte_mksoft_dirty(newpte);
- if (pte_swp_uffd_wp(old_pte))
- newpte = pte_mkuffd_wp(newpte);
+ if (pte_swp_uffd(old_pte))
+ newpte = pte_mkuffd(newpte);
+
+ /* See remove_migration_pte(): restore PAGE_NONE for RWP */
+ if (pte_swp_uffd(old_pte) && userfaultfd_rwp(pvmw->vma))
+ newpte = pte_modify(newpte, PAGE_NONE);
set_pte_at(pvmw->vma->vm_mm, pvmw->address, pvmw->pte, newpte);
@@ -396,8 +400,12 @@ static bool remove_migration_pte(struct folio *folio,
if (softleaf_is_migration_write(entry))
pte = pte_mkwrite(pte, vma);
- else if (pte_swp_uffd_wp(old_pte))
- pte = pte_mkuffd_wp(pte);
+ else if (pte_swp_uffd(old_pte))
+ pte = pte_mkuffd(pte);
+
+ /* See do_swap_page(): restore PAGE_NONE for RWP */
+ if (pte_swp_uffd(old_pte) && userfaultfd_rwp(vma))
+ pte = pte_modify(pte, PAGE_NONE);
if (folio_test_anon(folio) && !softleaf_is_migration_read(entry))
rmap_flags |= RMAP_EXCLUSIVE;
@@ -412,8 +420,8 @@ static bool remove_migration_pte(struct folio *folio,
pte = softleaf_to_pte(entry);
if (pte_swp_soft_dirty(old_pte))
pte = pte_swp_mksoft_dirty(pte);
- if (pte_swp_uffd_wp(old_pte))
- pte = pte_swp_mkuffd_wp(pte);
+ if (pte_swp_uffd(old_pte))
+ pte = pte_swp_mkuffd(pte);
}
#ifdef CONFIG_HUGETLB_PAGE
diff --git a/mm/migrate_device.c b/mm/migrate_device.c
index 2fffeb1f9969..18d097c38853 100644
--- a/mm/migrate_device.c
+++ b/mm/migrate_device.c
@@ -456,13 +456,13 @@ again:
if (pte_present(pte)) {
if (pte_soft_dirty(pte))
swp_pte = pte_swp_mksoft_dirty(swp_pte);
- if (pte_uffd_wp(pte))
- swp_pte = pte_swp_mkuffd_wp(swp_pte);
+ if (pte_uffd(pte))
+ swp_pte = pte_swp_mkuffd(swp_pte);
} else {
if (pte_swp_soft_dirty(pte))
swp_pte = pte_swp_mksoft_dirty(swp_pte);
- if (pte_swp_uffd_wp(pte))
- swp_pte = pte_swp_mkuffd_wp(swp_pte);
+ if (pte_swp_uffd(pte))
+ swp_pte = pte_swp_mkuffd(swp_pte);
}
set_pte_at(mm, addr, ptep, swp_pte);
diff --git a/mm/mprotect.c b/mm/mprotect.c
index cec2a1eed539..dc27bbc1712f 100644
--- a/mm/mprotect.c
+++ b/mm/mprotect.c
@@ -214,8 +214,9 @@ static __always_inline void set_write_prot_commit_flush_ptes(struct vm_area_stru
static long change_softleaf_pte(struct vm_area_struct *vma,
unsigned long addr, pte_t *pte, pte_t oldpte, unsigned long cp_flags)
{
- const bool uffd_wp = cp_flags & MM_CP_UFFD_WP;
- const bool uffd_wp_resolve = cp_flags & MM_CP_UFFD_WP_RESOLVE;
+ const bool uffd_prot = cp_flags & (MM_CP_UFFD_WP | MM_CP_UFFD_RWP);
+ const bool uffd_prot_resolve = cp_flags &
+ (MM_CP_UFFD_WP_RESOLVE | MM_CP_UFFD_RWP_RESOLVE);
softleaf_t entry = softleaf_from_pte(oldpte);
pte_t newpte;
@@ -240,8 +241,8 @@ static long change_softleaf_pte(struct vm_area_struct *vma,
*/
entry = make_readable_device_private_entry(swp_offset(entry));
newpte = swp_entry_to_pte(entry);
- if (pte_swp_uffd_wp(oldpte))
- newpte = pte_swp_mkuffd_wp(newpte);
+ if (pte_swp_uffd(oldpte))
+ newpte = pte_swp_mkuffd(newpte);
} else if (softleaf_is_marker(entry)) {
/*
* Ignore error swap entries unconditionally,
@@ -256,7 +257,7 @@ static long change_softleaf_pte(struct vm_area_struct *vma,
* to unprotect it, drop it; the next page
* fault will trigger without uffd trapping.
*/
- if (uffd_wp_resolve) {
+ if (uffd_prot_resolve) {
pte_clear(vma->vm_mm, addr, pte);
return 1;
}
@@ -265,10 +266,10 @@ static long change_softleaf_pte(struct vm_area_struct *vma,
newpte = oldpte;
}
- if (uffd_wp)
- newpte = pte_swp_mkuffd_wp(newpte);
- else if (uffd_wp_resolve)
- newpte = pte_swp_clear_uffd_wp(newpte);
+ if (uffd_prot)
+ newpte = pte_swp_mkuffd(newpte);
+ else if (uffd_prot_resolve)
+ newpte = pte_swp_clear_uffd(newpte);
if (!pte_same(oldpte, newpte)) {
set_pte_at(vma->vm_mm, addr, pte, newpte);
@@ -282,17 +283,28 @@ static __always_inline void change_present_ptes(struct mmu_gather *tlb,
int nr_ptes, unsigned long end, pgprot_t newprot,
struct folio *folio, struct page *page, unsigned long cp_flags)
{
- const bool uffd_wp_resolve = cp_flags & MM_CP_UFFD_WP_RESOLVE;
- const bool uffd_wp = cp_flags & MM_CP_UFFD_WP;
+ const bool uffd_prot = cp_flags & (MM_CP_UFFD_WP | MM_CP_UFFD_RWP);
+ const bool uffd_prot_resolve = cp_flags &
+ (MM_CP_UFFD_WP_RESOLVE | MM_CP_UFFD_RWP_RESOLVE);
pte_t ptent, oldpte;
oldpte = modify_prot_start_ptes(vma, addr, ptep, nr_ptes);
ptent = pte_modify(oldpte, newprot);
- if (uffd_wp)
- ptent = pte_mkuffd_wp(ptent);
- else if (uffd_wp_resolve)
- ptent = pte_clear_uffd_wp(ptent);
+ if (uffd_prot)
+ ptent = pte_mkuffd(ptent);
+ else if (uffd_prot_resolve)
+ ptent = pte_clear_uffd(ptent);
+
+ /*
+ * The uffd bit on a VM_UFFD_RWP VMA carries PROT_NONE
+ * semantics. If mprotect() or NUMA hinting changed the
+ * base protection, restore PAGE_NONE so the PTE still
+ * traps on any access. pte_modify() preserves
+ * _PAGE_UFFD.
+ */
+ if (userfaultfd_rwp(vma) && pte_uffd(ptent))
+ ptent = pte_modify(ptent, PAGE_NONE);
/*
* In some writable, shared mappings, we might want
@@ -325,6 +337,7 @@ static long change_pte_range(struct mmu_gather *tlb,
long pages = 0;
bool is_private_single_threaded;
bool prot_numa = cp_flags & MM_CP_PROT_NUMA;
+ bool uffd_rwp = cp_flags & MM_CP_UFFD_RWP;
bool uffd_wp = cp_flags & MM_CP_UFFD_WP;
int nr_ptes;
@@ -350,6 +363,14 @@ static long change_pte_range(struct mmu_gather *tlb,
/* Already in the desired state. */
if (prot_numa && pte_protnone(oldpte))
continue;
+ /*
+ * RWP-protected PTEs carry _PAGE_UFFD as a marker on
+ * top of PROT_NONE. Skip only entries already in that
+ * exact state; plain PROT_NONE from mprotect() still needs
+ * to be promoted so future faults can be distinguished.
+ */
+ if (uffd_rwp && pte_protnone(oldpte) && pte_uffd(oldpte))
+ continue;
page = vm_normal_page(vma, addr, oldpte);
if (page)
@@ -358,6 +379,8 @@ static long change_pte_range(struct mmu_gather *tlb,
/*
* Avoid trapping faults against the zero or KSM
* pages. See similar comment in change_huge_pmd.
+ * Skip this filter for uffd RWP which
+ * must set protnone regardless of NUMA placement.
*/
if (prot_numa &&
!folio_can_map_prot_numa(folio, vma,
@@ -428,7 +451,7 @@ pgtable_split_needed(struct vm_area_struct *vma, unsigned long cp_flags)
* (e.g. 2M shmem) because file thp is handled differently when
* split by erasing the pmd so far.
*/
- return (cp_flags & MM_CP_UFFD_WP) && !vma_is_anonymous(vma);
+ return (cp_flags & (MM_CP_UFFD_WP | MM_CP_UFFD_RWP)) && !vma_is_anonymous(vma);
}
/*
@@ -667,7 +690,16 @@ long change_protection(struct mmu_gather *tlb,
pgprot_t newprot = vma->vm_page_prot;
long pages;
- BUG_ON((cp_flags & MM_CP_UFFD_WP_ALL) == MM_CP_UFFD_WP_ALL);
+ /*
+ * MM_CP_UFFD_{WP,RWP} and _RESOLVE are mutually exclusive within one
+ * change, and WP and RWP cannot mix. Miswired callers get a warn and
+ * a no-op; userspace cannot reach this state.
+ */
+ if (WARN_ON_ONCE((cp_flags & MM_CP_UFFD_WP_ALL) == MM_CP_UFFD_WP_ALL ||
+ (cp_flags & MM_CP_UFFD_RWP_ALL) == MM_CP_UFFD_RWP_ALL ||
+ ((cp_flags & MM_CP_UFFD_WP_ALL) &&
+ (cp_flags & MM_CP_UFFD_RWP_ALL))))
+ return 0;
#ifdef CONFIG_NUMA_BALANCING
/*
@@ -681,6 +713,10 @@ long change_protection(struct mmu_gather *tlb,
WARN_ON_ONCE(cp_flags & MM_CP_PROT_NUMA);
#endif
+ if (IS_ENABLED(CONFIG_ARCH_HAS_PTE_PROTNONE) &&
+ (cp_flags & MM_CP_UFFD_RWP))
+ newprot = PAGE_NONE;
+
if (is_vm_hugetlb_page(vma))
pages = hugetlb_change_protection(vma, start, end, newprot,
cp_flags);
diff --git a/mm/mremap.c b/mm/mremap.c
index e9c8b1d05832..8a46ec5831c8 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -296,10 +296,19 @@ static int move_ptes(struct pagetable_move_control *pmc,
pte_clear(mm, new_addr, new_ptep);
else {
if (need_clear_uffd_wp) {
- if (pte_present(pte))
- pte = pte_clear_uffd_wp(pte);
- else
- pte = pte_swp_clear_uffd_wp(pte);
+ if (pte_present(pte)) {
+ /*
+ * See __copy_present_ptes(): normalise
+ * RWP PTEs so the destination starts
+ * accessible instead of taking a
+ * numa-hinting fault on first access.
+ */
+ if (userfaultfd_rwp(vma) && pte_uffd(pte))
+ pte = pte_modify(pte, vma->vm_page_prot);
+ pte = pte_clear_uffd(pte);
+ } else {
+ pte = pte_swp_clear_uffd(pte);
+ }
}
set_ptes(mm, new_addr, new_ptep, pte, nr_ptes);
}
diff --git a/mm/nommu.c b/mm/nommu.c
index 815ebefddfae..852ec9bd0505 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -1181,7 +1181,6 @@ unsigned long do_mmap(struct file *file,
ret = do_mmap_private(vma, region, len, capabilities);
if (ret < 0)
goto error_just_free;
- add_nommu_region(region);
/* clear anonymous mappings that don't ask for uninitialized data */
if (!vma->vm_file &&
@@ -1199,7 +1198,9 @@ share:
BUG_ON(!vma->vm_region);
vma_iter_config(&vmi, vma->vm_start, vma->vm_end);
if (vma_iter_prealloc(&vmi, vma))
- goto error_just_free;
+ goto error_vma_iter_prealloc;
+
+ add_nommu_region(region);
setup_vma_to_mm(vma, current->mm);
current->mm->map_count++;
@@ -1218,22 +1219,41 @@ share:
return result;
error_just_free:
+ vma_close(vma);
+ /* if the error was from shared mapping/existing region, don't free the region.
+ * this has to be before releasing semaphore.
+ */
+ if (region->vm_usage == 1) {
+ if (region->vm_file)
+ fput(region->vm_file);
+ kmem_cache_free(vm_region_jar, region);
+
+ } else
+ region->vm_usage--;
+
up_write(&nommu_region_sem);
-error:
vma_iter_free(&vmi);
- if (region->vm_file)
- fput(region->vm_file);
- kmem_cache_free(vm_region_jar, region);
+
if (vma->vm_file)
fput(vma->vm_file);
vm_area_free(vma);
return ret;
sharing_violation:
- up_write(&nommu_region_sem);
pr_warn("Attempt to share mismatched mappings\n");
ret = -EINVAL;
- goto error;
+ goto error_just_free;
+
+error_vma_iter_prealloc:
+ pr_warn("Allocation of vma iterator for process %d failed\n", current->pid);
+ show_mem();
+ ret = -ENOMEM;
+
+ /* in case that the region is allocated via do_mmap_private() */
+ if ((region->vm_usage == 1) && (region->vm_flags & VM_MAPPED_COPY))
+ free_page_series(region->vm_start, region->vm_top);
+
+ goto error_just_free;
error_getting_vma:
kmem_cache_free(vm_region_jar, region);
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index a63733dac659..cc45dfe89c76 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1377,15 +1377,23 @@ static __always_inline bool __free_pages_prepare(struct page *page,
#endif
}
for (i = 1; i < (1 << order); i++) {
+ struct page *tail_page = page + i;
+
if (compound)
- bad += free_tail_page_prepare(page, page + i);
+ bad += free_tail_page_prepare(page, tail_page);
if (is_check_pages_enabled()) {
- if (free_page_is_bad(page + i)) {
+ if (free_page_is_bad(tail_page)) {
+ bad++;
+ continue;
+ }
+
+ if (tail_page->private) {
+ bad_page(tail_page, "nonzero private");
bad++;
continue;
}
}
- (page + i)->flags.f &= ~PAGE_FLAGS_CHECK_AT_PREP;
+ tail_page->flags.f &= ~PAGE_FLAGS_CHECK_AT_PREP;
}
}
if (folio_test_anon(folio)) {
diff --git a/mm/page_table_check.c b/mm/page_table_check.c
index 53a8997ec043..3fb995e5d40d 100644
--- a/mm/page_table_check.c
+++ b/mm/page_table_check.c
@@ -188,8 +188,8 @@ static inline bool softleaf_cached_writable(softleaf_t entry)
static void page_table_check_pte_flags(pte_t pte)
{
if (pte_present(pte)) {
- WARN_ON_ONCE(pte_uffd_wp(pte) && pte_write(pte));
- } else if (pte_swp_uffd_wp(pte)) {
+ WARN_ON_ONCE(pte_uffd(pte) && pte_write(pte));
+ } else if (pte_swp_uffd(pte)) {
const softleaf_t entry = softleaf_from_pte(pte);
WARN_ON_ONCE(softleaf_cached_writable(entry));
@@ -216,9 +216,9 @@ EXPORT_SYMBOL(__page_table_check_ptes_set);
static inline void page_table_check_pmd_flags(pmd_t pmd)
{
if (pmd_present(pmd)) {
- if (pmd_uffd_wp(pmd))
+ if (pmd_uffd(pmd))
WARN_ON_ONCE(pmd_write(pmd));
- } else if (pmd_swp_uffd_wp(pmd)) {
+ } else if (pmd_swp_uffd(pmd)) {
const softleaf_t entry = softleaf_from_pmd(pmd);
WARN_ON_ONCE(softleaf_cached_writable(entry));
diff --git a/mm/percpu-km.c b/mm/percpu-km.c
index 4efa74a495cb..65fd5580e447 100644
--- a/mm/percpu-km.c
+++ b/mm/percpu-km.c
@@ -75,7 +75,7 @@ static struct pcpu_chunk *pcpu_create_chunk(gfp_t gfp)
chunk->base_addr = page_address(pages);
spin_lock_irqsave(&pcpu_lock, flags);
- pcpu_chunk_populated(chunk, 0, nr_pages);
+ pcpu_chunk_populated(chunk, 0, chunk->nr_pages);
spin_unlock_irqrestore(&pcpu_lock, flags);
pcpu_stats_chunk_alloc();
@@ -94,8 +94,15 @@ static void pcpu_destroy_chunk(struct pcpu_chunk *chunk)
pcpu_stats_chunk_dealloc();
trace_percpu_destroy_chunk(chunk->base_addr);
- if (chunk->data)
+ if (chunk->data) {
+ struct page *pages = (struct page *)chunk->data;
+ int i;
+
+ /* clear chunk info from each page before free them */
+ for (i = 0; i < nr_pages; i++)
+ pcpu_set_page_chunk(pages + i, NULL);
__free_pages(chunk->data, order_base_2(nr_pages));
+ }
pcpu_free_chunk(chunk);
}
diff --git a/mm/rmap.c b/mm/rmap.c
index 9939400e77c7..26166a6b8cb9 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -1965,7 +1965,7 @@ static inline unsigned int folio_unmap_pte_batch(struct folio *folio,
if (pte_unused(pte))
return 1;
- if (userfaultfd_wp(vma))
+ if (userfaultfd_protected(vma))
return 1;
/*
@@ -2317,13 +2317,13 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,
if (likely(pte_present(pteval))) {
if (pte_soft_dirty(pteval))
swp_pte = pte_swp_mksoft_dirty(swp_pte);
- if (pte_uffd_wp(pteval))
- swp_pte = pte_swp_mkuffd_wp(swp_pte);
+ if (pte_uffd(pteval))
+ swp_pte = pte_swp_mkuffd(swp_pte);
} else {
if (pte_swp_soft_dirty(pteval))
swp_pte = pte_swp_mksoft_dirty(swp_pte);
- if (pte_swp_uffd_wp(pteval))
- swp_pte = pte_swp_mkuffd_wp(swp_pte);
+ if (pte_swp_uffd(pteval))
+ swp_pte = pte_swp_mkuffd(swp_pte);
}
set_pte_at(mm, address, pvmw.pte, swp_pte);
} else {
@@ -2694,14 +2694,14 @@ static bool try_to_migrate_one(struct folio *folio, struct vm_area_struct *vma,
swp_pte = swp_entry_to_pte(entry);
if (pte_soft_dirty(pteval))
swp_pte = pte_swp_mksoft_dirty(swp_pte);
- if (pte_uffd_wp(pteval))
- swp_pte = pte_swp_mkuffd_wp(swp_pte);
+ if (pte_uffd(pteval))
+ swp_pte = pte_swp_mkuffd(swp_pte);
} else {
swp_pte = swp_entry_to_pte(entry);
if (pte_swp_soft_dirty(pteval))
swp_pte = pte_swp_mksoft_dirty(swp_pte);
- if (pte_swp_uffd_wp(pteval))
- swp_pte = pte_swp_mkuffd_wp(swp_pte);
+ if (pte_swp_uffd(pteval))
+ swp_pte = pte_swp_mkuffd(swp_pte);
}
if (folio_test_hugetlb(folio))
set_huge_pte_at(mm, address, pvmw.pte, swp_pte,
diff --git a/mm/shmem.c b/mm/shmem.c
index 8c4736188b57..8e5ab5b23937 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1287,7 +1287,8 @@ static int shmem_getattr(struct mnt_idmap *idmap,
struct inode *inode = path->dentry->d_inode;
struct shmem_inode_info *info = SHMEM_I(inode);
- if (info->alloced - info->swapped != inode->i_mapping->nrpages)
+ /* Fast-path hint; recalc under info->lock corrects any stale read. */
+ if (data_race(info->alloced - info->swapped != inode->i_mapping->nrpages))
shmem_recalc_inode(inode, 0, 0);
if (info->fsflags & FS_APPEND_FL)
diff --git a/mm/slub.c b/mm/slub.c
index 7f845d22d0c8..1e6542f27c48 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -6174,51 +6174,21 @@ check_pfmemalloc:
}
/*
- * Bulk free objects to the percpu sheaves.
- * Unlike free_to_pcs() this includes the calls to all necessary hooks
- * and the fallback to freeing to slab pages.
+ * Try to free as many objects (already processed by free hooks) as possible to
+ * a single per-cpu sheaf.
+ *
+ * Returns how many objects were freed. Zero means failure and the caller should
+ * fall back to __kmem_cache_free_bulk().
*/
-static void free_to_pcs_bulk(struct kmem_cache *s, size_t size, void **p)
+static unsigned int __free_to_pcs_batch(struct kmem_cache *s, size_t size, void **p)
{
struct slub_percpu_sheaves *pcs;
struct slab_sheaf *main, *empty;
- bool init = slab_want_init_on_free(s);
- unsigned int batch, i = 0;
struct node_barn *barn;
- void *remote_objects[PCS_BATCH_MAX];
- unsigned int remote_nr = 0;
-
- while (i < size) {
- struct slab *slab = virt_to_slab(p[i]);
-
- memcg_slab_free_hook(s, slab, p + i, 1);
- alloc_tagging_slab_free_hook(s, slab, p + i, 1);
-
- if (unlikely(!slab_free_hook(s, p[i], init, false))) {
- p[i] = p[--size];
- continue;
- }
-
- if (unlikely(!can_free_to_pcs(slab))) {
- remote_objects[remote_nr] = p[i];
- p[i] = p[--size];
- if (++remote_nr >= PCS_BATCH_MAX) {
- __kmem_cache_free_bulk(s, remote_nr, &remote_objects[0]);
- stat_add(s, FREE_SLOWPATH, remote_nr);
- remote_nr = 0;
- }
- continue;
- }
-
- i++;
- }
-
- if (!size)
- goto flush_remote;
+ unsigned int batch;
-next_batch:
if (!local_trylock(&s->cpu_sheaves->lock))
- goto fallback;
+ return 0;
pcs = this_cpu_ptr(s->cpu_sheaves);
@@ -6264,29 +6234,65 @@ do_free:
stat_add(s, FREE_FASTPATH, batch);
- if (batch < size) {
- p += batch;
- size -= batch;
- goto next_batch;
+ return batch;
+
+no_empty:
+ local_unlock(&s->cpu_sheaves->lock);
+
+ return 0;
+}
+
+/*
+ * Bulk free objects to the percpu sheaves.
+ * Unlike free_to_pcs() this includes the calls to all necessary hooks
+ * and the fallback to freeing to slab pages.
+ */
+static void free_to_pcs_bulk(struct kmem_cache *s, size_t size, void **p)
+{
+ bool init = slab_want_init_on_free(s);
+ void *remote_objects[PCS_BATCH_MAX];
+ unsigned int remote_nr = 0;
+
+ for (unsigned int i = 0; i < size;) {
+ struct slab *slab = virt_to_slab(p[i]);
+
+ memcg_slab_free_hook(s, slab, p + i, 1);
+ alloc_tagging_slab_free_hook(s, slab, p + i, 1);
+
+ if (unlikely(!slab_free_hook(s, p[i], init, false))) {
+ p[i] = p[--size];
+ continue;
+ }
+
+ if (unlikely(!can_free_to_pcs(slab))) {
+ remote_objects[remote_nr] = p[i];
+ p[i] = p[--size];
+ if (++remote_nr >= PCS_BATCH_MAX) {
+ __kmem_cache_free_bulk(s, remote_nr, &remote_objects[0]);
+ stat_add(s, FREE_SLOWPATH, remote_nr);
+ remote_nr = 0;
+ }
+ continue;
+ }
+
+ i++;
}
- if (remote_nr)
- goto flush_remote;
+ while (size) {
+ unsigned int batch_freed = __free_to_pcs_batch(s, size, p);
- return;
+ if (!batch_freed)
+ break;
-no_empty:
- local_unlock(&s->cpu_sheaves->lock);
+ p += batch_freed;
+ size -= batch_freed;
+ }
- /*
- * if we depleted all empty sheaves in the barn or there are too
- * many full sheaves, free the rest to slab pages
- */
-fallback:
- __kmem_cache_free_bulk(s, size, p);
- stat_add(s, FREE_SLOWPATH, size);
+ if (size) {
+ __kmem_cache_free_bulk(s, size, p);
+ stat_add(s, FREE_SLOWPATH, size);
+ }
-flush_remote:
if (remote_nr) {
__kmem_cache_free_bulk(s, remote_nr, &remote_objects[0]);
stat_add(s, FREE_SLOWPATH, remote_nr);
diff --git a/mm/swap.h b/mm/swap.h
index 44ab8e1e595b..b51ad3071a73 100644
--- a/mm/swap.h
+++ b/mm/swap.h
@@ -8,8 +8,6 @@ struct mempolicy;
struct swap_iocb;
struct swap_memcg_table;
-extern int page_cluster;
-
#if defined(MAX_POSSIBLE_PHYSMEM_BITS)
#define SWAP_CACHE_PFN_BITS (MAX_POSSIBLE_PHYSMEM_BITS - PAGE_SHIFT)
#elif defined(MAX_PHYSMEM_BITS)
diff --git a/mm/swap_state.c b/mm/swap_state.c
index 6fd6e3415b71..1444d20a40e9 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -22,10 +22,15 @@
#include <linux/vmalloc.h>
#include <linux/huge_mm.h>
#include <linux/shmem_fs.h>
+#include <linux/sysctl.h>
#include "internal.h"
#include "swap_table.h"
#include "swap.h"
+/* Swap readahead cluster size, as a power of 2 pages. */
+static int page_cluster;
+static const int page_cluster_max = 31;
+
/*
* swapper_space is a fiction, retained to simplify the path through
* vmscan's shrink_folio_list.
@@ -985,6 +990,35 @@ struct folio *swapin_readahead(swp_entry_t entry, gfp_t gfp_mask,
return folio;
}
+static const struct ctl_table swap_readahead_sysctl_table[] = {
+ {
+ .procname = "page-cluster",
+ .data = &page_cluster,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = SYSCTL_ZERO,
+ .extra2 = (void *)&page_cluster_max,
+ }
+};
+
+static void __init swap_readahead_setup(void)
+{
+ unsigned long megs = PAGES_TO_MB(totalram_pages());
+
+ /* Use a smaller cluster for small-memory machines */
+ if (megs < 16)
+ page_cluster = 2;
+ else
+ page_cluster = 3;
+ /*
+ * Right now other parts of the system means that we
+ * _really_ don't want to cluster much more
+ */
+
+ register_sysctl_init("vm", swap_readahead_sysctl_table);
+}
+
#ifdef CONFIG_SYSFS
static ssize_t vma_ra_enabled_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
@@ -1014,7 +1048,7 @@ static const struct attribute_group swap_attr_group = {
.attrs = swap_attrs,
};
-static int __init swap_init(void)
+static int __init swap_sysfs_init(void)
{
int err;
struct kobject *swap_kobj;
@@ -1037,5 +1071,17 @@ delete_obj:
kobject_put(swap_kobj);
return err;
}
-subsys_initcall(swap_init);
+#else
+static int __init swap_sysfs_init(void)
+{
+ return 0;
+}
#endif
+
+static int __init swap_init(void)
+{
+ swap_readahead_setup();
+
+ return swap_sysfs_init();
+}
+subsys_initcall(swap_init);
diff --git a/mm/swapfile.c b/mm/swapfile.c
index a602e5820513..775c385490a5 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -2496,8 +2496,13 @@ static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd,
new_pte = pte_mkold(mk_pte(page, vma->vm_page_prot));
if (pte_swp_soft_dirty(old_pte))
new_pte = pte_mksoft_dirty(new_pte);
- if (pte_swp_uffd_wp(old_pte))
- new_pte = pte_mkuffd_wp(new_pte);
+ if (pte_swp_uffd(old_pte))
+ new_pte = pte_mkuffd(new_pte);
+
+ /* See do_swap_page(): restore PAGE_NONE for RWP */
+ if (pte_swp_uffd(old_pte) && userfaultfd_rwp(vma))
+ new_pte = pte_modify(new_pte, PAGE_NONE);
+
setpte:
set_pte_at(vma->vm_mm, addr, pte, new_pte);
folio_put_swap(swapcache, folio_file_page(swapcache, swp_offset(entry)));
diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
index 33ef42d5a04e..73f32299453b 100644
--- a/mm/userfaultfd.c
+++ b/mm/userfaultfd.c
@@ -376,7 +376,7 @@ static int mfill_atomic_install_pte(pmd_t *dst_pmd,
if (writable)
_dst_pte = pte_mkwrite(_dst_pte, dst_vma);
if (flags & MFILL_ATOMIC_WP)
- _dst_pte = pte_mkuffd_wp(_dst_pte);
+ _dst_pte = pte_mkuffd(_dst_pte);
ret = -EAGAIN;
dst_pte = pte_offset_map_lock(dst_mm, dst_pmd, dst_addr, &ptl);
@@ -1164,6 +1164,75 @@ out_unlock:
return err;
}
+int mrwprotect_range(struct userfaultfd_ctx *ctx, unsigned long start,
+ unsigned long len, bool enable_rwp)
+{
+ struct mm_struct *dst_mm = ctx->mm;
+ unsigned long end = start + len;
+ struct vm_area_struct *dst_vma;
+ unsigned int mm_cp_flags;
+ struct mmu_gather tlb;
+ bool found = false;
+ VMA_ITERATOR(vmi, dst_mm, start);
+
+ VM_WARN_ON_ONCE(start & ~PAGE_MASK);
+ VM_WARN_ON_ONCE(len & ~PAGE_MASK);
+ VM_WARN_ON_ONCE(start + len <= start);
+
+ guard(mmap_read_lock)(dst_mm);
+ guard(rwsem_read)(&ctx->map_changing_lock);
+
+ if (atomic_read(&ctx->mmap_changing))
+ return -EAGAIN;
+
+ if (enable_rwp)
+ mm_cp_flags = MM_CP_UFFD_RWP;
+ else
+ mm_cp_flags = MM_CP_UFFD_RWP_RESOLVE;
+
+ /*
+ * Pre-scan the range: validate every spanned VMA before applying
+ * any change_protection() so a partial failure cannot leave the
+ * process with only a prefix of the range re-protected.
+ */
+ for_each_vma_range(vmi, dst_vma, end) {
+ if (!userfaultfd_rwp(dst_vma))
+ return -ENOENT;
+
+ if (is_vm_hugetlb_page(dst_vma)) {
+ unsigned long page_mask;
+
+ page_mask = vma_kernel_pagesize(dst_vma) - 1;
+ if ((start & page_mask) || (len & page_mask))
+ return -EINVAL;
+ }
+ found = true;
+ }
+ if (!found)
+ return -ENOENT;
+
+ vma_iter_set(&vmi, start);
+ tlb_gather_mmu(&tlb, dst_mm);
+ for_each_vma_range(vmi, dst_vma, end) {
+ unsigned long vma_start = max(dst_vma->vm_start, start);
+ unsigned long vma_end = min(dst_vma->vm_end, end);
+ unsigned int flags = mm_cp_flags;
+
+ /*
+ * On resolve, try to upgrade writability per-VMA --
+ * MM_CP_TRY_CHANGE_WRITABLE WARNs in
+ * maybe_change_pte_writable() if the VMA is not VM_WRITE,
+ * and RWP can be registered on PROT_READ-only mappings.
+ */
+ if (!enable_rwp && vma_wants_manual_pte_write_upgrade(dst_vma))
+ flags |= MM_CP_TRY_CHANGE_WRITABLE;
+
+ change_protection(&tlb, dst_vma, vma_start, vma_end, flags);
+ }
+ tlb_finish_mmu(&tlb);
+
+ return 0;
+}
void double_pt_lock(spinlock_t *ptl1,
spinlock_t *ptl2)
@@ -1292,6 +1361,13 @@ static long move_present_ptes(struct mm_struct *mm,
if (pte_dirty(orig_src_pte))
orig_dst_pte = pte_mkdirty(orig_dst_pte);
orig_dst_pte = pte_mkwrite(orig_dst_pte, dst_vma);
+
+ /* Re-arm RWP on the moved PTE if dst_vma is RWP-registered. */
+ if (userfaultfd_rwp(dst_vma)) {
+ orig_dst_pte = pte_modify(orig_dst_pte, PAGE_NONE);
+ orig_dst_pte = pte_mkuffd(orig_dst_pte);
+ }
+
set_pte_at(mm, dst_addr, dst_pte, orig_dst_pte);
src_addr += PAGE_SIZE;
@@ -1373,6 +1449,9 @@ static int move_swap_pte(struct mm_struct *mm, struct vm_area_struct *dst_vma,
orig_src_pte = ptep_get_and_clear(mm, src_addr, src_pte);
if (pgtable_supports_soft_dirty())
orig_src_pte = pte_swp_mksoft_dirty(orig_src_pte);
+ /* Re-arm RWP on the moved swap entry if dst_vma is RWP-registered. */
+ if (userfaultfd_rwp(dst_vma))
+ orig_src_pte = pte_swp_mkuffd(orig_src_pte);
set_pte_at(mm, dst_addr, dst_pte, orig_src_pte);
double_pt_unlock(dst_ptl, src_ptl);
@@ -1399,6 +1478,13 @@ static int move_zeropage_pte(struct mm_struct *mm,
zero_pte = pte_mkspecial(pfn_pte(zero_pfn(dst_addr),
dst_vma->vm_page_prot));
+
+ /* Re-arm RWP on the moved PTE if dst_vma is RWP-registered. */
+ if (userfaultfd_rwp(dst_vma)) {
+ zero_pte = pte_modify(zero_pte, PAGE_NONE);
+ zero_pte = pte_mkuffd(zero_pte);
+ }
+
ptep_clear_flush(src_vma, src_addr, src_pte);
set_pte_at(mm, dst_addr, dst_pte, zero_pte);
double_pt_unlock(dst_ptl, src_ptl);
@@ -2190,9 +2276,22 @@ static struct vm_area_struct *userfaultfd_clear_vma(struct vma_iterator *vmi,
if (start == vma->vm_start && end == vma->vm_end)
give_up_on_oom = true;
- /* Reset ptes for the whole vma range if wr-protected */
- if (userfaultfd_wp(vma))
- uffd_wp_range(vma, start, end - start, false);
+ /* Clear the uffd bit and/or restore protnone PTEs */
+ if (userfaultfd_protected(vma)) {
+ unsigned int mm_cp_flags = 0;
+ struct mmu_gather tlb;
+
+ if (userfaultfd_wp(vma))
+ mm_cp_flags |= MM_CP_UFFD_WP_RESOLVE;
+ if (userfaultfd_rwp(vma))
+ mm_cp_flags |= MM_CP_UFFD_RWP_RESOLVE;
+ if (vma_wants_manual_pte_write_upgrade(vma))
+ mm_cp_flags |= MM_CP_TRY_CHANGE_WRITABLE;
+
+ tlb_gather_mmu(&tlb, vma->vm_mm);
+ change_protection(&tlb, vma, start, end, mm_cp_flags);
+ tlb_finish_mmu(&tlb);
+ }
ret = vma_modify_flags_uffd(vmi, prev, vma, start, end,
&new_vma_flags, NULL_VM_UFFD_CTX,
@@ -2241,6 +2340,14 @@ static int userfaultfd_register_range(struct userfaultfd_ctx *ctx,
(vma->vm_flags & __VM_UFFD_FLAGS) == vm_flags)
goto skip;
+ /*
+ * Pre-scan in userfaultfd_register() already rejected mode
+ * switches that would drop VM_UFFD_WP or VM_UFFD_RWP, so a
+ * stray bit here is a bug.
+ */
+ VM_WARN_ON_ONCE(vma->vm_userfaultfd_ctx.ctx == ctx &&
+ vma->vm_flags & (VM_UFFD_WP | VM_UFFD_RWP) & ~vm_flags);
+
if (vma->vm_start > start)
start = vma->vm_start;
vma_end = min(end, vma->vm_end);
@@ -2379,14 +2486,29 @@ struct userfaultfd_wake_range {
/* internal indication that UFFD_API ioctl was successfully executed */
#define UFFD_FEATURE_INITIALIZED (1u << 31)
+/*
+ * UFFDIO_SET_MODE updates ctx->features under mmap_write_lock with
+ * WRITE_ONCE; readers that run outside mmap_read_lock or the per-VMA
+ * lock (poll/read_iter/ioctl, fdinfo) must pair with READ_ONCE.
+ */
+static unsigned int userfaultfd_features(struct userfaultfd_ctx *ctx)
+{
+ return READ_ONCE(ctx->features);
+}
+
static bool userfaultfd_is_initialized(struct userfaultfd_ctx *ctx)
{
- return ctx->features & UFFD_FEATURE_INITIALIZED;
+ return userfaultfd_features(ctx) & UFFD_FEATURE_INITIALIZED;
}
static bool userfaultfd_wp_async_ctx(struct userfaultfd_ctx *ctx)
{
- return ctx && (ctx->features & UFFD_FEATURE_WP_ASYNC);
+ return ctx && (userfaultfd_features(ctx) & UFFD_FEATURE_WP_ASYNC);
+}
+
+static bool userfaultfd_rwp_async_ctx(struct userfaultfd_ctx *ctx)
+{
+ return ctx && (userfaultfd_features(ctx) & UFFD_FEATURE_RWP_ASYNC);
}
/*
@@ -2401,7 +2523,7 @@ bool userfaultfd_wp_unpopulated(struct vm_area_struct *vma)
if (!ctx)
return false;
- return ctx->features & UFFD_FEATURE_WP_UNPOPULATED;
+ return userfaultfd_features(ctx) & UFFD_FEATURE_WP_UNPOPULATED;
}
static int userfaultfd_wake_function(wait_queue_entry_t *wq, unsigned mode,
@@ -2515,6 +2637,8 @@ static inline struct uffd_msg userfault_msg(unsigned long address,
msg.arg.pagefault.flags |= UFFD_PAGEFAULT_FLAG_WRITE;
if (reason & VM_UFFD_WP)
msg.arg.pagefault.flags |= UFFD_PAGEFAULT_FLAG_WP;
+ if (reason & VM_UFFD_RWP)
+ msg.arg.pagefault.flags |= UFFD_PAGEFAULT_FLAG_RWP;
if (reason & VM_UFFD_MINOR)
msg.arg.pagefault.flags |= UFFD_PAGEFAULT_FLAG_MINOR;
if (features & UFFD_FEATURE_THREAD_ID)
@@ -2568,6 +2692,12 @@ static inline bool userfaultfd_huge_must_wait(struct userfaultfd_ctx *ctx,
*/
if (!huge_pte_write(pte) && (reason & VM_UFFD_WP))
return true;
+ /*
+ * PTE is still RW-protected (protnone with uffd bit), wait for
+ * resolution. Plain PROT_NONE without the marker is not an RWP fault.
+ */
+ if (pte_protnone(pte) && huge_pte_uffd(pte) && (reason & VM_UFFD_RWP))
+ return true;
return false;
}
@@ -2628,8 +2758,14 @@ again:
if (!pmd_present(_pmd))
return false;
- if (pmd_trans_huge(_pmd))
- return !pmd_write(_pmd) && (reason & VM_UFFD_WP);
+ if (pmd_trans_huge(_pmd)) {
+ if (!pmd_write(_pmd) && (reason & VM_UFFD_WP))
+ return true;
+ if (pmd_protnone(_pmd) && pmd_uffd(_pmd) &&
+ (reason & VM_UFFD_RWP))
+ return true;
+ return false;
+ }
pte = pte_offset_map(pmd, address);
if (!pte)
@@ -2665,6 +2801,13 @@ again:
*/
if (!pte_write(ptent) && (reason & VM_UFFD_WP))
goto out;
+ /*
+ * PTE is still RW-protected (protnone with uffd bit), wait for
+ * userspace to resolve. Plain PROT_NONE without the marker is not
+ * an RWP fault.
+ */
+ if (pte_protnone(ptent) && pte_uffd(ptent) && (reason & VM_UFFD_RWP))
+ goto out;
ret = false;
out:
@@ -3609,11 +3752,27 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
if (uffdio_register.mode & UFFDIO_REGISTER_MODE_MISSING)
vm_flags |= VM_UFFD_MISSING;
if (uffdio_register.mode & UFFDIO_REGISTER_MODE_WP) {
- if (!pgtable_supports_uffd_wp())
+ if (!pgtable_supports_uffd())
goto out;
vm_flags |= VM_UFFD_WP;
}
+ if (uffdio_register.mode & UFFDIO_REGISTER_MODE_RWP) {
+ if (!pgtable_supports_uffd() || VM_UFFD_RWP == VM_NONE)
+ goto out;
+ if (!(userfaultfd_features(ctx) & UFFD_FEATURE_RWP))
+ goto out;
+ vm_flags |= VM_UFFD_RWP;
+ }
+
+ /*
+ * WP and RWP share the uffd PTE bit and
+ * cannot coexist in the same VMA — the bit would carry ambiguous
+ * semantics. Reject the combination up front.
+ */
+ if ((vm_flags & VM_UFFD_WP) && (vm_flags & VM_UFFD_RWP))
+ goto out;
+
if (uffdio_register.mode & UFFDIO_REGISTER_MODE_MINOR) {
#ifndef CONFIG_HAVE_ARCH_USERFAULTFD_MINOR
goto out;
@@ -3669,6 +3828,17 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
goto out_unlock;
/*
+ * RWP uses protnone as an access-tracking marker. PROT_NONE
+ * VMAs have vm_page_prot == PAGE_NONE, so RWP resolution
+ * cannot make a page accessible again. Reject at register
+ * time only: a VMA that later becomes inaccessible via
+ * mprotect() must still be unregisterable, so this is not
+ * part of vma_can_userfault().
+ */
+ if ((vm_flags & VM_UFFD_RWP) && !vma_is_accessible(cur))
+ goto out_unlock;
+
+ /*
* UFFDIO_COPY will fill file holes even without
* PROT_WRITE. This check enforces that if this is a
* MAP_SHARED, the process has write permission to the backing
@@ -3708,6 +3878,16 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
goto out_unlock;
/*
+ * Mode switches that drop VM_UFFD_WP or VM_UFFD_RWP would
+ * leave PTE markers without the flag that describes them;
+ * subsequent mprotect() would then promote stale markers
+ * into the other mode. Require an unregister first.
+ */
+ if (cur->vm_userfaultfd_ctx.ctx == ctx &&
+ cur->vm_flags & (VM_UFFD_WP | VM_UFFD_RWP) & ~vm_flags)
+ goto out_unlock;
+
+ /*
* Note vmas containing huge pages
*/
if (is_vm_hugetlb_page(cur))
@@ -3740,6 +3920,10 @@ out_unlock:
if (!(uffdio_register.mode & UFFDIO_REGISTER_MODE_MINOR))
ioctls_out &= ~((__u64)1 << _UFFDIO_CONTINUE);
+ /* RWPROTECT is only supported for RWP ranges */
+ if (!(uffdio_register.mode & UFFDIO_REGISTER_MODE_RWP))
+ ioctls_out &= ~((__u64)1 << _UFFDIO_RWPROTECT);
+
/*
* Now that we scanned all vmas we can already tell
* userland which ioctls methods are guaranteed to
@@ -4087,6 +4271,158 @@ static int userfaultfd_writeprotect(struct userfaultfd_ctx *ctx,
return ret;
}
+static int userfaultfd_rwprotect(struct userfaultfd_ctx *ctx,
+ unsigned long arg)
+{
+ int ret;
+ struct uffdio_rwprotect uffdio_rwp;
+ struct userfaultfd_wake_range range;
+ bool mode_rwp, mode_dontwake;
+
+ if (atomic_read(&ctx->mmap_changing))
+ return -EAGAIN;
+
+ if (copy_from_user(&uffdio_rwp, (void __user *)arg,
+ sizeof(uffdio_rwp)))
+ return -EFAULT;
+
+ ret = validate_range(ctx->mm, uffdio_rwp.range.start,
+ uffdio_rwp.range.len);
+ if (ret)
+ return ret;
+
+ if (uffdio_rwp.mode & ~(UFFDIO_RWPROTECT_MODE_DONTWAKE |
+ UFFDIO_RWPROTECT_MODE_RWP))
+ return -EINVAL;
+
+ mode_rwp = uffdio_rwp.mode & UFFDIO_RWPROTECT_MODE_RWP;
+ mode_dontwake = uffdio_rwp.mode & UFFDIO_RWPROTECT_MODE_DONTWAKE;
+
+ if (mode_rwp && mode_dontwake)
+ return -EINVAL;
+
+ if (mmget_not_zero(ctx->mm)) {
+ ret = mrwprotect_range(ctx, uffdio_rwp.range.start,
+ uffdio_rwp.range.len, mode_rwp);
+ mmput(ctx->mm);
+ } else {
+ return -ESRCH;
+ }
+
+ if (ret)
+ return ret;
+
+ if (!mode_rwp && !mode_dontwake) {
+ range.start = uffdio_rwp.range.start;
+ range.len = uffdio_rwp.range.len;
+ wake_userfault(ctx, &range);
+ }
+ return ret;
+}
+
+/* Subset of UFFD_API_FEATURES actually supported by this kernel/arch */
+static __u64 uffd_api_available_features(void)
+{
+ __u64 f = UFFD_API_FEATURES;
+
+ if (!IS_ENABLED(CONFIG_HAVE_ARCH_USERFAULTFD_MINOR))
+ f &= ~(UFFD_FEATURE_MINOR_HUGETLBFS | UFFD_FEATURE_MINOR_SHMEM);
+ if (!pgtable_supports_uffd())
+ f &= ~UFFD_FEATURE_PAGEFAULT_FLAG_WP;
+ if (!uffd_supports_wp_marker())
+ f &= ~(UFFD_FEATURE_WP_HUGETLBFS_SHMEM |
+ UFFD_FEATURE_WP_UNPOPULATED |
+ UFFD_FEATURE_WP_ASYNC);
+ /*
+ * RWP needs both PROT_NONE support and the uffd PTE bit. The
+ * VM_UFFD_RWP check covers compile-time unavailability; the
+ * pgtable_supports_uffd() check covers runtime (e.g. riscv
+ * without the SVRSW60T59B extension) where the PTE bit is declared
+ * but not actually usable.
+ */
+ if (VM_UFFD_RWP == VM_NONE || !pgtable_supports_uffd())
+ f &= ~(UFFD_FEATURE_RWP | UFFD_FEATURE_RWP_ASYNC);
+ return f;
+}
+
+/* Async features that can be toggled at runtime via UFFDIO_SET_MODE */
+#define UFFD_FEATURE_TOGGLEABLE UFFD_FEATURE_RWP_ASYNC
+
+static int userfaultfd_set_mode(struct userfaultfd_ctx *ctx,
+ unsigned long arg)
+{
+ struct uffdio_set_mode mode;
+ struct mm_struct *mm = ctx->mm;
+
+ if (copy_from_user(&mode, (void __user *)arg, sizeof(mode)))
+ return -EFAULT;
+
+ /* enable and disable must not overlap */
+ if (mode.enable & mode.disable)
+ return -EINVAL;
+
+ /* only toggleable features that this kernel/arch actually supports */
+ if ((mode.enable | mode.disable) &
+ ~(uffd_api_available_features() & UFFD_FEATURE_TOGGLEABLE))
+ return -EINVAL;
+
+ /* RWP_ASYNC can only be enabled on contexts that negotiated RWP */
+ if ((mode.enable & UFFD_FEATURE_RWP_ASYNC) &&
+ !(userfaultfd_features(ctx) & UFFD_FEATURE_RWP))
+ return -EINVAL;
+
+ if (!mmget_not_zero(mm))
+ return -ESRCH;
+
+ /*
+ * Drain in-flight faults before flipping features. mmap_write_lock()
+ * blocks new mmap_read_lock() callers, but per-VMA locked faults
+ * (lock_vma_under_rcu() + FAULT_FLAG_VMA_LOCK) that acquired before
+ * this point keep running. Calling vma_start_write() on each UFFD-
+ * armed VMA waits for those readers to drop, so no in-flight fault
+ * can observe the old features after mmap_write_unlock().
+ */
+ mmap_write_lock(mm);
+ {
+ struct vm_area_struct *vma;
+ VMA_ITERATOR(vmi, mm, 0);
+
+ for_each_vma(vmi, vma) {
+ if (vma->vm_userfaultfd_ctx.ctx == ctx)
+ vma_start_write(vma);
+ }
+ }
+ /*
+ * Single WRITE_ONCE so lockless readers (fdinfo, poll/read_iter
+ * via userfaultfd_is_initialized(), and the userfaultfd_features()
+ * helper used elsewhere) can't observe a mid-RMW intermediate
+ * value. Hot-path readers already serialise through the mmap lock
+ * + vma_start_write() drain above, so their load doesn't need an
+ * annotation.
+ */
+ WRITE_ONCE(ctx->features,
+ (ctx->features | mode.enable) & ~mode.disable);
+ mmap_write_unlock(mm);
+
+ /*
+ * If switching to async, wake threads blocked in handle_userfault().
+ * They will retry the fault and auto-resolve under the new mode.
+ * len=0 means wake all pending faults on this context.
+ */
+ if (mode.enable & UFFD_FEATURE_RWP_ASYNC) {
+ struct userfaultfd_wake_range range = { .len = 0 };
+
+ spin_lock_irq(&ctx->fault_pending_wqh.lock);
+ __wake_up_locked_key(&ctx->fault_pending_wqh, TASK_NORMAL,
+ &range);
+ __wake_up(&ctx->fault_wqh, TASK_NORMAL, 1, &range);
+ spin_unlock_irq(&ctx->fault_pending_wqh.lock);
+ }
+
+ mmput(mm);
+ return 0;
+}
+
static int userfaultfd_continue(struct userfaultfd_ctx *ctx, unsigned long arg)
{
__s64 ret;
@@ -4210,6 +4546,11 @@ bool userfaultfd_wp_async(struct vm_area_struct *vma)
return userfaultfd_wp_async_ctx(vma->vm_userfaultfd_ctx.ctx);
}
+bool userfaultfd_rwp_async(struct vm_area_struct *vma)
+{
+ return userfaultfd_rwp_async_ctx(vma->vm_userfaultfd_ctx.ctx);
+}
+
static inline unsigned int uffd_ctx_features(__u64 user_features)
{
/*
@@ -4313,20 +4654,14 @@ static int userfaultfd_api(struct userfaultfd_ctx *ctx,
if (features & UFFD_FEATURE_WP_ASYNC)
features |= UFFD_FEATURE_WP_UNPOPULATED;
- /* report all available features and ioctls to userland */
- uffdio_api.features = UFFD_API_FEATURES;
-#ifndef CONFIG_HAVE_ARCH_USERFAULTFD_MINOR
- uffdio_api.features &=
- ~(UFFD_FEATURE_MINOR_HUGETLBFS | UFFD_FEATURE_MINOR_SHMEM);
-#endif
- if (!pgtable_supports_uffd_wp())
- uffdio_api.features &= ~UFFD_FEATURE_PAGEFAULT_FLAG_WP;
+ ret = -EINVAL;
+ /* RWP_ASYNC requires RWP */
+ if ((features & UFFD_FEATURE_RWP_ASYNC) &&
+ !(features & UFFD_FEATURE_RWP))
+ goto err_out;
- if (!uffd_supports_wp_marker()) {
- uffdio_api.features &= ~UFFD_FEATURE_WP_HUGETLBFS_SHMEM;
- uffdio_api.features &= ~UFFD_FEATURE_WP_UNPOPULATED;
- uffdio_api.features &= ~UFFD_FEATURE_WP_ASYNC;
- }
+ /* report all available features and ioctls to userland */
+ uffdio_api.features = uffd_api_available_features();
ret = -EINVAL;
if (features & ~uffdio_api.features)
@@ -4393,6 +4728,12 @@ static long userfaultfd_ioctl(struct file *file, unsigned cmd,
case UFFDIO_POISON:
ret = userfaultfd_poison(ctx, arg);
break;
+ case UFFDIO_RWPROTECT:
+ ret = userfaultfd_rwprotect(ctx, arg);
+ break;
+ case UFFDIO_SET_MODE:
+ ret = userfaultfd_set_mode(ctx, arg);
+ break;
}
return ret;
}
@@ -4420,7 +4761,7 @@ static void userfaultfd_show_fdinfo(struct seq_file *m, struct file *f)
* protocols: aa:... bb:...
*/
seq_printf(m, "pending:\t%lu\ntotal:\t%lu\nAPI:\t%Lx:%x:%Lx\n",
- pending, total, UFFD_API, ctx->features,
+ pending, total, UFFD_API, userfaultfd_features(ctx),
UFFD_API_IOCTLS|UFFD_API_RANGE_IOCTLS);
}
#endif
diff --git a/mm/util.c b/mm/util.c
index af2c2103f0d9..34cb43b3eaa4 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -1353,7 +1353,7 @@ again:
if (ps->idx < MAX_FOLIO_NR_PAGES) {
memcpy(&ps->folio_snapshot, foliop, 2 * sizeof(struct page));
nr_pages = folio_nr_pages(&ps->folio_snapshot);
- if (nr_pages > 1)
+ if (nr_pages > 2)
memcpy(&ps->folio_snapshot.__page_2, &foliop->__page_2,
sizeof(struct page));
set_ps_flags(ps, foliop, page);
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 1474a7234ea1..f8faa7d06329 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -3255,10 +3255,40 @@ static void update_batch_size(struct lru_gen_mm_walk *walk, struct folio *folio,
walk->nr_pages[new_gen][type][zone] += delta;
}
+#ifdef CONFIG_MEMCG
+static struct lruvec *lock_batch_lruvec(struct lruvec *lruvec)
+{
+ struct pglist_data *pgdat = lruvec_pgdat(lruvec);
+ struct mem_cgroup *memcg = lruvec_memcg(lruvec);
+
+ rcu_read_lock();
+
+ /*
+ * The memcg can be NULL when the memory controller is disabled.
+ * Otherwise, the caller keeps the memcg owning @lruvec alive.
+ */
+ while (unlikely(memcg && css_is_dying(&memcg->css))) {
+ memcg = parent_mem_cgroup(memcg);
+ lruvec = mem_cgroup_lruvec(memcg, pgdat);
+ }
+
+ spin_lock_irq(&lruvec->lru_lock);
+
+ return lruvec;
+}
+#else
+static struct lruvec *lock_batch_lruvec(struct lruvec *lruvec)
+{
+ lruvec_lock_irq(lruvec);
+
+ return lruvec;
+}
+#endif
+
static void reset_batch_size(struct lru_gen_mm_walk *walk)
{
int gen, type, zone;
- struct lruvec *lruvec = walk->lruvec;
+ struct lruvec *lruvec = lock_batch_lruvec(walk->lruvec);
struct lru_gen_folio *lrugen = &lruvec->lrugen;
walk->batched = 0;
@@ -3278,6 +3308,8 @@ static void reset_batch_size(struct lru_gen_mm_walk *walk)
lru += LRU_ACTIVE;
__update_lru_size(lruvec, lru, zone, delta);
}
+
+ lruvec_unlock_irq(lruvec);
}
static int should_skip_vma(unsigned long start, unsigned long end, struct mm_walk *args)
@@ -3772,11 +3804,8 @@ static void walk_mm(struct mm_struct *mm, struct lru_gen_mm_walk *walk)
mmap_read_unlock(mm);
}
- if (walk->batched) {
- lruvec_lock_irq(lruvec);
+ if (walk->batched)
reset_batch_size(walk);
- lruvec_unlock_irq(lruvec);
- }
cond_resched();
} while (err == -EAGAIN);
@@ -4860,9 +4889,7 @@ retry:
walk = current->reclaim_state->mm_walk;
if (walk && walk->batched) {
walk->lruvec = lruvec;
- lruvec_lock_irq(lruvec);
reset_batch_size(walk);
- lruvec_unlock_irq(lruvec);
}
mod_lruvec_state(lruvec, PGDEMOTE_KSWAPD + reclaimer_offset(sc),
@@ -7647,7 +7674,6 @@ static int __init kswapd_init(void)
{
int nid;
- swap_setup();
for_each_node_state(nid, N_MEMORY)
kswapd_run(nid);
register_sysctl_init("vm", vmscan_sysctl_table);
diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c
index c40c9e02391b..a6fe4820f65b 100644
--- a/net/batman-adv/distributed-arp-table.c
+++ b/net/batman-adv/distributed-arp-table.c
@@ -546,7 +546,7 @@ static bool batadv_is_orig_node_eligible(struct batadv_dat_candidate *res,
* the one with the lowest address
*/
if (tmp_max == max && max_orig_node &&
- batadv_compare_eth(candidate->orig, max_orig_node->orig))
+ memcmp(candidate->orig, max_orig_node->orig, ETH_ALEN) >= 0)
goto out;
ret = true;
diff --git a/net/batman-adv/fragmentation.c b/net/batman-adv/fragmentation.c
index 8a006a0473a8..2e20a2cb64cb 100644
--- a/net/batman-adv/fragmentation.c
+++ b/net/batman-adv/fragmentation.c
@@ -518,8 +518,10 @@ int batadv_frag_send_packet(struct sk_buff *skb,
mtu = min_t(unsigned int, mtu, BATADV_FRAG_MAX_FRAG_SIZE);
max_fragment_size = mtu - header_size;
- if (skb->len == 0 || max_fragment_size == 0)
- return -EINVAL;
+ if (skb->len == 0 || max_fragment_size == 0) {
+ ret = -EINVAL;
+ goto free_skb;
+ }
num_fragments = (skb->len - 1) / max_fragment_size + 1;
max_fragment_size = (skb->len - 1) / num_fragments + 1;
@@ -545,7 +547,7 @@ int batadv_frag_send_packet(struct sk_buff *skb,
*/
if (skb_has_frag_list(skb) && __skb_linearize(skb)) {
ret = -ENOMEM;
- goto free_skb;
+ goto put_primary_if;
}
/* Create one header to be copied to all fragments */
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c
index fb2b0e35e349..73becb054948 100644
--- a/net/batman-adv/main.c
+++ b/net/batman-adv/main.c
@@ -253,6 +253,7 @@ err_orig:
void batadv_mesh_free(struct net_device *mesh_iface)
{
struct batadv_priv *bat_priv = netdev_priv(mesh_iface);
+ struct batadv_meshif_vlan *vlan;
WRITE_ONCE(bat_priv->mesh_state, BATADV_MESH_DEACTIVATING);
@@ -267,6 +268,13 @@ void batadv_mesh_free(struct net_device *mesh_iface)
batadv_mcast_free(bat_priv);
+ /* destroy the "untagged" VLAN */
+ vlan = batadv_meshif_vlan_get(bat_priv, BATADV_NO_FLAGS);
+ if (vlan) {
+ batadv_meshif_destroy_vlan(bat_priv, vlan);
+ batadv_meshif_vlan_put(vlan);
+ }
+
/* Free the TT and the originator tables only after having terminated
* all the other depending components which may use these structures for
* their purposes.
@@ -362,7 +370,7 @@ void batadv_skb_set_priority(struct sk_buff *skb, int offset)
switch (ethhdr->h_proto) {
case htons(ETH_P_8021Q):
- vhdr = skb_header_pointer(skb, offset + sizeof(*vhdr),
+ vhdr = skb_header_pointer(skb, offset,
sizeof(*vhdr), &vhdr_tmp);
if (!vhdr)
return;
diff --git a/net/batman-adv/mesh-interface.c b/net/batman-adv/mesh-interface.c
index 5cc72bbc4570..1dc6cfae9e9a 100644
--- a/net/batman-adv/mesh-interface.c
+++ b/net/batman-adv/mesh-interface.c
@@ -195,6 +195,9 @@ static netdev_tx_t batadv_interface_tx(struct sk_buff *skb,
if (READ_ONCE(bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
goto dropped;
+ if (!pskb_may_pull(skb, ETH_HLEN))
+ goto dropped;
+
/* reset control block to avoid left overs from previous users */
memset(skb->cb, 0, sizeof(struct batadv_skb_cb));
@@ -592,8 +595,8 @@ int batadv_meshif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid)
* @bat_priv: the bat priv with all the mesh interface information
* @vlan: the object to remove
*/
-static void batadv_meshif_destroy_vlan(struct batadv_priv *bat_priv,
- struct batadv_meshif_vlan *vlan)
+void batadv_meshif_destroy_vlan(struct batadv_priv *bat_priv,
+ struct batadv_meshif_vlan *vlan)
{
/* explicitly remove the associated TT local entry because it is marked
* with the NOPURGE flag
@@ -1077,22 +1080,13 @@ static int batadv_meshif_newlink(struct net_device *dev,
static void batadv_meshif_destroy_netlink(struct net_device *mesh_iface,
struct list_head *head)
{
- struct batadv_priv *bat_priv = netdev_priv(mesh_iface);
struct batadv_hard_iface *hard_iface;
- struct batadv_meshif_vlan *vlan;
while (!list_empty(&mesh_iface->adj_list.lower)) {
hard_iface = netdev_adjacent_get_private(mesh_iface->adj_list.lower.next);
batadv_hardif_disable_interface(hard_iface);
}
- /* destroy the "untagged" VLAN */
- vlan = batadv_meshif_vlan_get(bat_priv, BATADV_NO_FLAGS);
- if (vlan) {
- batadv_meshif_destroy_vlan(bat_priv, vlan);
- batadv_meshif_vlan_put(vlan);
- }
-
unregister_netdevice_queue(mesh_iface, head);
}
diff --git a/net/batman-adv/mesh-interface.h b/net/batman-adv/mesh-interface.h
index 53756c5a45e0..5e1e83e04ffb 100644
--- a/net/batman-adv/mesh-interface.h
+++ b/net/batman-adv/mesh-interface.h
@@ -21,6 +21,8 @@ void batadv_interface_rx(struct net_device *mesh_iface,
bool batadv_meshif_is_valid(const struct net_device *net_dev);
extern struct rtnl_link_ops batadv_link_ops;
int batadv_meshif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid);
+void batadv_meshif_destroy_vlan(struct batadv_priv *bat_priv,
+ struct batadv_meshif_vlan *vlan);
void batadv_meshif_vlan_release(struct kref *ref);
struct batadv_meshif_vlan *batadv_meshif_vlan_get(struct batadv_priv *bat_priv,
unsigned short vid);
diff --git a/net/batman-adv/multicast_forw.c b/net/batman-adv/multicast_forw.c
index b8668a80b94a..1404a3b7adfb 100644
--- a/net/batman-adv/multicast_forw.c
+++ b/net/batman-adv/multicast_forw.c
@@ -927,11 +927,11 @@ static int batadv_mcast_forw_packet(struct batadv_priv *bat_priv,
{
struct batadv_tvlv_mcast_tracker *mcast_tracker;
struct batadv_neigh_node *neigh_node;
- unsigned long offset, num_dests_off;
struct sk_buff *nexthop_skb;
unsigned char *skb_net_hdr;
bool local_recv = false;
unsigned int tvlv_len;
+ unsigned long offset;
bool xmitted = false;
u8 *dest, *next_dest;
u16 num_dests;
@@ -940,9 +940,8 @@ static int batadv_mcast_forw_packet(struct batadv_priv *bat_priv,
/* (at least) TVLV part needs to be linearized */
SKB_LINEAR_ASSERT(skb);
- /* check if num_dests is within skb length */
- num_dests_off = offsetof(struct batadv_tvlv_mcast_tracker, num_dests);
- if (num_dests_off > skb_network_header_len(skb))
+ /* check if batadv_tvlv_mcast_tracker header is within skb length */
+ if (sizeof(*mcast_tracker) > skb_network_header_len(skb))
return -EINVAL;
skb_net_hdr = skb_network_header(skb);
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 4bfad36a4b70..dae5e1d8c038 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -2971,7 +2971,7 @@ static bool batadv_send_tt_request(struct batadv_priv *bat_priv,
out:
batadv_hardif_put(primary_if);
- if (ret && tt_req_node) {
+ if (!ret && tt_req_node) {
spin_lock_bh(&bat_priv->tt.req_list_lock);
if (!hlist_unhashed(&tt_req_node->list)) {
hlist_del_init(&tt_req_node->list);
@@ -4033,7 +4033,8 @@ static int batadv_tt_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv,
u16 tvlv_value_len)
{
struct batadv_tvlv_tt_data *tt_data;
- u16 tt_vlan_len, tt_num_entries;
+ u16 tt_num_entries;
+ size_t tt_vlan_len;
char tt_flag;
bool ret;
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index 042d31278713..0bf541936f60 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -405,6 +405,9 @@ ebt_check_match(struct ebt_entry_match *m, struct xt_mtchk_param *par,
left - sizeof(struct ebt_entry_match) < m->match_size)
return -EINVAL;
+ if (strnlen(m->u.name, XT_EXTENSION_MAXNAMELEN) == XT_EXTENSION_MAXNAMELEN)
+ return -EINVAL;
+
match = xt_find_match(NFPROTO_BRIDGE, m->u.name, m->u.revision);
if (IS_ERR(match) || match->family != NFPROTO_BRIDGE) {
if (!IS_ERR(match))
@@ -923,8 +926,7 @@ static int translate_table(struct net *net, const char *name,
* if an error occurs
*/
newinfo->chainstack =
- vmalloc_array(nr_cpu_ids,
- sizeof(*(newinfo->chainstack)));
+ vcalloc(nr_cpu_ids, sizeof(*(newinfo->chainstack)));
if (!newinfo->chainstack)
return -ENOMEM;
for_each_possible_cpu(i) {
@@ -1435,6 +1437,8 @@ static int update_counters(struct net *net, sockptr_t arg, unsigned int len)
if (copy_from_sockptr(&hlp, arg, sizeof(hlp)))
return -EFAULT;
+ hlp.name[sizeof(hlp.name) - 1] = '\0';
+
if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter))
return -EINVAL;
@@ -2273,6 +2277,8 @@ static int compat_copy_ebt_replace_from_user(struct ebt_replace *repl,
memcpy(repl, &tmp, offsetof(struct ebt_replace, hook_entry));
+ repl->name[sizeof(repl->name) - 1] = '\0';
+
/* starting with hook_entry, 32 vs. 64 bit structures are different */
for (i = 0; i < NF_BR_NUMHOOKS; i++)
repl->hook_entry[i] = compat_ptr(tmp.hook_entry[i]);
@@ -2395,6 +2401,8 @@ static int compat_update_counters(struct net *net, sockptr_t arg,
if (copy_from_sockptr(&hlp, arg, sizeof(hlp)))
return -EFAULT;
+ hlp.name[sizeof(hlp.name) - 1] = '\0';
+
/* try real handler in case userland supplied needed padding */
if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter))
return update_counters(net, arg, len);
diff --git a/net/core/bpf_sk_storage.c b/net/core/bpf_sk_storage.c
index ecd659f79fd4..1d295a8769fa 100644
--- a/net/core/bpf_sk_storage.c
+++ b/net/core/bpf_sk_storage.c
@@ -158,8 +158,6 @@ int bpf_sk_storage_clone(const struct sock *sk, struct sock *newsk)
struct bpf_local_storage_elem *selem;
int ret = 0;
- RCU_INIT_POINTER(newsk->sk_bpf_storage, NULL);
-
rcu_read_lock_dont_migrate();
sk_storage = rcu_dereference(sk->sk_bpf_storage);
diff --git a/net/core/filter.c b/net/core/filter.c
index 4f5cbcac3e78..e4697036c67b 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -84,6 +84,9 @@
#include <linux/un.h>
#include <net/xdp_sock_drv.h>
#include <net/inet_dscp.h>
+#include <linux/icmpv6.h>
+#include <net/icmp.h>
+#include <net/ip6_route.h>
#include "dev.h"
@@ -12548,6 +12551,83 @@ __bpf_kfunc int bpf_xdp_pull_data(struct xdp_md *x, u32 len)
return 0;
}
+/**
+ * bpf_icmp_send - Send an ICMP control message
+ * @skb_ctx: Packet that triggered the control message
+ * @type: ICMP type (only ICMP_DEST_UNREACH/ICMPV6_DEST_UNREACH supported)
+ * @code: ICMP code (0-15 except ICMP_FRAG_NEEDED for IPv4, 0-6 for IPv6)
+ *
+ * Sends an ICMP control message in response to the packet. The original packet
+ * is cloned before sending the ICMP message, so the BPF program can still let
+ * the packet pass if desired.
+ *
+ * Currently only ICMP_DEST_UNREACH (IPv4) and ICMPV6_DEST_UNREACH (IPv6) are
+ * supported.
+ *
+ * Return: 0 on success (send attempt), negative error code on failure:
+ * -EBUSY: Recursion detected
+ * -EPROTONOSUPPORT: Non-IP protocol
+ * -EOPNOTSUPP: Unsupported ICMP type
+ * -EINVAL: Invalid code parameter
+ * -ENETUNREACH: No usable route/dst for the ICMP reply
+ * -ENOMEM: Memory allocation failed
+ */
+__bpf_kfunc int bpf_icmp_send(struct __sk_buff *skb_ctx, int type, int code)
+{
+ struct sk_buff *skb = (struct sk_buff *)skb_ctx;
+ struct sk_buff *nskb;
+ struct sock *sk;
+
+ sk = skb_to_full_sk(skb);
+ if (sk && sk->sk_kern_sock &&
+ (sk->sk_protocol == IPPROTO_ICMP || sk->sk_protocol == IPPROTO_ICMPV6))
+ return -EBUSY;
+
+ if (!skb_valid_dst(skb))
+ return -ENETUNREACH;
+
+ switch (skb->protocol) {
+#if IS_ENABLED(CONFIG_INET)
+ case htons(ETH_P_IP): {
+ if (type != ICMP_DEST_UNREACH)
+ return -EOPNOTSUPP;
+ if (code < 0 || code > NR_ICMP_UNREACH ||
+ code == ICMP_FRAG_NEEDED) /* needs a valid next-hop MTU */
+ return -EINVAL;
+
+ nskb = skb_clone(skb, GFP_ATOMIC);
+ if (!nskb)
+ return -ENOMEM;
+
+ memset(IPCB(nskb), 0, sizeof(*IPCB(nskb)));
+ icmp_send(nskb, type, code, 0);
+ consume_skb(nskb);
+ break;
+ }
+#endif
+#if IS_ENABLED(CONFIG_IPV6)
+ case htons(ETH_P_IPV6):
+ if (type != ICMPV6_DEST_UNREACH)
+ return -EOPNOTSUPP;
+ if (code < 0 || code > ICMPV6_REJECT_ROUTE)
+ return -EINVAL;
+
+ nskb = skb_clone(skb, GFP_ATOMIC);
+ if (!nskb)
+ return -ENOMEM;
+
+ memset(IP6CB(nskb), 0, sizeof(*IP6CB(nskb)));
+ icmpv6_send(nskb, type, code, 0);
+ consume_skb(nskb);
+ break;
+#endif
+ default:
+ return -EPROTONOSUPPORT;
+ }
+
+ return 0;
+}
+
__bpf_kfunc_end_defs();
int bpf_dynptr_from_skb_rdonly(struct __sk_buff *skb, u64 flags,
@@ -12590,6 +12670,10 @@ BTF_KFUNCS_START(bpf_kfunc_check_set_sock_ops)
BTF_ID_FLAGS(func, bpf_sock_ops_enable_tx_tstamp)
BTF_KFUNCS_END(bpf_kfunc_check_set_sock_ops)
+BTF_KFUNCS_START(bpf_kfunc_check_set_icmp_send)
+BTF_ID_FLAGS(func, bpf_icmp_send)
+BTF_KFUNCS_END(bpf_kfunc_check_set_icmp_send)
+
static const struct btf_kfunc_id_set bpf_kfunc_set_skb = {
.owner = THIS_MODULE,
.set = &bpf_kfunc_check_set_skb,
@@ -12620,6 +12704,11 @@ static const struct btf_kfunc_id_set bpf_kfunc_set_sock_ops = {
.set = &bpf_kfunc_check_set_sock_ops,
};
+static const struct btf_kfunc_id_set bpf_kfunc_set_icmp_send = {
+ .owner = THIS_MODULE,
+ .set = &bpf_kfunc_check_set_icmp_send,
+};
+
static int __init bpf_kfunc_init(void)
{
int ret;
@@ -12641,6 +12730,7 @@ static int __init bpf_kfunc_init(void)
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_CGROUP_SOCK_ADDR,
&bpf_kfunc_set_sock_addr);
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SCHED_CLS, &bpf_kfunc_set_tcp_reqsk);
+ ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_CGROUP_SKB, &bpf_kfunc_set_icmp_send);
return ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SOCK_OPS, &bpf_kfunc_set_sock_ops);
}
late_initcall(bpf_kfunc_init);
diff --git a/net/core/sock.c b/net/core/sock.c
index 8a59bfaa8096..498a57f34f5b 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -2492,6 +2492,9 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority,
sock_copy(newsk, sk);
newsk->sk_prot_creator = prot;
+#ifdef CONFIG_BPF_SYSCALL
+ RCU_INIT_POINTER(newsk->sk_bpf_storage, NULL);
+#endif
/* SANITY */
if (likely(newsk->sk_net_refcnt)) {
diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h
index 4ca2eca2e94b..3e969a070f9f 100644
--- a/net/ethtool/netlink.h
+++ b/net/ethtool/netlink.h
@@ -115,6 +115,34 @@ static inline void ethnl_update_u8(u8 *dst, const struct nlattr *attr,
}
/**
+ * ethnl_update_u8_u32() - update u8 value from an NLA_U32 attribute
+ * @dst: value to update
+ * @attr: netlink attribute with new value or null
+ * @mod: pointer to bool for modification tracking
+ *
+ * Some attributes are NLA_U32 on the wire but are stored in a u8. Read the
+ * full 32-bit value from NLA_U32 netlink attribute @attr and narrow it into
+ * the u8 pointed to by @dst; do nothing if @attr is null.
+ * Bool pointed to by @mod is set to true if this function changed the value
+ * of *dst, otherwise it is left as is.
+ */
+static inline void ethnl_update_u8_u32(u8 *dst, const struct nlattr *attr,
+ bool *mod)
+{
+ u32 val;
+
+ if (!attr)
+ return;
+ val = nla_get_u32(attr);
+ DEBUG_NET_WARN_ON_ONCE(val > U8_MAX);
+ if (*dst == val)
+ return;
+
+ *dst = val;
+ *mod = true;
+}
+
+/**
* ethnl_update_bool32() - update u32 used as bool from NLA_U8 attribute
* @dst: value to update
* @attr: netlink attribute with new value or null
diff --git a/net/ethtool/rss.c b/net/ethtool/rss.c
index d8adc78e3775..d4a1a4724b67 100644
--- a/net/ethtool/rss.c
+++ b/net/ethtool/rss.c
@@ -570,7 +570,7 @@ static const struct nla_policy ethnl_rss_flows_policy[] = {
const struct nla_policy ethnl_rss_set_policy[ETHTOOL_A_RSS_FLOW_HASH + 1] = {
[ETHTOOL_A_RSS_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy),
[ETHTOOL_A_RSS_CONTEXT] = { .type = NLA_U32, },
- [ETHTOOL_A_RSS_HFUNC] = NLA_POLICY_MIN(NLA_U32, 1),
+ [ETHTOOL_A_RSS_HFUNC] = NLA_POLICY_RANGE(NLA_U32, 1, U8_MAX),
[ETHTOOL_A_RSS_INDIR] = { .type = NLA_BINARY, },
[ETHTOOL_A_RSS_HKEY] = NLA_POLICY_MIN(NLA_BINARY, 1),
[ETHTOOL_A_RSS_INPUT_XFRM] =
@@ -851,7 +851,7 @@ ethnl_rss_set(struct ethnl_req_info *req_info, struct genl_info *info)
indir_mod = !!tb[ETHTOOL_A_RSS_INDIR];
rxfh.hfunc = data.hfunc;
- ethnl_update_u8(&rxfh.hfunc, tb[ETHTOOL_A_RSS_HFUNC], &mod);
+ ethnl_update_u8_u32(&rxfh.hfunc, tb[ETHTOOL_A_RSS_HFUNC], &mod);
if (rxfh.hfunc == data.hfunc)
rxfh.hfunc = ETH_RSS_HASH_NO_CHANGE;
@@ -860,7 +860,8 @@ ethnl_rss_set(struct ethnl_req_info *req_info, struct genl_info *info)
goto exit_free_indir;
rxfh.input_xfrm = data.input_xfrm;
- ethnl_update_u8(&rxfh.input_xfrm, tb[ETHTOOL_A_RSS_INPUT_XFRM], &mod);
+ ethnl_update_u8_u32(&rxfh.input_xfrm, tb[ETHTOOL_A_RSS_INPUT_XFRM],
+ &mod);
xfrm_sym = rxfh.input_xfrm || data.input_xfrm;
if (rxfh.input_xfrm == data.input_xfrm)
rxfh.input_xfrm = RXH_XFRM_NO_CHANGE;
@@ -934,7 +935,7 @@ const struct ethnl_request_ops ethnl_rss_request_ops = {
const struct nla_policy ethnl_rss_create_policy[ETHTOOL_A_RSS_INPUT_XFRM + 1] = {
[ETHTOOL_A_RSS_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy),
[ETHTOOL_A_RSS_CONTEXT] = NLA_POLICY_MIN(NLA_U32, 1),
- [ETHTOOL_A_RSS_HFUNC] = NLA_POLICY_MIN(NLA_U32, 1),
+ [ETHTOOL_A_RSS_HFUNC] = NLA_POLICY_RANGE(NLA_U32, 1, U8_MAX),
[ETHTOOL_A_RSS_INDIR] = NLA_POLICY_MIN(NLA_BINARY, 1),
[ETHTOOL_A_RSS_HKEY] = NLA_POLICY_MIN(NLA_BINARY, 1),
[ETHTOOL_A_RSS_INPUT_XFRM] =
@@ -1048,14 +1049,15 @@ int ethnl_rss_create_doit(struct sk_buff *skb, struct genl_info *info)
goto exit_clean_data;
indir_user_size = ret;
- ethnl_update_u8(&rxfh.hfunc, tb[ETHTOOL_A_RSS_HFUNC], &mod);
+ ethnl_update_u8_u32(&rxfh.hfunc, tb[ETHTOOL_A_RSS_HFUNC], &mod);
ret = rss_set_prep_hkey(dev, info, &data, &rxfh, &mod);
if (ret)
goto exit_free_indir;
rxfh.input_xfrm = RXH_XFRM_NO_CHANGE;
- ethnl_update_u8(&rxfh.input_xfrm, tb[ETHTOOL_A_RSS_INPUT_XFRM], &mod);
+ ethnl_update_u8_u32(&rxfh.input_xfrm, tb[ETHTOOL_A_RSS_INPUT_XFRM],
+ &mod);
ctx = ethtool_rxfh_ctx_alloc(ops, data.indir_size, data.hkey_size);
if (!ctx) {
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index fab1b76f5849..b80b8a92f46e 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -217,13 +217,18 @@ static void ip_sf_list_clear_all(struct ip_sf_list *psf)
static void igmp_stop_timer(struct ip_mc_list *im)
{
+ bool put = false;
+
spin_lock_bh(&im->lock);
if (timer_delete(&im->timer))
- refcount_dec(&im->refcnt);
+ put = true;
WRITE_ONCE(im->tm_running, 0);
WRITE_ONCE(im->reporter, 0);
im->unsolicit_count = 0;
spin_unlock_bh(&im->lock);
+
+ if (put)
+ ip_ma_put(im);
}
/* It must be called with locked im->lock */
@@ -248,20 +253,26 @@ static void igmp_gq_start_timer(struct in_device *in_dev)
return;
in_dev->mr_gq_running = 1;
- if (!mod_timer(&in_dev->mr_gq_timer, exp))
- in_dev_hold(in_dev);
+ if (in_dev_hold_safe(in_dev)) {
+ if (mod_timer(&in_dev->mr_gq_timer, exp))
+ in_dev_put(in_dev);
+ }
}
static void igmp_ifc_start_timer(struct in_device *in_dev, int delay)
{
- int tv = get_random_u32_below(delay);
+ if (in_dev_hold_safe(in_dev)) {
+ int tv = get_random_u32_below(delay);
- if (!mod_timer(&in_dev->mr_ifc_timer, jiffies+tv+2))
- in_dev_hold(in_dev);
+ if (mod_timer(&in_dev->mr_ifc_timer, jiffies + tv + 2))
+ in_dev_put(in_dev);
+ }
}
static void igmp_mod_timer(struct ip_mc_list *im, int max_delay)
{
+ bool put = false;
+
spin_lock_bh(&im->lock);
im->unsolicit_count = 0;
if (timer_delete(&im->timer)) {
@@ -271,10 +282,13 @@ static void igmp_mod_timer(struct ip_mc_list *im, int max_delay)
spin_unlock_bh(&im->lock);
return;
}
- refcount_dec(&im->refcnt);
+ put = true;
}
igmp_start_timer(im, max_delay);
spin_unlock_bh(&im->lock);
+
+ if (put)
+ ip_ma_put(im);
}
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 774f4c72a6fa..aaba4c2aae23 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -1084,8 +1084,10 @@ static void mld_gq_start_work(struct inet6_dev *idev)
mc_assert_locked(idev);
idev->mc_gq_running = 1;
- if (!mod_delayed_work(mld_wq, &idev->mc_gq_work, tv + 2))
- in6_dev_hold(idev);
+ if (in6_dev_hold_safe(idev)) {
+ if (mod_delayed_work(mld_wq, &idev->mc_gq_work, tv + 2))
+ in6_dev_put(idev);
+ }
}
static void mld_gq_stop_work(struct inet6_dev *idev)
@@ -1103,8 +1105,10 @@ static void mld_ifc_start_work(struct inet6_dev *idev, unsigned long delay)
mc_assert_locked(idev);
- if (!mod_delayed_work(mld_wq, &idev->mc_ifc_work, tv + 2))
- in6_dev_hold(idev);
+ if (in6_dev_hold_safe(idev)) {
+ if (mod_delayed_work(mld_wq, &idev->mc_ifc_work, tv + 2))
+ in6_dev_put(idev);
+ }
}
static void mld_ifc_stop_work(struct inet6_dev *idev)
@@ -1122,8 +1126,10 @@ static void mld_dad_start_work(struct inet6_dev *idev, unsigned long delay)
mc_assert_locked(idev);
- if (!mod_delayed_work(mld_wq, &idev->mc_dad_work, tv + 2))
- in6_dev_hold(idev);
+ if (in6_dev_hold_safe(idev)) {
+ if (mod_delayed_work(mld_wq, &idev->mc_dad_work, tv + 2))
+ in6_dev_put(idev);
+ }
}
static void mld_dad_stop_work(struct inet6_dev *idev)
@@ -1396,18 +1402,23 @@ static void mld_process_v2(struct inet6_dev *idev, struct mld2_query *mld,
void igmp6_event_query(struct sk_buff *skb)
{
struct inet6_dev *idev = __in6_dev_get(skb->dev);
+ bool put = false;
if (!idev || idev->dead)
goto out;
spin_lock_bh(&idev->mc_query_lock);
- if (skb_queue_len(&idev->mc_query_queue) < MLD_MAX_SKBS) {
+ if (skb_queue_len(&idev->mc_query_queue) < MLD_MAX_SKBS &&
+ in6_dev_hold_safe(idev)) {
__skb_queue_tail(&idev->mc_query_queue, skb);
- if (!mod_delayed_work(mld_wq, &idev->mc_query_work, 0))
- in6_dev_hold(idev);
+ if (mod_delayed_work(mld_wq, &idev->mc_query_work, 0))
+ put = true;
skb = NULL;
}
spin_unlock_bh(&idev->mc_query_lock);
+
+ if (put)
+ in6_dev_put(idev);
out:
kfree_skb(skb);
}
@@ -1571,18 +1582,23 @@ static void mld_query_work(struct work_struct *work)
void igmp6_event_report(struct sk_buff *skb)
{
struct inet6_dev *idev = __in6_dev_get(skb->dev);
+ bool put = false;
if (!idev || idev->dead)
goto out;
spin_lock_bh(&idev->mc_report_lock);
- if (skb_queue_len(&idev->mc_report_queue) < MLD_MAX_SKBS) {
+ if (skb_queue_len(&idev->mc_report_queue) < MLD_MAX_SKBS &&
+ in6_dev_hold_safe(idev)) {
__skb_queue_tail(&idev->mc_report_queue, skb);
- if (!mod_delayed_work(mld_wq, &idev->mc_report_work, 0))
- in6_dev_hold(idev);
+ if (mod_delayed_work(mld_wq, &idev->mc_report_work, 0))
+ put = true;
skb = NULL;
}
spin_unlock_bh(&idev->mc_report_lock);
+
+ if (put)
+ in6_dev_put(idev);
out:
kfree_skb(skb);
}
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 64ab23ff559b..599c49bf0a0a 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -348,7 +348,8 @@ static int nf_ct_frag6_reasm(struct frag_queue *fq, struct sk_buff *skb,
skb_network_header(skb)[fq->nhoffset] = skb_transport_header(skb)[0];
memmove(skb->head + sizeof(struct frag_hdr), skb->head,
(skb->data - skb->head) - sizeof(struct frag_hdr));
- skb->mac_header += sizeof(struct frag_hdr);
+ if (skb_mac_header_was_set(skb))
+ skb->mac_header += sizeof(struct frag_hdr);
skb->network_header += sizeof(struct frag_hdr);
skb_reset_transport_header(skb);
@@ -418,7 +419,7 @@ find_prev_fhdr(struct sk_buff *skb, u8 *prevhdrp, int *prevhoff, int *fhoff)
return -1;
}
if (skb_copy_bits(skb, start, &hdr, sizeof(hdr)))
- BUG();
+ return -1;
if (nexthdr == NEXTHDR_AUTH)
hdrlen = ipv6_authlen(&hdr);
else
diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h
index dedf59b661dd..8231317b0f1f 100644
--- a/net/netfilter/ipset/ip_set_hash_gen.h
+++ b/net/netfilter/ipset/ip_set_hash_gen.h
@@ -75,15 +75,17 @@ struct hbucket {
struct htable_gc {
struct delayed_work dwork;
struct ip_set *set; /* Set the gc belongs to */
+ spinlock_t lock; /* Lock to exclude gc and resize */
u32 region; /* Last gc run position */
};
/* The hash table: the table size stored here in order to make resizing easy */
struct htable {
- atomic_t ref; /* References for resizing */
+ bool resizing; /* Mark ongoing resize */
atomic_t uref; /* References for dumping and gc */
u8 htable_bits; /* size of hash table == 2^htable_bits */
u32 maxelem; /* Maxelem per region */
+ struct list_head ad; /* Resize add|del backlist */
struct ip_set_region *hregion; /* Region locks and ext sizes */
struct hbucket __rcu *bucket[]; /* hashtable buckets */
};
@@ -301,11 +303,13 @@ struct htype {
u8 netmask; /* netmask value for subnets to store */
union nf_inet_addr bitmask; /* stores bitmask */
#endif
- struct list_head ad; /* Resize add|del backlist */
- struct mtype_elem next; /* temporary storage for uadd */
#ifdef IP_SET_HASH_WITH_NETS
struct net_prefixes nets[NLEN]; /* book-keeping of prefixes */
#endif
+ /* Because 'next' is IPv4/IPv6 dependent, no elements of this
+ * structure and referred in create() may come after 'next'.
+ */
+ struct mtype_elem next; /* temporary storage for uadd */
};
/* ADD|DEL entries saved during resize */
@@ -451,13 +455,14 @@ static void
mtype_destroy(struct ip_set *set)
{
struct htype *h = set->data;
+ struct htable *t = (__force struct htable *)h->table;
struct list_head *l, *lt;
- mtype_ahash_destroy(set, (__force struct htable *)h->table, true);
- list_for_each_safe(l, lt, &h->ad) {
+ list_for_each_safe(l, lt, &t->ad) {
list_del(l);
kfree(l);
}
+ mtype_ahash_destroy(set, t, true);
kfree(h);
set->data = NULL;
@@ -569,9 +574,10 @@ mtype_gc(struct work_struct *work)
set = gc->set;
h = set->data;
- spin_lock_bh(&set->lock);
- t = ipset_dereference_set(h->table, set);
+ rcu_read_lock_bh();
+ t = rcu_dereference_bh(h->table);
atomic_inc(&t->uref);
+ rcu_read_unlock_bh();
numof_locks = ahash_numof_locks(t->htable_bits);
r = gc->region++;
if (r >= numof_locks) {
@@ -580,11 +586,13 @@ mtype_gc(struct work_struct *work)
next_run = (IPSET_GC_PERIOD(set->timeout) * HZ) / numof_locks;
if (next_run < HZ/10)
next_run = HZ/10;
- spin_unlock_bh(&set->lock);
- mtype_gc_do(set, h, t, r);
+ spin_lock_bh(&gc->lock);
+ if (!t->resizing)
+ mtype_gc_do(set, h, t, r);
+ spin_unlock_bh(&gc->lock);
- if (atomic_dec_and_test(&t->uref) && atomic_read(&t->ref)) {
+ if (atomic_dec_and_test(&t->uref) && t->resizing) {
pr_debug("Table destroy after resize by expire: %p\n", t);
mtype_ahash_destroy(set, t, false);
}
@@ -668,15 +676,18 @@ retry:
}
t->htable_bits = htable_bits;
t->maxelem = h->maxelem / ahash_numof_locks(htable_bits);
+ INIT_LIST_HEAD(&t->ad);
for (i = 0; i < ahash_numof_locks(htable_bits); i++)
spin_lock_init(&t->hregion[i].lock);
/* There can't be another parallel resizing,
- * but dumping, gc, kernel side add/del are possible
+ * but dumping and kernel side add/del are possible
*/
orig = ipset_dereference_bh_nfnl(h->table);
- atomic_set(&orig->ref, 1);
atomic_inc(&orig->uref);
+ spin_lock_bh(&h->gc.lock);
+ orig->resizing = true;
+ spin_unlock_bh(&h->gc.lock);
pr_debug("attempt to resize set %s from %u to %u, t %p\n",
set->name, orig->htable_bits, htable_bits, orig);
for (r = 0; r < ahash_numof_locks(orig->htable_bits); r++) {
@@ -768,7 +779,7 @@ retry:
* Kernel-side add cannot trigger a resize and userspace actions
* are serialized by the mutex.
*/
- list_for_each_safe(l, lt, &h->ad) {
+ list_for_each_safe(l, lt, &orig->ad) {
x = list_entry(l, struct mtype_resize_ad, list);
if (x->ad == IPSET_ADD) {
mtype_add(set, &x->d, &x->ext, &x->mext, x->flags);
@@ -792,11 +803,24 @@ out:
cleanup:
rcu_read_unlock_bh();
- atomic_set(&orig->ref, 0);
+ spin_lock_bh(&h->gc.lock);
+ orig->resizing = false;
+ spin_unlock_bh(&h->gc.lock);
+ /* Make sure parallel readers see that orig->resizing is false
+ * before we decrement uref */
+ synchronize_rcu();
atomic_dec(&orig->uref);
mtype_ahash_destroy(set, t, false);
if (ret == -EAGAIN)
goto retry;
+
+ /* Cleanup the backlog of ADD/DEL elements */
+ spin_lock_bh(&set->lock);
+ list_for_each_safe(l, lt, &orig->ad) {
+ list_del(l);
+ kfree(l);
+ }
+ spin_unlock_bh(&set->lock);
goto out;
hbwarn:
@@ -860,15 +884,13 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
key = HKEY(value, h->initval, t->htable_bits);
r = ahash_region(key);
atomic_inc(&t->uref);
+ rcu_read_unlock_bh();
elements = t->hregion[r].elements;
maxelem = t->maxelem;
if (elements >= maxelem) {
u32 e;
- if (SET_WITH_TIMEOUT(set)) {
- rcu_read_unlock_bh();
+ if (SET_WITH_TIMEOUT(set))
mtype_gc_do(set, h, t, r);
- rcu_read_lock_bh();
- }
maxelem = h->maxelem;
elements = 0;
for (e = 0; e < ahash_numof_locks(t->htable_bits); e++)
@@ -876,7 +898,6 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
if (elements >= maxelem && SET_WITH_FORCEADD(set))
forceadd = true;
}
- rcu_read_unlock_bh();
spin_lock_bh(&t->hregion[r].lock);
n = rcu_dereference_bh(hbucket(t, key));
@@ -1003,7 +1024,7 @@ overwrite_extensions:
ret = 0;
resize:
spin_unlock_bh(&t->hregion[r].lock);
- if (atomic_read(&t->ref) && ext->target) {
+ if (t->resizing && ext && ext->target) {
/* Resize is in process and kernel side add, save values */
struct mtype_resize_ad *x;
@@ -1017,7 +1038,7 @@ resize:
memcpy(&x->mext, mext, sizeof(struct ip_set_ext));
x->flags = flags;
spin_lock_bh(&set->lock);
- list_add_tail(&x->list, &h->ad);
+ list_add_tail(&x->list, &t->ad);
spin_unlock_bh(&set->lock);
}
goto out;
@@ -1030,7 +1051,7 @@ set_full:
unlock:
spin_unlock_bh(&t->hregion[r].lock);
out:
- if (atomic_dec_and_test(&t->uref) && atomic_read(&t->ref)) {
+ if (atomic_dec_and_test(&t->uref) && t->resizing) {
pr_debug("Table destroy after resize by add: %p\n", t);
mtype_ahash_destroy(set, t, false);
}
@@ -1093,7 +1114,7 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
#endif
ip_set_ext_destroy(set, data);
- if (atomic_read(&t->ref) && ext->target) {
+ if (t->resizing && ext && ext->target) {
/* Resize is in process and kernel side del,
* save values
*/
@@ -1141,10 +1162,10 @@ out:
spin_unlock_bh(&t->hregion[r].lock);
if (x) {
spin_lock_bh(&set->lock);
- list_add(&x->list, &h->ad);
+ list_add(&x->list, &t->ad);
spin_unlock_bh(&set->lock);
}
- if (atomic_dec_and_test(&t->uref) && atomic_read(&t->ref)) {
+ if (atomic_dec_and_test(&t->uref) && t->resizing) {
pr_debug("Table destroy after resize by del: %p\n", t);
mtype_ahash_destroy(set, t, false);
}
@@ -1353,7 +1374,7 @@ mtype_uref(struct ip_set *set, struct netlink_callback *cb, bool start)
rcu_read_unlock_bh();
} else if (cb->args[IPSET_CB_PRIVATE]) {
t = (struct htable *)cb->args[IPSET_CB_PRIVATE];
- if (atomic_dec_and_test(&t->uref) && atomic_read(&t->ref)) {
+ if (atomic_dec_and_test(&t->uref) && t->resizing) {
pr_debug("Table destroy after resize "
" by dump: %p\n", t);
mtype_ahash_destroy(set, t, false);
@@ -1566,7 +1587,13 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
if (tb[IPSET_ATTR_MAXELEM])
maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
- hsize = sizeof(*h);
+#ifdef IP_SET_PROTO_UNDEF
+ hsize = sizeof(struct htype);
+#else
+ hsize = set->family == NFPROTO_IPV6 ?
+ sizeof(struct IPSET_TOKEN(HTYPE, 6)) :
+ sizeof(struct IPSET_TOKEN(HTYPE, 4));
+#endif
h = kzalloc(hsize, GFP_KERNEL);
if (!h)
return -ENOMEM;
@@ -1593,6 +1620,7 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
return -ENOMEM;
}
h->gc.set = set;
+ spin_lock_init(&h->gc.lock);
for (i = 0; i < ahash_numof_locks(hbits); i++)
spin_lock_init(&t->hregion[i].lock);
h->maxelem = maxelem;
@@ -1619,9 +1647,8 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
}
t->htable_bits = hbits;
t->maxelem = h->maxelem / ahash_numof_locks(hbits);
+ INIT_LIST_HEAD(&t->ad);
RCU_INIT_POINTER(h->table, t);
-
- INIT_LIST_HEAD(&h->ad);
set->data = h;
#ifndef IP_SET_PROTO_UNDEF
if (set->family == NFPROTO_IPV4) {
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index 906f2c361676..35cbe821c259 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -398,10 +398,10 @@ ip_vs_conn_stats(struct ip_vs_conn *cp, struct ip_vs_service *svc)
static inline void
ip_vs_set_state(struct ip_vs_conn *cp, int direction,
const struct sk_buff *skb,
- struct ip_vs_proto_data *pd)
+ struct ip_vs_proto_data *pd, unsigned int iph_len)
{
if (likely(pd->pp->state_transition))
- pd->pp->state_transition(cp, direction, skb, pd);
+ pd->pp->state_transition(cp, direction, skb, pd, iph_len);
}
static inline int
@@ -803,7 +803,7 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
ip_vs_in_stats(cp, skb);
/* set state */
- ip_vs_set_state(cp, IP_VS_DIR_INPUT, skb, pd);
+ ip_vs_set_state(cp, IP_VS_DIR_INPUT, skb, pd, iph->len);
/* transmit the first SYN packet */
ret = cp->packet_xmit(skb, cp, pd->pp, iph);
@@ -1484,7 +1484,7 @@ handle_response(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,
after_nat:
ip_vs_out_stats(cp, skb);
- ip_vs_set_state(cp, IP_VS_DIR_OUTPUT, skb, pd);
+ ip_vs_set_state(cp, IP_VS_DIR_OUTPUT, skb, pd, iph->len);
skb->ipvs_property = 1;
if (!(cp->flags & IP_VS_CONN_F_NFCT))
ip_vs_notrack(skb);
@@ -1767,6 +1767,7 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
bool tunnel, new_cp = false;
union nf_inet_addr *raddr;
char *outer_proto = "IPIP";
+ unsigned int hlen_ipip;
int ulen = 0;
*related = 1;
@@ -1804,9 +1805,10 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
/* Now find the contained IP header */
offset += sizeof(_icmph);
cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
- if (cih == NULL)
+ if (!(cih && cih->version == 4 && cih->ihl >= 5))
return NF_ACCEPT; /* The packet looks wrong, ignore */
raddr = (union nf_inet_addr *)&cih->daddr;
+ hlen_ipip = cih->ihl * 4;
/* Special case for errors for IPIP/UDP/GRE tunnel packets */
tunnel = false;
@@ -1822,9 +1824,9 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
/* Only for known tunnel */
if (!dest || dest->tun_type != IP_VS_CONN_F_TUNNEL_TYPE_IPIP)
return NF_ACCEPT;
- offset += cih->ihl * 4;
+ offset += hlen_ipip;
cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
- if (cih == NULL)
+ if (!(cih && cih->version == 4 && cih->ihl >= 5))
return NF_ACCEPT; /* The packet looks wrong, ignore */
tunnel = true;
} else if ((cih->protocol == IPPROTO_UDP || /* Can be UDP encap */
@@ -1836,7 +1838,7 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
/* Non-first fragment has no UDP/GRE header */
if (unlikely(cih->frag_off & htons(IP_OFFSET)))
return NF_ACCEPT;
- offset2 = offset + cih->ihl * 4;
+ offset2 = offset + hlen_ipip;
if (cih->protocol == IPPROTO_UDP) {
ulen = ipvs_udp_decap(ipvs, skb, offset2, AF_INET,
raddr, &iproto);
@@ -1905,6 +1907,7 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
}
if (tunnel) {
+ unsigned int hlen_orig = cih->ihl * 4;
__be32 info = ic->un.gateway;
__u8 type = ic->type;
__u8 code = ic->code;
@@ -1921,6 +1924,9 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
goto ignore_tunnel;
offset2 -= ihl + sizeof(_icmph);
skb_reset_network_header(skb);
+ /* Ensure the IP header is present in headroom */
+ if (!pskb_may_pull(skb, hlen_ipip))
+ goto ignore_tunnel;
IP_VS_DBG(12, "ICMP for %s %pI4->%pI4: mtu=%u\n",
outer_proto, &ip_hdr(skb)->saddr,
&ip_hdr(skb)->daddr, mtu);
@@ -1936,8 +1942,8 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
if (dest_dst)
mtu = dst_mtu(dest_dst->dst_cache);
}
- if (mtu > 68 + sizeof(struct iphdr) + ulen)
- mtu -= sizeof(struct iphdr) + ulen;
+ if (mtu > 68 + hlen_ipip + ulen)
+ mtu -= hlen_ipip + ulen;
info = htonl(mtu);
}
/* Strip outer IP, ICMP and IPIP/UDP/GRE, go to IP header of
@@ -1946,6 +1952,9 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
if (pskb_pull(skb, offset2) == NULL)
goto ignore_tunnel;
skb_reset_network_header(skb);
+ /* Ensure the IP header is present in headroom */
+ if (!pskb_may_pull(skb, hlen_orig))
+ goto ignore_tunnel;
IP_VS_DBG(12, "Sending ICMP for %pI4->%pI4: t=%u, c=%u, i=%u\n",
&ip_hdr(skb)->saddr, &ip_hdr(skb)->daddr,
type, code, ntohl(info));
@@ -2233,7 +2242,7 @@ ip_vs_in_hook(void *priv, struct sk_buff *skb, const struct nf_hook_state *state
IP_VS_DBG_PKT(11, af, pp, skb, iph.off, "Incoming packet");
ip_vs_in_stats(cp, skb);
- ip_vs_set_state(cp, IP_VS_DIR_INPUT, skb, pd);
+ ip_vs_set_state(cp, IP_VS_DIR_INPUT, skb, pd, iph.len);
if (cp->packet_xmit)
ret = cp->packet_xmit(skb, cp, pp, &iph);
/* do not touch skb anymore */
diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c
index 63c78a1f3918..c67317be17df 100644
--- a/net/netfilter/ipvs/ip_vs_proto_sctp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c
@@ -372,20 +372,15 @@ static const char *sctp_state_name(int state)
static inline void
set_sctp_state(struct ip_vs_proto_data *pd, struct ip_vs_conn *cp,
- int direction, const struct sk_buff *skb)
+ int direction, const struct sk_buff *skb,
+ unsigned int iph_len)
{
struct sctp_chunkhdr _sctpch, *sch;
unsigned char chunk_type;
int event, next_state;
- int ihl, cofs;
+ int cofs;
-#ifdef CONFIG_IP_VS_IPV6
- ihl = cp->af == AF_INET ? ip_hdrlen(skb) : sizeof(struct ipv6hdr);
-#else
- ihl = ip_hdrlen(skb);
-#endif
-
- cofs = ihl + sizeof(struct sctphdr);
+ cofs = iph_len + sizeof(struct sctphdr);
sch = skb_header_pointer(skb, cofs, sizeof(_sctpch), &_sctpch);
if (sch == NULL)
return;
@@ -468,10 +463,11 @@ set_sctp_state(struct ip_vs_proto_data *pd, struct ip_vs_conn *cp,
static void
sctp_state_transition(struct ip_vs_conn *cp, int direction,
- const struct sk_buff *skb, struct ip_vs_proto_data *pd)
+ const struct sk_buff *skb, struct ip_vs_proto_data *pd,
+ unsigned int iph_len)
{
spin_lock_bh(&cp->lock);
- set_sctp_state(pd, cp, direction, skb);
+ set_sctp_state(pd, cp, direction, skb, iph_len);
spin_unlock_bh(&cp->lock);
}
diff --git a/net/netfilter/ipvs/ip_vs_proto_tcp.c b/net/netfilter/ipvs/ip_vs_proto_tcp.c
index 8cc0a8ce6241..f86b763efcc4 100644
--- a/net/netfilter/ipvs/ip_vs_proto_tcp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_tcp.c
@@ -579,17 +579,12 @@ set_tcp_state(struct ip_vs_proto_data *pd, struct ip_vs_conn *cp,
static void
tcp_state_transition(struct ip_vs_conn *cp, int direction,
const struct sk_buff *skb,
- struct ip_vs_proto_data *pd)
+ struct ip_vs_proto_data *pd,
+ unsigned int iph_len)
{
struct tcphdr _tcph, *th;
-#ifdef CONFIG_IP_VS_IPV6
- int ihl = cp->af == AF_INET ? ip_hdrlen(skb) : sizeof(struct ipv6hdr);
-#else
- int ihl = ip_hdrlen(skb);
-#endif
-
- th = skb_header_pointer(skb, ihl, sizeof(_tcph), &_tcph);
+ th = skb_header_pointer(skb, iph_len, sizeof(_tcph), &_tcph);
if (th == NULL)
return;
diff --git a/net/netfilter/ipvs/ip_vs_proto_udp.c b/net/netfilter/ipvs/ip_vs_proto_udp.c
index f9de632e38cd..58f9e255927e 100644
--- a/net/netfilter/ipvs/ip_vs_proto_udp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_udp.c
@@ -444,7 +444,8 @@ static const char * udp_state_name(int state)
static void
udp_state_transition(struct ip_vs_conn *cp, int direction,
const struct sk_buff *skb,
- struct ip_vs_proto_data *pd)
+ struct ip_vs_proto_data *pd,
+ unsigned int iph_len)
{
if (unlikely(!pd)) {
pr_err("UDP no ns data\n");
diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c
index 99c5b9d671a0..2a829b5e8240 100644
--- a/net/netfilter/nf_flow_table_core.c
+++ b/net/netfilter/nf_flow_table_core.c
@@ -127,12 +127,18 @@ static int flow_offload_fill_route(struct flow_offload *flow,
switch (route->tuple[dir].xmit_type) {
case FLOW_OFFLOAD_XMIT_DIRECT:
+ if (flow_tuple->tun_num) {
+ flow_tuple->dst_cache = dst;
+ flow_tuple->dst_cookie =
+ flow_offload_dst_cookie(flow_tuple);
+ }
memcpy(flow_tuple->out.h_dest, route->tuple[dir].out.h_dest,
ETH_ALEN);
memcpy(flow_tuple->out.h_source, route->tuple[dir].out.h_source,
ETH_ALEN);
flow_tuple->out.ifidx = route->tuple[dir].out.ifindex;
- dst_release(dst);
+ if (!flow_tuple->tun_num)
+ dst_release(dst);
break;
case FLOW_OFFLOAD_XMIT_XFRM:
case FLOW_OFFLOAD_XMIT_NEIGH:
@@ -152,9 +158,7 @@ static int flow_offload_fill_route(struct flow_offload *flow,
static void nft_flow_dst_release(struct flow_offload *flow,
enum flow_offload_tuple_dir dir)
{
- if (flow->tuplehash[dir].tuple.xmit_type == FLOW_OFFLOAD_XMIT_NEIGH ||
- flow->tuplehash[dir].tuple.xmit_type == FLOW_OFFLOAD_XMIT_XFRM)
- dst_release(flow->tuplehash[dir].tuple.dst_cache);
+ dst_release(flow->tuplehash[dir].tuple.dst_cache);
}
void flow_offload_route_init(struct flow_offload *flow,
@@ -345,10 +349,8 @@ int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow)
nf_ct_refresh(flow->ct, NF_CT_DAY);
- if (nf_flowtable_hw_offload(flow_table)) {
- __set_bit(NF_FLOW_HW, &flow->flags);
+ if (nf_flowtable_hw_offload(flow_table))
nf_flow_offload_add(flow_table, flow);
- }
return 0;
}
@@ -369,7 +371,8 @@ void flow_offload_refresh(struct nf_flowtable *flow_table,
test_bit(NF_FLOW_CLOSING, &flow->flags))
return;
- nf_flow_offload_add(flow_table, flow);
+ if (test_bit(NF_FLOW_HW, &flow->flags))
+ nf_flow_offload_refresh(flow_table, flow);
}
EXPORT_SYMBOL_GPL(flow_offload_refresh);
diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c
index 29e93ac1e2e4..0b78decce8a9 100644
--- a/net/netfilter/nf_flow_table_ip.c
+++ b/net/netfilter/nf_flow_table_ip.c
@@ -299,8 +299,7 @@ static bool nf_flow_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu)
static inline bool nf_flow_dst_check(struct flow_offload_tuple *tuple)
{
- if (tuple->xmit_type != FLOW_OFFLOAD_XMIT_NEIGH &&
- tuple->xmit_type != FLOW_OFFLOAD_XMIT_XFRM)
+ if (!tuple->dst_cache)
return true;
return dst_check(tuple->dst_cache, tuple->dst_cookie);
@@ -590,10 +589,10 @@ static int nf_flow_pppoe_push(struct sk_buff *skb, u16 id,
static int nf_flow_tunnel_ipip_push(struct net *net, struct sk_buff *skb,
struct flow_offload_tuple *tuple,
- __be32 *ip_daddr)
+ struct dst_entry *dst, __be32 *ip_daddr)
{
struct iphdr *iph = (struct iphdr *)skb_network_header(skb);
- struct rtable *rt = dst_rtable(tuple->dst_cache);
+ struct rtable *rt = dst_rtable(dst);
u8 tos = iph->tos, ttl = iph->ttl;
__be16 frag_off = iph->frag_off;
u32 headroom = sizeof(*iph);
@@ -636,21 +635,22 @@ static int nf_flow_tunnel_ipip_push(struct net *net, struct sk_buff *skb,
static int nf_flow_tunnel_v4_push(struct net *net, struct sk_buff *skb,
struct flow_offload_tuple *tuple,
- __be32 *ip_daddr)
+ struct dst_entry *dst, __be32 *ip_daddr)
{
if (tuple->tun_num)
- return nf_flow_tunnel_ipip_push(net, skb, tuple, ip_daddr);
+ return nf_flow_tunnel_ipip_push(net, skb, tuple, dst, ip_daddr);
return 0;
}
static int nf_flow_tunnel_ip6ip6_push(struct net *net, struct sk_buff *skb,
struct flow_offload_tuple *tuple,
+ struct dst_entry *dst,
struct in6_addr **ip6_daddr)
{
struct ipv6hdr *ip6h = (struct ipv6hdr *)skb_network_header(skb);
- struct rtable *rt = dst_rtable(tuple->dst_cache);
__u8 dsfield = ipv6_get_dsfield(ip6h);
+ struct rtable *rt = dst_rtable(dst);
struct flowi6 fl6 = {
.daddr = tuple->tun.src_v6,
.saddr = tuple->tun.dst_v6,
@@ -696,10 +696,11 @@ static int nf_flow_tunnel_ip6ip6_push(struct net *net, struct sk_buff *skb,
static int nf_flow_tunnel_v6_push(struct net *net, struct sk_buff *skb,
struct flow_offload_tuple *tuple,
+ struct dst_entry *dst,
struct in6_addr **ip6_daddr)
{
if (tuple->tun_num)
- return nf_flow_tunnel_ip6ip6_push(net, skb, tuple, ip6_daddr);
+ return nf_flow_tunnel_ip6ip6_push(net, skb, tuple, dst, ip6_daddr);
return 0;
}
@@ -842,7 +843,8 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
other_tuple = &flow->tuplehash[!dir].tuple;
ip_daddr = other_tuple->src_v4.s_addr;
- if (nf_flow_tunnel_v4_push(state->net, skb, other_tuple, &ip_daddr) < 0)
+ if (nf_flow_tunnel_v4_push(state->net, skb, other_tuple,
+ tuplehash->tuple.dst_cache, &ip_daddr) < 0)
return NF_DROP;
switch (tuplehash->tuple.xmit_type) {
@@ -1158,6 +1160,7 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
ip6_daddr = &other_tuple->src_v6;
if (nf_flow_tunnel_v6_push(state->net, skb, other_tuple,
+ tuplehash->tuple.dst_cache,
&ip6_daddr) < 0)
return NF_DROP;
diff --git a/net/netfilter/nf_flow_table_offload.c b/net/netfilter/nf_flow_table_offload.c
index 002ec15d988b..801a3dd9ceea 100644
--- a/net/netfilter/nf_flow_table_offload.c
+++ b/net/netfilter/nf_flow_table_offload.c
@@ -1101,9 +1101,17 @@ nf_flow_offload_work_alloc(struct nf_flowtable *flowtable,
return offload;
}
+static bool nf_flow_offload_unsupported(struct flow_offload *flow)
+{
+ if (flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.tun_num ||
+ flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.tun_num)
+ return true;
-void nf_flow_offload_add(struct nf_flowtable *flowtable,
- struct flow_offload *flow)
+ return false;
+}
+
+void nf_flow_offload_refresh(struct nf_flowtable *flowtable,
+ struct flow_offload *flow)
{
struct flow_offload_work *offload;
@@ -1114,6 +1122,16 @@ void nf_flow_offload_add(struct nf_flowtable *flowtable,
flow_offload_queue_work(offload);
}
+void nf_flow_offload_add(struct nf_flowtable *flowtable,
+ struct flow_offload *flow)
+{
+ if (nf_flow_offload_unsupported(flow))
+ return;
+
+ set_bit(NF_FLOW_HW, &flow->flags);
+ nf_flow_offload_refresh(flowtable, flow);
+}
+
void nf_flow_offload_del(struct nf_flowtable *flowtable,
struct flow_offload *flow)
{
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index fa3657599861..5fee61b3813c 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -676,7 +676,7 @@ __build_packet_message(struct nfnl_log_net *log,
goto nla_put_failure;
if (skb_copy_bits(skb, 0, nla_data(nla), data_len))
- BUG();
+ goto nla_put_failure;
}
nlh->nlmsg_len = inst->skb->tail - old_tail;
@@ -698,6 +698,21 @@ static const struct nf_loginfo default_loginfo = {
},
};
+static unsigned int nfulnl_get_copy_len(const struct nf_loginfo *li,
+ const struct sk_buff *skb,
+ unsigned int copy_len)
+{
+ unsigned int len = skb->len;
+
+ if ((li->u.ulog.flags & NF_LOG_F_COPY_LEN) &&
+ li->u.ulog.copy_len < copy_len)
+ copy_len = li->u.ulog.copy_len;
+ if (!skb_frags_readable(skb))
+ len = skb_headlen(skb);
+
+ return min(len, copy_len);
+}
+
/* log handler for internal netfilter logging api */
static void
nfulnl_log_packet(struct net *net,
@@ -790,14 +805,7 @@ nfulnl_log_packet(struct net *net,
break;
case NFULNL_COPY_PACKET:
- data_len = inst->copy_range;
- if ((li->u.ulog.flags & NF_LOG_F_COPY_LEN) &&
- (li->u.ulog.copy_len < data_len))
- data_len = li->u.ulog.copy_len;
-
- if (data_len > skb->len)
- data_len = skb->len;
-
+ data_len = nfulnl_get_copy_len(li, skb, inst->copy_range);
size += nla_total_size(data_len);
break;
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index 35d4c6c628ff..b8aaf39cb4d8 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -690,6 +690,17 @@ static int nfqnl_put_master_ifindex(struct sk_buff *nlskb, int attr,
}
#endif
+static unsigned int nfqnl_get_data_len(const struct sk_buff *entskb,
+ unsigned int copy_range)
+{
+ unsigned int data_len = entskb->len;
+
+ if (!skb_frags_readable(entskb))
+ data_len = skb_headlen(entskb);
+
+ return min(data_len, copy_range);
+}
+
static struct sk_buff *
nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
struct nf_queue_entry *entry,
@@ -755,10 +766,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
nf_queue_checksum_help(entskb))
return NULL;
- data_len = READ_ONCE(queue->copy_range);
- if (data_len > entskb->len)
- data_len = entskb->len;
-
+ data_len = nfqnl_get_data_len(entskb, READ_ONCE(queue->copy_range));
hlen = skb_zerocopy_headlen(entskb);
hlen = min_t(unsigned int, hlen, data_len);
size += sizeof(struct nlattr) + hlen;
diff --git a/net/netfilter/nft_lookup.c b/net/netfilter/nft_lookup.c
index ba512e94b402..19887439847d 100644
--- a/net/netfilter/nft_lookup.c
+++ b/net/netfilter/nft_lookup.c
@@ -103,13 +103,13 @@ void nft_lookup_eval(const struct nft_expr *expr,
bool found;
ext = nft_set_do_lookup(net, set, &regs->data[priv->sreg]);
+ if (!ext)
+ ext = nft_set_catchall_lookup(net, set);
+
found = !!ext ^ priv->invert;
if (!found) {
- ext = nft_set_catchall_lookup(net, set);
- if (!ext) {
- regs->verdict.code = NFT_BREAK;
- return;
- }
+ regs->verdict.code = NFT_BREAK;
+ return;
}
if (ext) {
diff --git a/net/netfilter/xt_u32.c b/net/netfilter/xt_u32.c
index ec1a21e3b6e2..dabbaa742874 100644
--- a/net/netfilter/xt_u32.c
+++ b/net/netfilter/xt_u32.c
@@ -14,8 +14,8 @@
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/xt_u32.h>
-static bool u32_match_it(const struct xt_u32 *data,
- const struct sk_buff *skb)
+static int u32_match_it(const struct xt_u32 *data,
+ const struct sk_buff *skb)
{
const struct xt_u32_test *ct;
unsigned int testind;
@@ -40,7 +40,8 @@ static bool u32_match_it(const struct xt_u32 *data,
return false;
if (skb_copy_bits(skb, pos, &n, sizeof(n)) < 0)
- BUG();
+ return -1;
+
val = ntohl(n);
nnums = ct->nnums;
@@ -68,7 +69,7 @@ static bool u32_match_it(const struct xt_u32 *data,
if (skb_copy_bits(skb, at + pos, &n,
sizeof(n)) < 0)
- BUG();
+ return -1;
val = ntohl(n);
break;
}
@@ -90,9 +91,14 @@ static bool u32_match_it(const struct xt_u32 *data,
static bool u32_mt(const struct sk_buff *skb, struct xt_action_param *par)
{
const struct xt_u32 *data = par->matchinfo;
- bool ret;
+ int ret;
ret = u32_match_it(data, skb);
+ if (ret < 0) {
+ par->hotdrop = true;
+ return false;
+ }
+
return ret ^ data->invert;
}
diff --git a/rust/kernel/iommu/pgtable.rs b/rust/kernel/iommu/pgtable.rs
index c88e38fd938a..eddda8d9d62a 100644
--- a/rust/kernel/iommu/pgtable.rs
+++ b/rust/kernel/iommu/pgtable.rs
@@ -102,8 +102,7 @@ impl<F: IoPageTableFmt> IoPageTable<F> {
coherent_walk: config.coherent_walk,
tlb: &raw const NOOP_FLUSH_OPS,
iommu_dev: dev.as_raw(),
- // SAFETY: All zeroes is a valid value for `struct io_pgtable_cfg`.
- ..unsafe { core::mem::zeroed() }
+ ..Zeroable::zeroed()
};
// SAFETY:
diff --git a/rust/kernel/module_param.rs b/rust/kernel/module_param.rs
index 6541af218390..a1724c890566 100644
--- a/rust/kernel/module_param.rs
+++ b/rust/kernel/module_param.rs
@@ -130,10 +130,26 @@ impl<T> ModuleParamAccess<T> {
}
}
+ /// Get a copy of the parameter value.
+ ///
+ /// Returns the value supplied at module load time, or the default value
+ /// if the parameter has not been set.
+ #[inline]
+ pub fn value(&self) -> T
+ where
+ T: Copy,
+ {
+ self.value.copy().unwrap_or(self.default)
+ }
+
/// Get a shared reference to the parameter value.
+ ///
+ /// Returns a reference to the value supplied at module load time, or a
+ /// reference to the default value if the parameter has not been set.
// Note: When sysfs access to parameters are enabled, we have to pass in a
// held lock guard here.
- pub fn value(&self) -> &T {
+ #[inline]
+ pub fn value_ref(&self) -> &T {
self.value.as_ref().unwrap_or(&self.default)
}
diff --git a/rust/kernel/usb.rs b/rust/kernel/usb.rs
index 7aff0c82d0af..bbf85366d2c9 100644
--- a/rust/kernel/usb.rs
+++ b/rust/kernel/usb.rs
@@ -24,11 +24,8 @@ use crate::{
};
use core::{
marker::PhantomData,
- mem::{
- offset_of,
- MaybeUninit, //
- },
- ptr::NonNull,
+ mem::offset_of,
+ ptr::NonNull, //
};
/// An adapter for the registration of USB drivers.
@@ -130,8 +127,7 @@ impl DeviceId {
match_flags: bindings::USB_DEVICE_ID_MATCH_DEVICE as u16,
idVendor: vendor,
idProduct: product,
- // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`.
- ..unsafe { MaybeUninit::zeroed().assume_init() }
+ ..pin_init::zeroed()
})
}
@@ -143,8 +139,7 @@ impl DeviceId {
idProduct: product,
bcdDevice_lo: bcd_lo,
bcdDevice_hi: bcd_hi,
- // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`.
- ..unsafe { MaybeUninit::zeroed().assume_init() }
+ ..pin_init::zeroed()
})
}
@@ -155,8 +150,7 @@ impl DeviceId {
bDeviceClass: class,
bDeviceSubClass: subclass,
bDeviceProtocol: protocol,
- // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`.
- ..unsafe { MaybeUninit::zeroed().assume_init() }
+ ..pin_init::zeroed()
})
}
@@ -167,8 +161,7 @@ impl DeviceId {
bInterfaceClass: class,
bInterfaceSubClass: subclass,
bInterfaceProtocol: protocol,
- // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`.
- ..unsafe { MaybeUninit::zeroed().assume_init() }
+ ..pin_init::zeroed()
})
}
@@ -180,8 +173,7 @@ impl DeviceId {
idVendor: vendor,
idProduct: product,
bInterfaceClass: class,
- // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`.
- ..unsafe { MaybeUninit::zeroed().assume_init() }
+ ..pin_init::zeroed()
})
}
@@ -193,8 +185,7 @@ impl DeviceId {
idVendor: vendor,
idProduct: product,
bInterfaceProtocol: protocol,
- // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`.
- ..unsafe { MaybeUninit::zeroed().assume_init() }
+ ..pin_init::zeroed()
})
}
@@ -206,8 +197,7 @@ impl DeviceId {
idVendor: vendor,
idProduct: product,
bInterfaceNumber: number,
- // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`.
- ..unsafe { MaybeUninit::zeroed().assume_init() }
+ ..pin_init::zeroed()
})
}
@@ -227,8 +217,7 @@ impl DeviceId {
bInterfaceClass: class,
bInterfaceSubClass: subclass,
bInterfaceProtocol: protocol,
- // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`.
- ..unsafe { MaybeUninit::zeroed().assume_init() }
+ ..pin_init::zeroed()
})
}
}
diff --git a/samples/damon/mtier.c b/samples/damon/mtier.c
index e567f4edd80e..ac9c24b92ead 100644
--- a/samples/damon/mtier.c
+++ b/samples/damon/mtier.c
@@ -193,8 +193,6 @@ static int damon_sample_mtier_start(void)
if (!err)
return 0;
- if (damon_is_running(ctxs[0]))
- damon_stop(ctxs, 1);
damon_destroy_ctx(ctxs[0]);
damon_destroy_ctx(ctxs[1]);
return err;
@@ -202,8 +200,7 @@ static int damon_sample_mtier_start(void)
static void damon_sample_mtier_stop(void)
{
- damon_stop(ctxs, 1);
- damon_stop(&ctxs[1], 1);
+ damon_stop(ctxs, 2);
damon_destroy_ctx(ctxs[0]);
damon_destroy_ctx(ctxs[1]);
}
diff --git a/samples/damon/prcl.c b/samples/damon/prcl.c
index edeae145c4a8..842099bd6228 100644
--- a/samples/damon/prcl.c
+++ b/samples/damon/prcl.c
@@ -113,10 +113,8 @@ static int damon_sample_prcl_start(void)
repeat_call_control.data = ctx;
err = damon_call(ctx, &repeat_call_control);
- if (err) {
- damon_stop(&ctx, 1);
+ if (err)
damon_destroy_ctx(ctx);
- }
return err;
}
diff --git a/samples/damon/wsse.c b/samples/damon/wsse.c
index ff5e8a890f44..37fd5da20158 100644
--- a/samples/damon/wsse.c
+++ b/samples/damon/wsse.c
@@ -93,10 +93,8 @@ static int damon_sample_wsse_start(void)
}
repeat_call_control.data = ctx;
err = damon_call(ctx, &repeat_call_control);
- if (err) {
- damon_stop(&ctx, 1);
+ if (err)
damon_destroy_ctx(ctx);
- }
return err;
}
diff --git a/samples/rust/rust_minimal.rs b/samples/rust/rust_minimal.rs
index 8eb9583571d7..60d03df6cd80 100644
--- a/samples/rust/rust_minimal.rs
+++ b/samples/rust/rust_minimal.rs
@@ -28,7 +28,7 @@ impl kernel::Module for RustMinimal {
pr_info!("Am I built-in? {}\n", !cfg!(MODULE));
pr_info!(
"test_parameter: {}\n",
- *module_parameters::test_parameter.value()
+ module_parameters::test_parameter.value()
);
let mut numbers = KVec::new();
diff --git a/scripts/module.lds.S b/scripts/module.lds.S
index b62683061d79..d0f200428957 100644
--- a/scripts/module.lds.S
+++ b/scripts/module.lds.S
@@ -3,11 +3,6 @@
* Archs are free to supply their own linker scripts. ld will
* combine them automatically.
*/
-#ifdef CONFIG_UNWIND_TABLES
-#define DISCARD_EH_FRAME
-#else
-#define DISCARD_EH_FRAME *(.eh_frame)
-#endif
#include <asm-generic/codetag.lds.h>
diff --git a/security/landlock/task.c b/security/landlock/task.c
index 474642edbd59..55522a601367 100644
--- a/security/landlock/task.c
+++ b/security/landlock/task.c
@@ -95,8 +95,7 @@ static int hook_ptrace_access_check(struct task_struct *const child,
if (!parent_subject)
return 0;
- scoped_guard(rcu)
- {
+ scoped_guard(rcu) {
const struct landlock_ruleset *const child_dom =
landlock_get_task_domain(child);
err = domain_ptrace(parent_subject->domain, child_dom);
@@ -381,8 +380,7 @@ static int hook_task_kill(struct task_struct *const p,
if (!subject)
return 0;
- scoped_guard(rcu)
- {
+ scoped_guard(rcu) {
is_scoped = domain_is_scoped(subject->domain,
landlock_get_task_domain(p),
signal_scope.scope);
@@ -433,8 +431,7 @@ static int hook_file_send_sigiotask(struct task_struct *tsk,
if (task_tgid(tsk) == landlock_file(fown->file)->fown_tg)
return 0;
- scoped_guard(rcu)
- {
+ scoped_guard(rcu) {
is_scoped = domain_is_scoped(subject->domain,
landlock_get_task_domain(tsk),
signal_scope.scope);
diff --git a/sound/core/control.c b/sound/core/control.c
index 037e455bb11b..73d7ba0f509f 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -63,12 +63,10 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
goto __error1;
}
err = snd_card_file_add(card, file);
- if (err < 0) {
- err = -ENODEV;
+ if (err < 0)
goto __error1;
- }
if (!try_module_get(card->module)) {
- err = -EFAULT;
+ err = -ENODEV;
goto __error2;
}
ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
index 973d11732bfd..352047e0b33e 100644
--- a/sound/core/hwdep.c
+++ b/sound/core/hwdep.c
@@ -87,7 +87,7 @@ static int snd_hwdep_open(struct inode *inode, struct file * file)
if (!try_module_get(hw->card->module)) {
snd_card_unref(hw->card);
- return -EFAULT;
+ return -ENODEV;
}
init_waitqueue_entry(&wait, current);
diff --git a/sound/core/info.c b/sound/core/info.c
index 54834dbe6b59..3b8ccda04e1a 100644
--- a/sound/core/info.c
+++ b/sound/core/info.c
@@ -78,7 +78,7 @@ static int alloc_info_private(struct snd_info_entry *entry,
if (!entry || !entry->p)
return -ENODEV;
if (!try_module_get(entry->module))
- return -EFAULT;
+ return -ENODEV;
data = kzalloc_obj(*data);
if (!data) {
module_put(entry->module);
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
index f5bcc7896542..3a1dd1edd26d 100644
--- a/sound/core/oss/mixer_oss.c
+++ b/sound/core/oss/mixer_oss.c
@@ -58,7 +58,7 @@ static int snd_mixer_oss_open(struct inode *inode, struct file *file)
kfree(fmixer);
snd_card_file_remove(card, file);
snd_card_unref(card);
- return -EFAULT;
+ return -ENODEV;
}
snd_card_unref(card);
return 0;
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index 0d7818eb3e14..8ae43755fb9b 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -2507,7 +2507,7 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
if (err < 0)
goto __error1;
if (!try_module_get(pcm->card->module)) {
- err = -EFAULT;
+ err = -ENODEV;
goto __error2;
}
if (snd_task_name(current, task_name, sizeof(task_name)) < 0) {
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 3462cd5275a2..4fe5fab8d096 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -2913,7 +2913,7 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream)
if (err < 0)
goto __error1;
if (!try_module_get(pcm->card->module)) {
- err = -EFAULT;
+ err = -ENODEV;
goto __error2;
}
init_waitqueue_entry(&wait, current);
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c
index 06bfe09eae1a..236f49a7fb8b 100644
--- a/sound/drivers/aloop.c
+++ b/sound/drivers/aloop.c
@@ -23,6 +23,7 @@
#include <linux/wait.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/hrtimer.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/pcm.h>
@@ -55,7 +56,7 @@ MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-8) for loopback driver.");
module_param_array(pcm_notify, int, NULL, 0444);
MODULE_PARM_DESC(pcm_notify, "Break capture when PCM format/rate/channels changes.");
module_param_array(timer_source, charp, NULL, 0444);
-MODULE_PARM_DESC(timer_source, "Sound card name or number and device/subdevice number of timer to be used. Empty string for jiffies timer [default].");
+MODULE_PARM_DESC(timer_source, "Sound card name or number and device/subdevice number of timer to be used. Empty string for jiffies timer [default], 'hrtimer' for high-resolution timer.");
#define NO_PITCH 100000
@@ -161,8 +162,11 @@ struct loopback_pcm {
unsigned int period_size_frac; /* period size in jiffies ticks */
unsigned int last_drift;
unsigned long last_jiffies;
- /* If jiffies timer is used */
+ /* If jiffies / hrtimer is used */
struct timer_list timer;
+#ifdef CONFIG_HIGH_RES_TIMERS
+ struct hrtimer hrtimer;
+#endif
/* size of per channel buffer in case of non-interleaved access */
unsigned int channel_buf_n;
@@ -232,6 +236,31 @@ static int loopback_jiffies_timer_start(struct loopback_pcm *dpcm)
return 0;
}
+#ifdef CONFIG_HIGH_RES_TIMERS
+/* call in cable->lock */
+static int loopback_hrtimer_start(struct loopback_pcm *dpcm)
+{
+ unsigned long tick;
+ unsigned int rate_shift = get_rate_shift(dpcm);
+
+ if (rate_shift != dpcm->pcm_rate_shift) {
+ dpcm->pcm_rate_shift = rate_shift;
+ dpcm->period_size_frac = frac_pos(dpcm, dpcm->pcm_period_size);
+ }
+ if (dpcm->period_size_frac <= dpcm->irq_pos) {
+ dpcm->irq_pos %= dpcm->period_size_frac;
+ dpcm->period_update_pending = 1;
+ }
+ tick = dpcm->period_size_frac - dpcm->irq_pos;
+ tick = DIV_ROUND_UP(tick, dpcm->pcm_bps);
+ hrtimer_start(&dpcm->hrtimer,
+ ns_to_ktime(div_u64((u64)tick * NSEC_PER_SEC, HZ)),
+ HRTIMER_MODE_REL_SOFT);
+
+ return 0;
+}
+#endif
+
/* call in cable->lock */
static int loopback_snd_timer_start(struct loopback_pcm *dpcm)
{
@@ -270,6 +299,16 @@ static inline int loopback_jiffies_timer_stop(struct loopback_pcm *dpcm)
return 0;
}
+#ifdef CONFIG_HIGH_RES_TIMERS
+/* call in cable->lock */
+static inline int loopback_hrtimer_stop(struct loopback_pcm *dpcm)
+{
+ hrtimer_cancel(&dpcm->hrtimer);
+
+ return 0;
+}
+#endif
+
/* call in cable->lock */
static int loopback_snd_timer_stop(struct loopback_pcm *dpcm)
{
@@ -300,6 +339,15 @@ static inline int loopback_jiffies_timer_stop_sync(struct loopback_pcm *dpcm)
return 0;
}
+#ifdef CONFIG_HIGH_RES_TIMERS
+static inline int loopback_hrtimer_stop_sync(struct loopback_pcm *dpcm)
+{
+ hrtimer_cancel(&dpcm->hrtimer);
+
+ return 0;
+}
+#endif
+
/* call in loopback->cable_lock */
static int loopback_snd_timer_close_cable(struct loopback_pcm *dpcm)
{
@@ -734,6 +782,30 @@ static void loopback_jiffies_timer_function(struct timer_list *t)
snd_pcm_period_elapsed(dpcm->substream);
}
+#ifdef CONFIG_HIGH_RES_TIMERS
+static enum hrtimer_restart loopback_hrtimer_function(struct hrtimer *t)
+{
+ struct loopback_pcm *dpcm = container_of(t, struct loopback_pcm, hrtimer);
+ bool period_elapsed = false;
+
+ scoped_guard(spinlock_irqsave, &dpcm->cable->lock) {
+ if (loopback_jiffies_timer_pos_update(dpcm->cable) &
+ (1 << dpcm->substream->stream)) {
+ loopback_hrtimer_start(dpcm);
+ if (dpcm->period_update_pending) {
+ dpcm->period_update_pending = 0;
+ period_elapsed = true;
+ }
+ }
+ }
+
+ if (period_elapsed)
+ snd_pcm_period_elapsed(dpcm->substream);
+
+ return HRTIMER_NORESTART;
+}
+#endif
+
/* call in cable->lock */
static int loopback_snd_timer_check_resolution(struct snd_pcm_runtime *runtime,
unsigned long resolution)
@@ -907,6 +979,21 @@ static void loopback_jiffies_timer_dpcm_info(struct loopback_pcm *dpcm,
snd_iprintf(buffer, " timer_expires:\t%lu\n", dpcm->timer.expires);
}
+#ifdef CONFIG_HIGH_RES_TIMERS
+static void loopback_hrtimer_dpcm_info(struct loopback_pcm *dpcm,
+ struct snd_info_buffer *buffer)
+{
+ snd_iprintf(buffer, " update_pending:\t%u\n",
+ dpcm->period_update_pending);
+ snd_iprintf(buffer, " irq_pos:\t\t%u\n", dpcm->irq_pos);
+ snd_iprintf(buffer, " period_frac:\t%u\n", dpcm->period_size_frac);
+ snd_iprintf(buffer, " last_jiffies:\t%lu (%lu)\n",
+ dpcm->last_jiffies, jiffies);
+ snd_iprintf(buffer, " timer_expires:\t%llu\n",
+ ktime_to_ns(hrtimer_get_expires(&dpcm->hrtimer)));
+}
+#endif
+
static void loopback_snd_timer_dpcm_info(struct loopback_pcm *dpcm,
struct snd_info_buffer *buffer)
{
@@ -1097,6 +1184,26 @@ static const struct loopback_ops loopback_jiffies_timer_ops = {
.dpcm_info = loopback_jiffies_timer_dpcm_info,
};
+#ifdef CONFIG_HIGH_RES_TIMERS
+static int loopback_hrtimer_open(struct loopback_pcm *dpcm)
+{
+ hrtimer_setup(&dpcm->hrtimer, loopback_hrtimer_function,
+ CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
+
+ return 0;
+}
+
+static const struct loopback_ops loopback_hrtimer_ops = {
+ .open = loopback_hrtimer_open,
+ .start = loopback_hrtimer_start,
+ .stop = loopback_hrtimer_stop,
+ .stop_sync = loopback_hrtimer_stop_sync,
+ .close_substream = loopback_hrtimer_stop_sync,
+ .pos_update = loopback_jiffies_timer_pos_update,
+ .dpcm_info = loopback_hrtimer_dpcm_info,
+};
+#endif
+
static int loopback_parse_timer_id(const char *str,
struct snd_timer_id *tid)
{
@@ -1274,7 +1381,12 @@ static int loopback_open(struct snd_pcm_substream *substream)
spin_lock_init(&cable->lock);
snd_refcount_init(&cable->stop_count);
cable->hw = loopback_pcm_hardware;
- if (loopback->timer_source)
+#ifdef CONFIG_HIGH_RES_TIMERS
+ if (loopback->timer_source && !strcmp(loopback->timer_source, "hrtimer"))
+ cable->ops = &loopback_hrtimer_ops;
+ else
+#endif
+ if (loopback->timer_source && loopback->timer_source[0])
cable->ops = &loopback_snd_timer_ops;
else
cable->ops = &loopback_jiffies_timer_ops;
diff --git a/sound/hda/codecs/cm9825.c b/sound/hda/codecs/cm9825.c
index eeb9ca38d2d8..8a74862d8a81 100644
--- a/sound/hda/codecs/cm9825.c
+++ b/sound/hda/codecs/cm9825.c
@@ -15,7 +15,8 @@
enum {
QUIRK_CM_STD = 0x0,
- QUIRK_GENE_TWL7_SSID = 0x160dc000
+ QUIRK_GENE_TWL7_SSID = 0x160dc000,
+ QUIRK_IBP_SSID = 0x15bd3275
};
/* CM9825 Offset Definitions */
@@ -40,13 +41,19 @@ enum {
#define CM9825_VERB_SET_GAD 0x7b4
#define CM9825_VERB_SET_TMOD 0x7b5
#define CM9825_VERB_SET_SNR 0x7b6
+#define CM9825_VERB_SET_OMTP 0x7ef
+#define CM9825_VERB_READ_OMTP 0xfec
struct cmi_spec {
struct hda_gen_spec gen;
const struct hda_verb *chip_d0_verbs;
const struct hda_verb *chip_d3_verbs;
+ const struct hda_verb *chip_playback_start_verbs;
+ const struct hda_verb *chip_playback_stop_verbs;
const struct hda_verb *chip_hp_present_verbs;
const struct hda_verb *chip_hp_remove_verbs;
+ const struct hda_verb *chip_lineout_present_verbs;
+ const struct hda_verb *chip_lineout_remove_verbs;
struct hda_codec *codec;
struct delayed_work unsol_inputs_work;
struct delayed_work unsol_lineout_work;
@@ -193,6 +200,94 @@ static const struct hda_verb cm9825_gene_twl7_playback_stop_verbs[] = {
{}
};
+/*
+ * To save power, AD/CLK is turned off.
+ */
+static const struct hda_verb cm9825_ibp_d3_verbs[] = {
+ {0x43, CM9825_VERB_SET_D2S, 0x62},
+ {0x43, CM9825_VERB_SET_PLL, 0x01},
+ {0x43, CM9825_VERB_SET_NEG, 0xc2},
+ {0x43, CM9825_VERB_SET_ADCL, 0x00},
+ {0x43, CM9825_VERB_SET_DACL, 0x02},
+ {0x43, CM9825_VERB_SET_VNEG, 0x50},
+ {0x43, CM9825_VERB_SET_MBIAS, 0x00},
+ {0x43, CM9825_VERB_SET_PDNEG, 0x04},
+ {0x43, CM9825_VERB_SET_CDALR, 0xf6},
+ {0x43, CM9825_VERB_SET_OTP, 0xcd},
+ {}
+};
+
+/*
+ * D0 configuration: enable PLL/CLK/ADC/DAC and optimize performance
+ */
+static const struct hda_verb cm9825_ibp_d0_verbs[] = {
+ {0x34, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
+ {0x43, CM9825_VERB_SET_SNR, 0x38},
+ {0x43, CM9825_VERB_SET_PLL, 0x00},
+ {0x43, CM9825_VERB_SET_ADCL, 0x00},
+ {0x43, CM9825_VERB_SET_DACL, 0x02},
+ {0x43, CM9825_VERB_SET_MBIAS, 0x00},
+ {0x43, CM9825_VERB_SET_VNEG, 0x56},
+ {0x43, CM9825_VERB_SET_D2S, 0x62},
+ {0x43, CM9825_VERB_SET_DACTRL, 0x00},
+ {0x43, CM9825_VERB_SET_PDNEG, 0x0c},
+ {0x43, CM9825_VERB_SET_CDALR, 0xf4},
+ {0x43, CM9825_VERB_SET_OTP, 0xcd},
+ {0x43, CM9825_VERB_SET_MTCBA, 0x61},
+ {0x43, CM9825_VERB_SET_OCP, 0x33},
+ {0x43, CM9825_VERB_SET_GAD, 0x07},
+ {0x43, CM9825_VERB_SET_TMOD, 0x26},
+ {0x3c, AC_VERB_SET_AMP_GAIN_MUTE | 0xa0, 0x2d},
+ {0x3c, AC_VERB_SET_AMP_GAIN_MUTE | 0x90, 0x2d},
+ {0x43, CM9825_VERB_SET_HPF_1, 0x40},
+ {0x43, CM9825_VERB_SET_HPF_2, 0x40},
+ {}
+};
+
+/*
+ * Enable mbias, ADC.
+ */
+static const struct hda_verb cm9825_ibp_lineout_present_verbs[] = {
+ {0x43, CM9825_VERB_SET_ADCL, 0x8c},
+ {0x43, CM9825_VERB_SET_MBIAS, 0x10},
+ {}
+};
+
+/*
+ * Disable mbias, ADC.
+ */
+static const struct hda_verb cm9825_ibp_lineout_remove_verbs[] = {
+ {0x43, CM9825_VERB_SET_ADCL, 0x00},
+ {0x43, CM9825_VERB_SET_MBIAS, 0x00},
+ {}
+};
+
+/*
+ * Turn on the DAC (widget NID 0x43) in the playback path by writing
+ * a sequence of vendor-specific verbs.
+ */
+static const struct hda_verb cm9825_ibp_playback_start_verbs[] = {
+ {0x43, CM9825_VERB_SET_DACL, 0xaa},
+ {0x43, CM9825_VERB_SET_D2S, 0xf2},
+ {0x43, CM9825_VERB_SET_VDO, 0xc4},
+ {0x43, CM9825_VERB_SET_SNR, 0x30},
+ {}
+};
+
+/*
+ * Shut down the playback path. The order differs slightly from the
+ * enable sequence, likely to avoid audible pop noise when powering
+ * down the output stage.
+ */
+static const struct hda_verb cm9825_ibp_playback_stop_verbs[] = {
+ {0x43, CM9825_VERB_SET_VDO, 0xc0},
+ {0x43, CM9825_VERB_SET_DACL, 0x02},
+ {0x43, CM9825_VERB_SET_D2S, 0x62},
+ {0x43, CM9825_VERB_SET_VDO, 0x80},
+ {0x43, CM9825_VERB_SET_SNR, 0x38},
+ {}
+};
+
static void cm9825_update_jk_plug_status(struct hda_codec *codec, hda_nid_t nid)
{
struct cmi_spec *spec = codec->spec;
@@ -232,6 +327,23 @@ static void cm9825_unsol_lineout_delayed(struct work_struct *work)
struct cmi_spec *spec =
container_of(to_delayed_work(work), struct cmi_spec,
unsol_lineout_work);
+ hda_nid_t line_out_pin = spec->gen.autocfg.line_out_pins[0];
+ bool line_out_jack_plugin = false;
+
+ line_out_jack_plugin = snd_hda_jack_detect(spec->codec, line_out_pin);
+
+ codec_dbg(spec->codec, "lineout_jack_plugin %d, lineout_pin 0x%X\n",
+ (int)line_out_jack_plugin, line_out_pin);
+
+ if (!line_out_jack_plugin) {
+ /* Jack plugout */
+ snd_hda_sequence_write(spec->codec,
+ spec->chip_lineout_remove_verbs);
+ } else {
+ /* Jack plugin */
+ snd_hda_sequence_write(spec->codec,
+ spec->chip_lineout_present_verbs);
+ }
cm9825_update_jk_plug_status(spec->codec,
spec->gen.autocfg.line_out_pins[0]);
@@ -362,12 +474,10 @@ static void cm9825_playback_pcm_hook(struct hda_pcm_stream *hinfo,
switch (action) {
case HDA_GEN_PCM_ACT_PREPARE:
- snd_hda_sequence_write(spec->codec,
- cm9825_gene_twl7_playback_start_verbs);
+ snd_hda_sequence_write(codec, spec->chip_playback_start_verbs);
break;
case HDA_GEN_PCM_ACT_CLEANUP:
- snd_hda_sequence_write(spec->codec,
- cm9825_gene_twl7_playback_stop_verbs);
+ snd_hda_sequence_write(codec, spec->chip_playback_stop_verbs);
break;
default:
return;
@@ -471,7 +581,8 @@ static int cm9825_resume(struct hda_codec *codec)
if (codec->core.subsystem_id == QUIRK_CM_STD)
cm9825_cm_std_resume(codec);
- else if (codec->core.subsystem_id == QUIRK_GENE_TWL7_SSID) {
+ else if (codec->core.subsystem_id == QUIRK_GENE_TWL7_SSID ||
+ codec->core.subsystem_id == QUIRK_IBP_SSID) {
snd_hda_codec_init(codec);
snd_hda_sequence_write(codec, spec->chip_d0_verbs);
}
@@ -487,6 +598,7 @@ static int cm9825_probe(struct hda_codec *codec, const struct hda_device_id *id)
struct cmi_spec *spec;
struct auto_pin_cfg *cfg;
int err = 0;
+ unsigned int val;
spec = kzalloc_obj(*spec);
if (spec == NULL)
@@ -523,9 +635,33 @@ static int cm9825_probe(struct hda_codec *codec, const struct hda_device_id *id)
spec->chip_d0_verbs = cm9825_gene_twl7_d0_verbs;
spec->chip_d3_verbs = cm9825_gene_twl7_d3_verbs;
spec->gen.pcm_playback_hook = cm9825_playback_pcm_hook;
+ spec->chip_playback_start_verbs =
+ cm9825_gene_twl7_playback_start_verbs;
+ spec->chip_playback_stop_verbs =
+ cm9825_gene_twl7_playback_stop_verbs;
/* Internal fixed device, Rear, Mic-in, 3.5mm */
snd_hda_codec_set_pincfg(codec, 0x37, 0x24A70100);
break;
+ case QUIRK_IBP_SSID:
+ snd_hda_codec_set_name(codec, "CM9825 IBP");
+ spec->chip_d0_verbs = cm9825_ibp_d0_verbs;
+ spec->chip_d3_verbs = cm9825_ibp_d3_verbs;
+ spec->gen.pcm_playback_hook = cm9825_playback_pcm_hook;
+ spec->chip_lineout_present_verbs =
+ cm9825_ibp_lineout_present_verbs;
+ spec->chip_lineout_remove_verbs =
+ cm9825_ibp_lineout_remove_verbs;
+ spec->chip_playback_start_verbs =
+ cm9825_ibp_playback_start_verbs;
+ spec->chip_playback_stop_verbs = cm9825_ibp_playback_stop_verbs;
+
+ /* OMTP */
+ val =
+ snd_hda_codec_read(codec, 0x46, 0, CM9825_VERB_READ_OMTP,
+ 0x0);
+ snd_hda_codec_write(codec, 0x46, 0, CM9825_VERB_SET_OMTP,
+ (val >> 24) & 0x7f);
+ break;
default:
err = -ENXIO;
break;
diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c
index d887534f29ae..fedd734f180e 100644
--- a/sound/hda/codecs/realtek/alc269.c
+++ b/sound/hda/codecs/realtek/alc269.c
@@ -4177,6 +4177,7 @@ enum {
ALC256_FIXUP_HONOR_MRB_XXX_M1020_AUDIO,
ALC245_FIXUP_HP_ENVY_X360_15_FH0XXX,
ALC287_FIXUP_ACER_MICMUTE_LED,
+ ALC236_FIXUP_DELL_HP_POP_NOISE,
};
/* A special fixup for Lenovo C940 and Yoga Duet 7;
@@ -6798,6 +6799,10 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC2XX_FIXUP_HEADSET_MIC,
},
+ [ALC236_FIXUP_DELL_HP_POP_NOISE] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc285_fixup_invalidate_dacs,
+ },
};
static const struct hda_quirk alc269_fixup_tbl[] = {
@@ -6949,6 +6954,8 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x0cc3, "Dell Oasis 14 Low Weight MTL-U", ALC289_FIXUP_DELL_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1028, 0x0cc4, "Dell Oasis 16 MTL-H/U", ALC289_FIXUP_DELL_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1028, 0x0cc5, "Dell Oasis 14", ALC289_FIXUP_RTK_AMP_DUAL_SPK),
+ SND_PCI_QUIRK(0x1028, 0x0e6b, "Dell Pro QCM1255", ALC236_FIXUP_DELL_HP_POP_NOISE),
+ SND_PCI_QUIRK(0x1028, 0x0e6d, "Dell Pro Micro QCM1255", ALC236_FIXUP_DELL_HP_POP_NOISE),
SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
@@ -7165,6 +7172,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8a36, "HP Pavilion Plus 14-eh0xxx", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
SND_PCI_QUIRK(0x103c, 0x8a3d, "HP Victus 15-fb0xxx (MB 8A3D)", ALC245_FIXUP_HP_MUTE_LED_V2_COEFBIT),
SND_PCI_QUIRK(0x103c, 0x8a4f, "HP Victus 15-fa0xxx (MB 8A4F)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
+ SND_PCI_QUIRK(0x103c, 0x8a50, "HP Victus 15-fa0xxx (MB 8A50)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
SND_PCI_QUIRK(0x103c, 0x8a6e, "HP EDNA 360", ALC287_FIXUP_CS35L41_I2C_4),
SND_PCI_QUIRK(0x103c, 0x8a74, "HP ProBook 440 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8a75, "HP ProBook 450 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
@@ -7312,7 +7320,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8da8, "HP 16 Piston OmniBook X", ALC245_FIXUP_HP_ENVY_X360_15_FH0XXX),
SND_PCI_QUIRK(0x103c, 0x8dc9, "HP Laptop 15-fc0xxx", ALC236_FIXUP_HP_DMIC),
SND_PCI_QUIRK(0x103c, 0x8dd4, "HP EliteStudio 8 AIO", ALC274_FIXUP_HP_AIO_BIND_DACS),
- SND_PCI_QUIRK(0x103c, 0x8dd7, "HP Laptop 15-fd0xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
+ SND_PCI_QUIRK(0x103c, 0x8dd7, "HP Laptop 15-fd0xxx", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
SND_PCI_QUIRK(0x103c, 0x8de8, "HP Gemtree", ALC245_FIXUP_TAS2781_SPI_2),
SND_PCI_QUIRK(0x103c, 0x8de9, "HP Gemtree", ALC245_FIXUP_TAS2781_SPI_2),
SND_PCI_QUIRK(0x103c, 0x8dec, "HP EliteBook 640 G12", ALC236_FIXUP_HP_GPIO_LED),
@@ -7931,6 +7939,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1d05, 0x300f, "TongFang X6AR5xxY", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1d05, 0x3019, "TongFang X6FR5xxY", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1d05, 0x3031, "TongFang X6AR55xU", ALC2XX_FIXUP_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1d05, 0x3034, "TongFang X6xx45xU", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1d17, 0x3288, "Haier Boyue G42", ALC269VC_FIXUP_ACER_VCOPPERBOX_PINS),
SND_PCI_QUIRK(0x1d72, 0x1602, "RedmiBook", ALC255_FIXUP_XIAOMI_HEADSET_MIC),
SND_PCI_QUIRK(0x1d72, 0x1701, "XiaomiNotebook Pro", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE),
diff --git a/sound/hda/codecs/side-codecs/Kconfig b/sound/hda/codecs/side-codecs/Kconfig
index 2a2e8804bf9e..1cfd83e251e4 100644
--- a/sound/hda/codecs/side-codecs/Kconfig
+++ b/sound/hda/codecs/side-codecs/Kconfig
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
config SND_HDA_CIRRUS_SCODEC
- tristate
+ tristate "Cirrus side-codec library" if KUNIT
config SND_HDA_CIRRUS_SCODEC_KUNIT_TEST
tristate "KUnit test for Cirrus side-codec library" if !KUNIT_ALL_TESTS
diff --git a/sound/soc/amd/acp/acp-i2s.c b/sound/soc/amd/acp/acp-i2s.c
index 283a674c7e2c..bb58a9d34993 100644
--- a/sound/soc/amd/acp/acp-i2s.c
+++ b/sound/soc/amd/acp/acp-i2s.c
@@ -686,6 +686,10 @@ static int acp_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_d
return 0;
}
+static const u64 acp_i2s_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A;
+
const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = {
.startup = acp_i2s_startup,
.hw_params = acp_i2s_hwparams,
@@ -693,6 +697,8 @@ const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = {
.trigger = acp_i2s_trigger,
.set_fmt = acp_i2s_set_fmt,
.set_tdm_slot = acp_i2s_set_tdm_slot,
+ .auto_selectable_formats = &acp_i2s_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
EXPORT_SYMBOL_NS_GPL(asoc_acp_cpu_dai_ops, "SND_SOC_ACP_COMMON");
diff --git a/sound/soc/amd/raven/acp3x-i2s.c b/sound/soc/amd/raven/acp3x-i2s.c
index 352485dd98b1..b0147e88ba54 100644
--- a/sound/soc/amd/raven/acp3x-i2s.c
+++ b/sound/soc/amd/raven/acp3x-i2s.c
@@ -250,11 +250,17 @@ static int acp3x_i2s_trigger(struct snd_pcm_substream *substream,
return ret;
}
+static const u64 acp3x_i2s_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A;
+
static const struct snd_soc_dai_ops acp3x_i2s_dai_ops = {
.hw_params = acp3x_i2s_hwparams,
.trigger = acp3x_i2s_trigger,
.set_fmt = acp3x_i2s_set_fmt,
.set_tdm_slot = acp3x_i2s_set_tdm_slot,
+ .auto_selectable_formats = &acp3x_i2s_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static const struct snd_soc_component_driver acp3x_dai_component = {
diff --git a/sound/soc/amd/vangogh/acp5x-i2s.c b/sound/soc/amd/vangogh/acp5x-i2s.c
index bf719f628617..dbfb87e2fe92 100644
--- a/sound/soc/amd/vangogh/acp5x-i2s.c
+++ b/sound/soc/amd/vangogh/acp5x-i2s.c
@@ -337,11 +337,17 @@ static int acp5x_i2s_trigger(struct snd_pcm_substream *substream,
return ret;
}
+static const u64 acp5x_i2s_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A;
+
static const struct snd_soc_dai_ops acp5x_i2s_dai_ops = {
.hw_params = acp5x_i2s_hwparams,
.trigger = acp5x_i2s_trigger,
.set_fmt = acp5x_i2s_set_fmt,
.set_tdm_slot = acp5x_i2s_set_tdm_slot,
+ .auto_selectable_formats = &acp5x_i2s_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static const struct snd_soc_component_driver acp5x_dai_component = {
diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c
index d6df7de70b27..8b121593f26a 100644
--- a/sound/soc/amd/yc/acp6x-mach.c
+++ b/sound/soc/amd/yc/acp6x-mach.c
@@ -753,12 +753,12 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
}
},
{
- .driver_data = &acp6x_card,
- .matches = {
- DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "Vivobook_ASUSLaptop M6501RR_M6501RR"),
- }
- },
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Vivobook_ASUSLaptop M6501RR_M6501RR"),
+ }
+ },
{
.driver_data = &acp6x_card,
.matches = {
diff --git a/sound/soc/codecs/audio-iio-aux.c b/sound/soc/codecs/audio-iio-aux.c
index 964b9a5b2990..eef0af63e3d6 100644
--- a/sound/soc/codecs/audio-iio-aux.c
+++ b/sound/soc/codecs/audio-iio-aux.c
@@ -311,3 +311,4 @@ module_platform_driver(audio_iio_aux_driver);
MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
MODULE_DESCRIPTION("IIO ALSA SoC aux driver");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c
index c835088de578..8288fb6d50be 100644
--- a/sound/soc/codecs/cs35l32.c
+++ b/sound/soc/codecs/cs35l32.c
@@ -538,7 +538,15 @@ static int cs35l32_runtime_resume(struct device *dev)
gpiod_set_value_cansleep(cs35l32->reset_gpio, 1);
regcache_cache_only(cs35l32->regmap, false);
- regcache_sync(cs35l32->regmap);
+ ret = regcache_sync(cs35l32->regmap);
+ if (ret) {
+ regcache_cache_only(cs35l32->regmap, true);
+ regcache_mark_dirty(cs35l32->regmap);
+ gpiod_set_value_cansleep(cs35l32->reset_gpio, 0);
+ regulator_bulk_disable(ARRAY_SIZE(cs35l32->supplies),
+ cs35l32->supplies);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/cs42l43-jack.c b/sound/soc/codecs/cs42l43-jack.c
index 934666295ee3..dbf45cabfffe 100644
--- a/sound/soc/codecs/cs42l43-jack.c
+++ b/sound/soc/codecs/cs42l43-jack.c
@@ -310,6 +310,7 @@ irqreturn_t cs42l43_bias_detect_clamp(int irq, void *data)
#define CS42L43_JACK_ABSENT 0x0
#define CS42L43_JACK_OPTICAL (SND_JACK_MECHANICAL | SND_JACK_AVOUT)
+#define CS42L43_JACK_MICROPHONE (SND_JACK_MECHANICAL | SND_JACK_MICROPHONE)
#define CS42L43_JACK_HEADPHONE (SND_JACK_MECHANICAL | SND_JACK_HEADPHONE)
#define CS42L43_JACK_HEADSET (SND_JACK_MECHANICAL | SND_JACK_HEADSET)
#define CS42L43_JACK_LINEOUT (SND_JACK_MECHANICAL | SND_JACK_LINEOUT)
@@ -871,7 +872,7 @@ static const struct cs42l43_jack_override_mode {
.hsdet_mode = CS42L43_JACK_3_POLE_SWITCHES,
.mic_ctrl = (0x3 << CS42L43_JACK_STEREO_CONFIG_SHIFT) |
CS42L43_HS1_BIAS_EN_MASK | CS42L43_HS2_BIAS_EN_MASK,
- .report = CS42L43_JACK_LINEIN,
+ .report = CS42L43_JACK_MICROPHONE,
},
[CS42L43_JACK_RAW_OPTICAL] = {
.hsdet_mode = CS42L43_JACK_3_POLE_SWITCHES,
diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c
index 6ac6d306b054..9a7f70175717 100644
--- a/sound/soc/codecs/cs4349.c
+++ b/sound/soc/codecs/cs4349.c
@@ -340,7 +340,13 @@ static int cs4349_runtime_resume(struct device *dev)
gpiod_set_value_cansleep(cs4349->reset_gpio, 1);
regcache_cache_only(cs4349->regmap, false);
- regcache_sync(cs4349->regmap);
+ ret = regcache_sync(cs4349->regmap);
+ if (ret) {
+ regcache_cache_only(cs4349->regmap, true);
+ regcache_mark_dirty(cs4349->regmap);
+ gpiod_set_value_cansleep(cs4349->reset_gpio, 0);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c
index 6233aa9f5bc6..550fc76109c6 100644
--- a/sound/soc/codecs/lpass-rx-macro.c
+++ b/sound/soc/codecs/lpass-rx-macro.c
@@ -2030,9 +2030,10 @@ static struct snd_soc_dai_driver rx_macro_dai[] = {
},
};
-static void rx_macro_mclk_enable(struct rx_macro *rx, bool mclk_enable)
+static int rx_macro_mclk_enable(struct rx_macro *rx, bool mclk_enable)
{
struct regmap *regmap = rx->regmap;
+ int ret;
if (mclk_enable) {
if (rx->rx_mclk_users == 0) {
@@ -2047,14 +2048,16 @@ static void rx_macro_mclk_enable(struct rx_macro *rx, bool mclk_enable)
CDC_RX_FS_MCLK_CNT_EN_MASK,
CDC_RX_FS_MCLK_CNT_ENABLE);
regcache_mark_dirty(regmap);
- regcache_sync(regmap);
+ ret = regcache_sync(regmap);
+ if (ret)
+ return ret;
}
rx->rx_mclk_users++;
} else {
if (rx->rx_mclk_users <= 0) {
dev_err(rx->dev, "%s: clock already disabled\n", __func__);
rx->rx_mclk_users = 0;
- return;
+ return 0;
}
rx->rx_mclk_users--;
if (rx->rx_mclk_users == 0) {
@@ -2068,6 +2071,8 @@ static void rx_macro_mclk_enable(struct rx_macro *rx, bool mclk_enable)
CDC_RX_CLK_MCLK2_EN_MASK, 0x0);
}
}
+
+ return 0;
}
static int rx_macro_mclk_event(struct snd_soc_dapm_widget *w,
@@ -2079,11 +2084,9 @@ static int rx_macro_mclk_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- rx_macro_mclk_enable(rx, true);
- break;
+ return rx_macro_mclk_enable(rx, true);
case SND_SOC_DAPM_POST_PMD:
- rx_macro_mclk_enable(rx, false);
- break;
+ return rx_macro_mclk_enable(rx, false);
default:
dev_err(component->dev, "%s: invalid DAPM event %d\n", __func__, event);
ret = -EINVAL;
@@ -3677,7 +3680,11 @@ static int swclk_gate_enable(struct clk_hw *hw)
return ret;
}
- rx_macro_mclk_enable(rx, true);
+ ret = rx_macro_mclk_enable(rx, true);
+ if (ret) {
+ clk_disable_unprepare(rx->mclk);
+ return ret;
+ }
regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL,
CDC_RX_SWR_CLK_EN_MASK, 1);
@@ -4003,9 +4010,15 @@ static int rx_macro_runtime_resume(struct device *dev)
goto err_fsgen;
}
regcache_cache_only(rx->regmap, false);
- regcache_sync(rx->regmap);
+ ret = regcache_sync(rx->regmap);
+ if (ret)
+ goto err_sync;
return 0;
+err_sync:
+ regcache_cache_only(rx->regmap, true);
+ regcache_mark_dirty(rx->regmap);
+ clk_disable_unprepare(rx->fsgen);
err_fsgen:
clk_disable_unprepare(rx->npl);
err_npl:
diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c
index f7d168f557dd..b6b5ef802035 100644
--- a/sound/soc/codecs/lpass-tx-macro.c
+++ b/sound/soc/codecs/lpass-tx-macro.c
@@ -614,6 +614,7 @@ static int tx_macro_mclk_enable(struct tx_macro *tx,
bool mclk_enable)
{
struct regmap *regmap = tx->regmap;
+ int ret;
if (mclk_enable) {
if (tx->tx_mclk_users == 0) {
@@ -626,7 +627,9 @@ static int tx_macro_mclk_enable(struct tx_macro *tx,
CDC_TX_FS_CNT_EN_MASK,
CDC_TX_FS_CNT_ENABLE);
regcache_mark_dirty(regmap);
- regcache_sync(regmap);
+ ret = regcache_sync(regmap);
+ if (ret)
+ return ret;
}
tx->tx_mclk_users++;
} else {
@@ -739,11 +742,9 @@ static int tx_macro_mclk_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- tx_macro_mclk_enable(tx, true);
- break;
+ return tx_macro_mclk_enable(tx, true);
case SND_SOC_DAPM_POST_PMD:
- tx_macro_mclk_enable(tx, false);
- break;
+ return tx_macro_mclk_enable(tx, false);
default:
break;
}
@@ -2155,7 +2156,11 @@ static int swclk_gate_enable(struct clk_hw *hw)
return ret;
}
- tx_macro_mclk_enable(tx, true);
+ ret = tx_macro_mclk_enable(tx, true);
+ if (ret) {
+ clk_disable_unprepare(tx->mclk);
+ return ret;
+ }
regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
CDC_TX_SWR_CLK_EN_MASK,
@@ -2437,9 +2442,15 @@ static int tx_macro_runtime_resume(struct device *dev)
}
regcache_cache_only(tx->regmap, false);
- regcache_sync(tx->regmap);
+ ret = regcache_sync(tx->regmap);
+ if (ret)
+ goto err_sync;
return 0;
+err_sync:
+ regcache_cache_only(tx->regmap, true);
+ regcache_mark_dirty(tx->regmap);
+ clk_disable_unprepare(tx->fsgen);
err_fsgen:
clk_disable_unprepare(tx->npl);
err_npl:
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
index bccce322ccc3..60da518b0e57 100644
--- a/sound/soc/codecs/max98090.c
+++ b/sound/soc/codecs/max98090.c
@@ -2646,12 +2646,18 @@ static void max98090_i2c_remove(struct i2c_client *client)
static int max98090_runtime_resume(struct device *dev)
{
struct max98090_priv *max98090 = dev_get_drvdata(dev);
+ int ret;
regcache_cache_only(max98090->regmap, false);
max98090_reset(max98090);
- regcache_sync(max98090->regmap);
+ ret = regcache_sync(max98090->regmap);
+ if (ret < 0) {
+ regcache_cache_only(max98090->regmap, true);
+ regcache_mark_dirty(max98090->regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/max98363.c b/sound/soc/codecs/max98363.c
index 099dc5bf6195..0e32b7a94cb0 100644
--- a/sound/soc/codecs/max98363.c
+++ b/sound/soc/codecs/max98363.c
@@ -100,7 +100,12 @@ static int max98363_resume(struct device *dev)
return ret;
regcache_cache_only(max98363->regmap, false);
- regcache_sync(max98363->regmap);
+ ret = regcache_sync(max98363->regmap);
+ if (ret) {
+ regcache_cache_only(max98363->regmap, true);
+ regcache_mark_dirty(max98363->regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/max98373-i2c.c b/sound/soc/codecs/max98373-i2c.c
index 8805bd01153c..cbd7ebffa6d6 100644
--- a/sound/soc/codecs/max98373-i2c.c
+++ b/sound/soc/codecs/max98373-i2c.c
@@ -488,10 +488,17 @@ static int max98373_suspend(struct device *dev)
static int max98373_resume(struct device *dev)
{
struct max98373_priv *max98373 = dev_get_drvdata(dev);
+ int ret;
regcache_cache_only(max98373->regmap, false);
max98373_reset(max98373, dev);
- regcache_sync(max98373->regmap);
+ ret = regcache_sync(max98373->regmap);
+ if (ret) {
+ regcache_cache_only(max98373->regmap, true);
+ regcache_mark_dirty(max98373->regmap);
+ return ret;
+ }
+
return 0;
}
diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c
index 8fe9c58e1a62..638ef343813b 100644
--- a/sound/soc/codecs/max98373-sdw.c
+++ b/sound/soc/codecs/max98373-sdw.c
@@ -277,7 +277,12 @@ static int max98373_resume(struct device *dev)
}
regcache_cache_only(max98373->regmap, false);
- regcache_sync(max98373->regmap);
+ ret = regcache_sync(max98373->regmap);
+ if (ret) {
+ regcache_cache_only(max98373->regmap, true);
+ regcache_mark_dirty(max98373->regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/max98388.c b/sound/soc/codecs/max98388.c
index a4c57152d25f..d97dab41bf0f 100644
--- a/sound/soc/codecs/max98388.c
+++ b/sound/soc/codecs/max98388.c
@@ -863,10 +863,16 @@ static int max98388_suspend(struct device *dev)
static int max98388_resume(struct device *dev)
{
struct max98388_priv *max98388 = dev_get_drvdata(dev);
+ int ret;
regcache_cache_only(max98388->regmap, false);
max98388_reset(max98388, dev);
- regcache_sync(max98388->regmap);
+ ret = regcache_sync(max98388->regmap);
+ if (ret) {
+ regcache_cache_only(max98388->regmap, true);
+ regcache_mark_dirty(max98388->regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/max98396.c b/sound/soc/codecs/max98396.c
index 9c1d7213410c..e5a2fe824c03 100644
--- a/sound/soc/codecs/max98396.c
+++ b/sound/soc/codecs/max98396.c
@@ -1600,19 +1600,37 @@ static int max98396_resume(struct device *dev)
if (max98396->pvdd) {
ret = regulator_enable(max98396->pvdd);
if (ret < 0)
- return ret;
+ goto err_core_supplies;
}
if (max98396->vbat) {
ret = regulator_enable(max98396->vbat);
if (ret < 0)
- return ret;
+ goto err_pvdd;
}
regcache_cache_only(max98396->regmap, false);
max98396_reset(max98396, dev);
- regcache_sync(max98396->regmap);
+ ret = regcache_sync(max98396->regmap);
+ if (ret < 0) {
+ regcache_cache_only(max98396->regmap, true);
+ regcache_mark_dirty(max98396->regmap);
+ goto err_vbat;
+ }
+
return 0;
+
+err_vbat:
+ if (max98396->vbat)
+ regulator_disable(max98396->vbat);
+err_pvdd:
+ if (max98396->pvdd)
+ regulator_disable(max98396->pvdd);
+err_core_supplies:
+ regulator_bulk_disable(MAX98396_NUM_CORE_SUPPLIES,
+ max98396->core_supplies);
+
+ return ret;
}
static const struct dev_pm_ops max98396_pm = {
diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c
index 65e6fdb30eec..524300d8fb0b 100644
--- a/sound/soc/codecs/max98927.c
+++ b/sound/soc/codecs/max98927.c
@@ -742,11 +742,17 @@ static int max98927_suspend(struct device *dev)
static int max98927_resume(struct device *dev)
{
struct max98927_priv *max98927 = dev_get_drvdata(dev);
+ int ret;
regmap_write(max98927->regmap, MAX98927_R0100_SOFT_RESET,
MAX98927_SOFT_RESET);
regcache_cache_only(max98927->regmap, false);
- regcache_sync(max98927->regmap);
+ ret = regcache_sync(max98927->regmap);
+ if (ret) {
+ regcache_cache_only(max98927->regmap, true);
+ regcache_mark_dirty(max98927->regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c
index cb923cecb47f..60fdbe5c4e05 100644
--- a/sound/soc/codecs/pcm1681.c
+++ b/sound/soc/codecs/pcm1681.c
@@ -199,10 +199,17 @@ static int pcm1681_hw_params(struct snd_pcm_substream *substream,
return pcm1681_set_deemph(component);
}
+static const u64 pcm1681_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
static const struct snd_soc_dai_ops pcm1681_dai_ops = {
.set_fmt = pcm1681_set_dai_fmt,
.hw_params = pcm1681_hw_params,
.mute_stream = pcm1681_mute,
+ .auto_selectable_formats = &pcm1681_selectable_formats,
+ .num_auto_selectable_formats = 1,
.no_capture_mute = 1,
};
diff --git a/sound/soc/codecs/pcm1754.c b/sound/soc/codecs/pcm1754.c
index b68a528000be..bb15da1c24aa 100644
--- a/sound/soc/codecs/pcm1754.c
+++ b/sound/soc/codecs/pcm1754.c
@@ -78,10 +78,16 @@ static int pcm1754_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
return 0;
}
+static const u64 pcm1754_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J;
+
static const struct snd_soc_dai_ops pcm1754_dai_ops = {
.set_fmt = pcm1754_set_dai_fmt,
.hw_params = pcm1754_hw_params,
.mute_stream = pcm1754_mute_stream,
+ .auto_selectable_formats = &pcm1754_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static const struct snd_soc_dai_driver pcm1754_dai = {
diff --git a/sound/soc/codecs/pcm1789.c b/sound/soc/codecs/pcm1789.c
index 3ab381e9a856..f06e353743aa 100644
--- a/sound/soc/codecs/pcm1789.c
+++ b/sound/soc/codecs/pcm1789.c
@@ -164,11 +164,18 @@ static int pcm1789_trigger(struct snd_pcm_substream *substream, int cmd,
return ret;
}
+static const u64 pcm1789_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
static const struct snd_soc_dai_ops pcm1789_dai_ops = {
.set_fmt = pcm1789_set_dai_fmt,
.hw_params = pcm1789_hw_params,
.mute_stream = pcm1789_mute,
.trigger = pcm1789_trigger,
+ .auto_selectable_formats = &pcm1789_selectable_formats,
+ .num_auto_selectable_formats = 1,
.no_capture_mute = 1,
};
diff --git a/sound/soc/codecs/pcm179x.c b/sound/soc/codecs/pcm179x.c
index f52ff66b6e64..cb70927872aa 100644
--- a/sound/soc/codecs/pcm179x.c
+++ b/sound/soc/codecs/pcm179x.c
@@ -142,10 +142,16 @@ static int pcm179x_hw_params(struct snd_pcm_substream *substream,
return 0;
}
+static const u64 pcm179x_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J;
+
static const struct snd_soc_dai_ops pcm179x_dai_ops = {
.set_fmt = pcm179x_set_dai_fmt,
.hw_params = pcm179x_hw_params,
.mute_stream = pcm179x_mute,
+ .auto_selectable_formats = &pcm179x_selectable_formats,
+ .num_auto_selectable_formats = 1,
.no_capture_mute = 1,
};
diff --git a/sound/soc/codecs/pcm186x.c b/sound/soc/codecs/pcm186x.c
index 0d1103fe4e04..461ec74e8752 100644
--- a/sound/soc/codecs/pcm186x.c
+++ b/sound/soc/codecs/pcm186x.c
@@ -473,11 +473,20 @@ static int pcm186x_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
return 0;
}
+static const u64 pcm186x_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_B |
+ SND_SOC_POSSIBLE_DAIFMT_NB_NF;
+
static const struct snd_soc_dai_ops pcm186x_dai_ops = {
.set_sysclk = pcm186x_set_dai_sysclk,
.set_tdm_slot = pcm186x_set_tdm_slot,
.set_fmt = pcm186x_set_fmt,
.hw_params = pcm186x_hw_params,
+ .auto_selectable_formats = &pcm186x_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static struct snd_soc_dai_driver pcm1863_dai = {
diff --git a/sound/soc/codecs/pcm3060.c b/sound/soc/codecs/pcm3060.c
index 8974200652e7..f01c46583e89 100644
--- a/sound/soc/codecs/pcm3060.c
+++ b/sound/soc/codecs/pcm3060.c
@@ -164,10 +164,18 @@ val_ready:
return 0;
}
+static const u64 pcm3060_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
+ SND_SOC_POSSIBLE_DAIFMT_NB_NF;
+
static const struct snd_soc_dai_ops pcm3060_dai_ops = {
.set_sysclk = pcm3060_set_sysclk,
.set_fmt = pcm3060_set_fmt,
.hw_params = pcm3060_hw_params,
+ .auto_selectable_formats = &pcm3060_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
#define PCM3060_DAI_RATES_ADC (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 | \
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index fe3b5011fa16..10868df3c75d 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -1505,12 +1505,21 @@ unlock:
return ret;
}
+static const u64 pcm512x_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_B;
+
static const struct snd_soc_dai_ops pcm512x_dai_ops = {
.startup = pcm512x_dai_startup,
.hw_params = pcm512x_hw_params,
.set_fmt = pcm512x_set_fmt,
.mute_stream = pcm512x_mute,
.set_bclk_ratio = pcm512x_set_bclk_ratio,
+ .auto_selectable_formats = &pcm512x_selectable_formats,
+ .num_auto_selectable_formats = 1,
.no_capture_mute = 1,
};
diff --git a/sound/soc/codecs/pm4125-sdw.c b/sound/soc/codecs/pm4125-sdw.c
index 1c612ae4a4b2..307b66025426 100644
--- a/sound/soc/codecs/pm4125-sdw.c
+++ b/sound/soc/codecs/pm4125-sdw.c
@@ -464,10 +464,16 @@ static int __maybe_unused pm4125_sdw_runtime_suspend(struct device *dev)
static int __maybe_unused pm4125_sdw_runtime_resume(struct device *dev)
{
struct pm4125_sdw_priv *priv = dev_get_drvdata(dev);
+ int ret;
if (priv->regmap) {
regcache_cache_only(priv->regmap, false);
- regcache_sync(priv->regmap);
+ ret = regcache_sync(priv->regmap);
+ if (ret) {
+ regcache_cache_only(priv->regmap, true);
+ regcache_mark_dirty(priv->regmap);
+ return ret;
+ }
}
return 0;
diff --git a/sound/soc/codecs/pm4125.c b/sound/soc/codecs/pm4125.c
index 29655175ea28..674a2fbc4eda 100644
--- a/sound/soc/codecs/pm4125.c
+++ b/sound/soc/codecs/pm4125.c
@@ -5,6 +5,7 @@
#include <linux/component.h>
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/irqdomain.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -1295,7 +1296,7 @@ static const struct irq_domain_ops pm4125_domain_ops = {
static int pm4125_irq_init(struct pm4125_priv *pm4125, struct device *dev)
{
- pm4125->virq = irq_domain_add_linear(NULL, 1, &pm4125_domain_ops, NULL);
+ pm4125->virq = irq_domain_create_linear(NULL, 1, &pm4125_domain_ops, NULL);
if (!(pm4125->virq)) {
dev_err(dev, "%s: Failed to add IRQ domain\n", __func__);
return -EINVAL;
diff --git a/sound/soc/codecs/rt1017-sdca-sdw.c b/sound/soc/codecs/rt1017-sdca-sdw.c
index 95405cea8143..caf75e5657ef 100644
--- a/sound/soc/codecs/rt1017-sdca-sdw.c
+++ b/sound/soc/codecs/rt1017-sdca-sdw.c
@@ -784,7 +784,12 @@ static int rt1017_sdca_dev_resume(struct device *dev)
}
regcache_cache_only(rt1017->regmap, false);
- regcache_sync(rt1017->regmap);
+ ret = regcache_sync(rt1017->regmap);
+ if (ret) {
+ regcache_cache_only(rt1017->regmap, true);
+ regcache_mark_dirty(rt1017->regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c
index ca318dbd946e..359b52ba1ef9 100644
--- a/sound/soc/codecs/rt1316-sdw.c
+++ b/sound/soc/codecs/rt1316-sdw.c
@@ -756,7 +756,12 @@ static int rt1316_dev_resume(struct device *dev)
}
regcache_cache_only(rt1316->regmap, false);
- regcache_sync(rt1316->regmap);
+ ret = regcache_sync(rt1316->regmap);
+ if (ret) {
+ regcache_cache_only(rt1316->regmap, true);
+ regcache_mark_dirty(rt1316->regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/rt1318-sdw.c b/sound/soc/codecs/rt1318-sdw.c
index c038ac0e3b76..ef18cd63d461 100644
--- a/sound/soc/codecs/rt1318-sdw.c
+++ b/sound/soc/codecs/rt1318-sdw.c
@@ -830,7 +830,12 @@ static int rt1318_dev_resume(struct device *dev)
return ret;
regcache_cache_only(rt1318->regmap, false);
- regcache_sync(rt1318->regmap);
+ ret = regcache_sync(rt1318->regmap);
+ if (ret) {
+ regcache_cache_only(rt1318->regmap, true);
+ regcache_mark_dirty(rt1318->regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c
index 18d7ebff505f..a30fb575918d 100644
--- a/sound/soc/codecs/rt1320-sdw.c
+++ b/sound/soc/codecs/rt1320-sdw.c
@@ -3626,10 +3626,23 @@ static int rt1320_dev_resume(struct device *dev)
return ret;
regcache_cache_only(rt1320->regmap, false);
- regcache_sync(rt1320->regmap);
+ ret = regcache_sync(rt1320->regmap);
+ if (ret)
+ goto err_sync;
+
regcache_cache_only(rt1320->mbq_regmap, false);
- regcache_sync(rt1320->mbq_regmap);
+ ret = regcache_sync(rt1320->mbq_regmap);
+ if (ret)
+ goto err_sync;
+
return 0;
+
+err_sync:
+ regcache_cache_only(rt1320->regmap, true);
+ regcache_cache_only(rt1320->mbq_regmap, true);
+ regcache_mark_dirty(rt1320->regmap);
+ regcache_mark_dirty(rt1320->mbq_regmap);
+ return ret;
}
static const struct dev_pm_ops rt1320_pm = {
diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c
index 00a4a208d2fa..58aecd4c83a6 100644
--- a/sound/soc/codecs/rt5514.c
+++ b/sound/soc/codecs/rt5514.c
@@ -1073,12 +1073,18 @@ static int rt5514_set_bias_level(struct snd_soc_component *component,
* settings to make sure recording properly.
*/
if (rt5514->dsp_enabled) {
- rt5514->dsp_enabled = 0;
- regmap_multi_reg_write(rt5514->i2c_regmap,
- rt5514_i2c_patch,
- ARRAY_SIZE(rt5514_i2c_patch));
+ ret = regmap_multi_reg_write(rt5514->i2c_regmap,
+ rt5514_i2c_patch,
+ ARRAY_SIZE(rt5514_i2c_patch));
+ if (ret)
+ return ret;
+
regcache_mark_dirty(rt5514->regmap);
- regcache_sync(rt5514->regmap);
+ ret = regcache_sync(rt5514->regmap);
+ if (ret)
+ return ret;
+
+ rt5514->dsp_enabled = 0;
}
}
break;
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index e9819653b30d..93a4148ccccd 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -3518,9 +3518,15 @@ static int rt5645_suspend(struct snd_soc_component *component)
static int rt5645_resume(struct snd_soc_component *component)
{
struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
+ int ret;
regcache_cache_only(rt5645->regmap, false);
- regcache_sync(rt5645->regmap);
+ ret = regcache_sync(rt5645->regmap);
+ if (ret) {
+ regcache_cache_only(rt5645->regmap, true);
+ regcache_mark_dirty(rt5645->regmap);
+ return ret;
+ }
return 0;
}
@@ -4331,9 +4337,15 @@ static int rt5645_sys_suspend(struct device *dev)
static int rt5645_sys_resume(struct device *dev)
{
struct rt5645_priv *rt5645 = dev_get_drvdata(dev);
+ int ret;
regcache_cache_only(rt5645->regmap, false);
- regcache_sync(rt5645->regmap);
+ ret = regcache_sync(rt5645->regmap);
+ if (ret) {
+ regcache_cache_only(rt5645->regmap, true);
+ regcache_mark_dirty(rt5645->regmap);
+ return ret;
+ }
if (rt5645->hp_jack) {
rt5645->jack_type = 0;
diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c
index dec8c2147d68..e49ec28b6103 100644
--- a/sound/soc/codecs/rt5682-sdw.c
+++ b/sound/soc/codecs/rt5682-sdw.c
@@ -410,7 +410,9 @@ static int rt5682_io_init(struct device *dev, struct sdw_slave *slave)
if (rt5682->first_hw_init) {
regcache_cache_bypass(rt5682->regmap, false);
regcache_mark_dirty(rt5682->regmap);
- regcache_sync(rt5682->regmap);
+ ret = regcache_sync(rt5682->regmap);
+ if (ret)
+ goto err_sync;
/* volatile registers */
regmap_update_bits(rt5682->regmap, RT5682_CBJ_CTRL_2,
@@ -472,8 +474,16 @@ reinit:
/* Mark Slave initialization complete */
rt5682->hw_init = true;
rt5682->first_hw_init = true;
+ goto out;
+
+err_sync:
+ regcache_cache_bypass(rt5682->regmap, false);
+ regcache_cache_only(rt5682->sdw_regmap, true);
+ regcache_cache_only(rt5682->regmap, true);
+ regcache_mark_dirty(rt5682->regmap);
err_nodev:
+out:
pm_runtime_put_autosuspend(&slave->dev);
dev_dbg(&slave->dev, "%s hw_init complete: %d\n", __func__, ret);
@@ -776,7 +786,13 @@ static int rt5682_dev_resume(struct device *dev)
regcache_cache_only(rt5682->sdw_regmap, false);
regcache_cache_only(rt5682->regmap, false);
- regcache_sync(rt5682->regmap);
+ ret = regcache_sync(rt5682->regmap);
+ if (ret) {
+ regcache_cache_only(rt5682->sdw_regmap, true);
+ regcache_cache_only(rt5682->regmap, true);
+ regcache_mark_dirty(rt5682->regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/rt712-sdca-dmic.c b/sound/soc/codecs/rt712-sdca-dmic.c
index 85779547653e..8860d81134e7 100644
--- a/sound/soc/codecs/rt712-sdca-dmic.c
+++ b/sound/soc/codecs/rt712-sdca-dmic.c
@@ -916,10 +916,23 @@ static int rt712_sdca_dmic_dev_resume(struct device *dev)
}
regcache_cache_only(rt712->regmap, false);
- regcache_sync(rt712->regmap);
+ ret = regcache_sync(rt712->regmap);
+ if (ret)
+ goto err_sync;
+
regcache_cache_only(rt712->mbq_regmap, false);
- regcache_sync(rt712->mbq_regmap);
+ ret = regcache_sync(rt712->mbq_regmap);
+ if (ret)
+ goto err_sync;
+
return 0;
+
+err_sync:
+ regcache_cache_only(rt712->regmap, true);
+ regcache_cache_only(rt712->mbq_regmap, true);
+ regcache_mark_dirty(rt712->regmap);
+ regcache_mark_dirty(rt712->mbq_regmap);
+ return ret;
}
static const struct dev_pm_ops rt712_sdca_dmic_pm = {
diff --git a/sound/soc/codecs/rt712-sdca-sdw.c b/sound/soc/codecs/rt712-sdca-sdw.c
index 70d661ce2ef2..ebdf7b308331 100644
--- a/sound/soc/codecs/rt712-sdca-sdw.c
+++ b/sound/soc/codecs/rt712-sdca-sdw.c
@@ -472,10 +472,23 @@ static int rt712_sdca_dev_resume(struct device *dev)
}
regcache_cache_only(rt712->regmap, false);
- regcache_sync(rt712->regmap);
+ ret = regcache_sync(rt712->regmap);
+ if (ret)
+ goto err_sync;
+
regcache_cache_only(rt712->mbq_regmap, false);
- regcache_sync(rt712->mbq_regmap);
+ ret = regcache_sync(rt712->mbq_regmap);
+ if (ret)
+ goto err_sync;
+
return 0;
+
+err_sync:
+ regcache_cache_only(rt712->regmap, true);
+ regcache_cache_only(rt712->mbq_regmap, true);
+ regcache_mark_dirty(rt712->regmap);
+ regcache_mark_dirty(rt712->mbq_regmap);
+ return ret;
}
static const struct dev_pm_ops rt712_sdca_pm = {
diff --git a/sound/soc/codecs/rt721-sdca-sdw.c b/sound/soc/codecs/rt721-sdca-sdw.c
index 041b381e582b..6e27e761afb6 100644
--- a/sound/soc/codecs/rt721-sdca-sdw.c
+++ b/sound/soc/codecs/rt721-sdca-sdw.c
@@ -510,10 +510,23 @@ static int rt721_sdca_dev_resume(struct device *dev)
}
regcache_cache_only(rt721->regmap, false);
- regcache_sync(rt721->regmap);
+ ret = regcache_sync(rt721->regmap);
+ if (ret)
+ goto err_sync;
+
regcache_cache_only(rt721->mbq_regmap, false);
- regcache_sync(rt721->mbq_regmap);
+ ret = regcache_sync(rt721->mbq_regmap);
+ if (ret)
+ goto err_sync;
+
return 0;
+
+err_sync:
+ regcache_cache_only(rt721->regmap, true);
+ regcache_cache_only(rt721->mbq_regmap, true);
+ regcache_mark_dirty(rt721->regmap);
+ regcache_mark_dirty(rt721->mbq_regmap);
+ return ret;
}
static const struct dev_pm_ops rt721_sdca_pm = {
diff --git a/sound/soc/codecs/rt722-sdca-sdw.c b/sound/soc/codecs/rt722-sdca-sdw.c
index e68aa0350a5b..d2db33b4f684 100644
--- a/sound/soc/codecs/rt722-sdca-sdw.c
+++ b/sound/soc/codecs/rt722-sdca-sdw.c
@@ -557,7 +557,13 @@ static int rt722_sdca_dev_resume(struct device *dev)
}
regcache_cache_only(rt722->regmap, false);
- regcache_sync(rt722->regmap);
+ ret = regcache_sync(rt722->regmap);
+ if (ret) {
+ regcache_cache_only(rt722->regmap, true);
+ regcache_mark_dirty(rt722->regmap);
+ return ret;
+ }
+
return 0;
}
diff --git a/sound/soc/codecs/rt9120.c b/sound/soc/codecs/rt9120.c
index 97f56af25577..e51cd4a31894 100644
--- a/sound/soc/codecs/rt9120.c
+++ b/sound/soc/codecs/rt9120.c
@@ -606,12 +606,19 @@ static int rt9120_runtime_suspend(struct device *dev)
static int rt9120_runtime_resume(struct device *dev)
{
struct rt9120_data *data = dev_get_drvdata(dev);
+ int ret;
if (data->pwdnn_gpio) {
gpiod_set_value(data->pwdnn_gpio, 1);
msleep(RT9120_CHIPON_WAITMS);
regcache_cache_only(data->regmap, false);
- regcache_sync(data->regmap);
+ ret = regcache_sync(data->regmap);
+ if (ret) {
+ regcache_cache_only(data->regmap, true);
+ regcache_mark_dirty(data->regmap);
+ gpiod_set_value(data->pwdnn_gpio, 0);
+ return ret;
+ }
}
return 0;
diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c
index 1a7650b9b2a7..22f93e29454f 100644
--- a/sound/soc/codecs/tas2552.c
+++ b/sound/soc/codecs/tas2552.c
@@ -495,13 +495,21 @@ static int tas2552_runtime_suspend(struct device *dev)
static int tas2552_runtime_resume(struct device *dev)
{
struct tas2552_data *tas2552 = dev_get_drvdata(dev);
+ int ret;
gpiod_set_value_cansleep(tas2552->enable_gpio, 1);
tas2552_sw_shutdown(tas2552, 0);
regcache_cache_only(tas2552->regmap, false);
- regcache_sync(tas2552->regmap);
+ ret = regcache_sync(tas2552->regmap);
+ if (ret) {
+ regcache_cache_only(tas2552->regmap, true);
+ regcache_mark_dirty(tas2552->regmap);
+ tas2552_sw_shutdown(tas2552, 1);
+ gpiod_set_value_cansleep(tas2552->enable_gpio, 0);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/tas2562.c b/sound/soc/codecs/tas2562.c
index 2f7cfc2be970..e1d62f30418a 100644
--- a/sound/soc/codecs/tas2562.c
+++ b/sound/soc/codecs/tas2562.c
@@ -675,11 +675,12 @@ static int tas2562_parse_dt(struct tas2562_data *tas2562)
if (tas2562->sdz_gpio == NULL) {
tas2562->sdz_gpio = devm_gpiod_get_optional(dev, "shut-down",
GPIOD_OUT_HIGH);
- if (IS_ERR(tas2562->sdz_gpio))
+ if (IS_ERR(tas2562->sdz_gpio)) {
if (PTR_ERR(tas2562->sdz_gpio) == -EPROBE_DEFER)
return -EPROBE_DEFER;
- tas2562->sdz_gpio = NULL;
+ tas2562->sdz_gpio = NULL;
+ }
}
if (tas2562->model_id == TAS2110)
diff --git a/sound/soc/codecs/tas2783-sdw.c b/sound/soc/codecs/tas2783-sdw.c
index 3d0b116544cc..db58c50e8a83 100644
--- a/sound/soc/codecs/tas2783-sdw.c
+++ b/sound/soc/codecs/tas2783-sdw.c
@@ -1099,7 +1099,13 @@ static s32 tas2783_sdca_dev_resume(struct device *dev)
}
regcache_cache_only(tas_dev->regmap, false);
- regcache_sync(tas_dev->regmap);
+ ret = regcache_sync(tas_dev->regmap);
+ if (ret) {
+ regcache_cache_only(tas_dev->regmap, true);
+ regcache_mark_dirty(tas_dev->regmap);
+ return ret;
+ }
+
return 0;
}
@@ -1210,6 +1216,7 @@ static s32 tas_update_status(struct sdw_slave *slave,
{
struct tas2783_prv *tas_dev = dev_get_drvdata(&slave->dev);
struct device *dev = &slave->dev;
+ int ret;
dev_dbg(dev, "Peripheral status = %s",
status == SDW_SLAVE_UNATTACHED ? "unattached" :
@@ -1227,7 +1234,12 @@ static s32 tas_update_status(struct sdw_slave *slave,
/* updated the cache data to device */
regcache_cache_only(tas_dev->regmap, false);
- regcache_sync(tas_dev->regmap);
+ ret = regcache_sync(tas_dev->regmap);
+ if (ret) {
+ regcache_cache_only(tas_dev->regmap, true);
+ regcache_mark_dirty(tas_dev->regmap);
+ return ret;
+ }
/* perform I/O transfers required for Slave initialization */
return tas_io_init(&slave->dev, slave);
diff --git a/sound/soc/codecs/uda1342.c b/sound/soc/codecs/uda1342.c
index 12f5757f4210..4e2d6240a869 100644
--- a/sound/soc/codecs/uda1342.c
+++ b/sound/soc/codecs/uda1342.c
@@ -308,9 +308,16 @@ static int uda1342_suspend(struct device *dev)
static int uda1342_resume(struct device *dev)
{
struct uda1342_priv *uda1342 = dev_get_drvdata(dev);
+ int ret;
+ regcache_cache_only(uda1342->regmap, false);
regcache_mark_dirty(uda1342->regmap);
- regcache_sync(uda1342->regmap);
+ ret = regcache_sync(uda1342->regmap);
+ if (ret) {
+ regcache_cache_only(uda1342->regmap, true);
+ regcache_mark_dirty(uda1342->regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/wcd937x-sdw.c b/sound/soc/codecs/wcd937x-sdw.c
index 7a18bed7f347..1ad75c226060 100644
--- a/sound/soc/codecs/wcd937x-sdw.c
+++ b/sound/soc/codecs/wcd937x-sdw.c
@@ -1084,10 +1084,16 @@ static int wcd937x_sdw_runtime_suspend(struct device *dev)
static int wcd937x_sdw_runtime_resume(struct device *dev)
{
struct wcd937x_sdw_priv *wcd = dev_get_drvdata(dev);
+ int ret;
if (wcd->regmap) {
regcache_cache_only(wcd->regmap, false);
- regcache_sync(wcd->regmap);
+ ret = regcache_sync(wcd->regmap);
+ if (ret) {
+ regcache_cache_only(wcd->regmap, true);
+ regcache_mark_dirty(wcd->regmap);
+ return ret;
+ }
}
return 0;
diff --git a/sound/soc/codecs/wcd938x-sdw.c b/sound/soc/codecs/wcd938x-sdw.c
index 0f0cc0ac3056..e5ad368418a2 100644
--- a/sound/soc/codecs/wcd938x-sdw.c
+++ b/sound/soc/codecs/wcd938x-sdw.c
@@ -1245,10 +1245,16 @@ static int wcd938x_sdw_runtime_suspend(struct device *dev)
static int wcd938x_sdw_runtime_resume(struct device *dev)
{
struct wcd938x_sdw_priv *wcd = dev_get_drvdata(dev);
+ int ret;
if (wcd->regmap) {
regcache_cache_only(wcd->regmap, false);
- regcache_sync(wcd->regmap);
+ ret = regcache_sync(wcd->regmap);
+ if (ret) {
+ regcache_cache_only(wcd->regmap, true);
+ regcache_mark_dirty(wcd->regmap);
+ return ret;
+ }
}
pm_runtime_mark_last_busy(dev);
diff --git a/sound/soc/codecs/wcd939x-sdw.c b/sound/soc/codecs/wcd939x-sdw.c
index 95f4be287e79..69b9b08118f0 100644
--- a/sound/soc/codecs/wcd939x-sdw.c
+++ b/sound/soc/codecs/wcd939x-sdw.c
@@ -1431,10 +1431,16 @@ static int wcd939x_sdw_runtime_suspend(struct device *dev)
static int wcd939x_sdw_runtime_resume(struct device *dev)
{
struct wcd939x_sdw_priv *wcd = dev_get_drvdata(dev);
+ int ret;
if (wcd->regmap) {
regcache_cache_only(wcd->regmap, false);
- regcache_sync(wcd->regmap);
+ ret = regcache_sync(wcd->regmap);
+ if (ret) {
+ regcache_cache_only(wcd->regmap, true);
+ regcache_mark_dirty(wcd->regmap);
+ return ret;
+ }
}
return 0;
diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
index ba8ce2e6e615..bc78b553b6cb 100644
--- a/sound/soc/codecs/wm2200.c
+++ b/sound/soc/codecs/wm2200.c
@@ -2461,7 +2461,15 @@ static int wm2200_runtime_resume(struct device *dev)
}
regcache_cache_only(wm2200->regmap, false);
- regcache_sync(wm2200->regmap);
+ ret = regcache_sync(wm2200->regmap);
+ if (ret) {
+ regcache_cache_only(wm2200->regmap, true);
+ regcache_mark_dirty(wm2200->regmap);
+ gpiod_set_value_cansleep(wm2200->ldo_ena, 0);
+ regulator_bulk_disable(ARRAY_SIZE(wm2200->core_supplies),
+ wm2200->core_supplies);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c
index bd94fa53c362..2fe937a93026 100644
--- a/sound/soc/codecs/wm5100.c
+++ b/sound/soc/codecs/wm5100.c
@@ -2659,7 +2659,15 @@ static int wm5100_runtime_resume(struct device *dev)
}
regcache_cache_only(wm5100->regmap, false);
- regcache_sync(wm5100->regmap);
+ ret = regcache_sync(wm5100->regmap);
+ if (ret) {
+ regcache_cache_only(wm5100->regmap, true);
+ regcache_mark_dirty(wm5100->regmap);
+ gpiod_set_value_cansleep(wm5100->ldo_ena, 0);
+ regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies),
+ wm5100->core_supplies);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index de18b1f85a32..2db822fc1de7 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -3937,7 +3937,9 @@ static int wm8962_runtime_resume(struct device *dev)
WM8962_OSC_ENA | WM8962_PLL2_ENA | WM8962_PLL3_ENA,
0);
- regcache_sync(wm8962->regmap);
+ ret = regcache_sync(wm8962->regmap);
+ if (ret)
+ goto cache_sync_err;
regmap_update_bits(wm8962->regmap, WM8962_ANTI_POP,
WM8962_STARTUP_BIAS_ENA | WM8962_VMID_BUF_ENA,
@@ -3955,6 +3957,11 @@ static int wm8962_runtime_resume(struct device *dev)
return 0;
+cache_sync_err:
+ regcache_cache_only(wm8962->regmap, true);
+ regcache_mark_dirty(wm8962->regmap);
+ regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies),
+ wm8962->supplies);
disable_clock:
clk_disable_unprepare(wm8962->pdata.mclk);
return ret;
diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c
index 5174614c3e83..47ac3e4985a5 100644
--- a/sound/soc/codecs/wsa881x.c
+++ b/sound/soc/codecs/wsa881x.c
@@ -1178,7 +1178,13 @@ static int wsa881x_runtime_resume(struct device *dev)
}
regcache_cache_only(regmap, false);
- regcache_sync(regmap);
+ ret = regcache_sync(regmap);
+ if (ret) {
+ regcache_cache_only(regmap, true);
+ regcache_mark_dirty(regmap);
+ gpiod_direction_output(wsa881x->sd_n, 1);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c
index 468d2b38a22a..24a5904d8e6c 100644
--- a/sound/soc/codecs/wsa883x.c
+++ b/sound/soc/codecs/wsa883x.c
@@ -1696,9 +1696,15 @@ static int wsa883x_runtime_suspend(struct device *dev)
static int wsa883x_runtime_resume(struct device *dev)
{
struct regmap *regmap = dev_get_regmap(dev, NULL);
+ int ret;
regcache_cache_only(regmap, false);
- regcache_sync(regmap);
+ ret = regcache_sync(regmap);
+ if (ret) {
+ regcache_cache_only(regmap, true);
+ regcache_mark_dirty(regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/wsa884x.c b/sound/soc/codecs/wsa884x.c
index 6c6b497657d0..567861dd42ad 100644
--- a/sound/soc/codecs/wsa884x.c
+++ b/sound/soc/codecs/wsa884x.c
@@ -2147,9 +2147,15 @@ static int wsa884x_runtime_suspend(struct device *dev)
static int wsa884x_runtime_resume(struct device *dev)
{
struct regmap *regmap = dev_get_regmap(dev, NULL);
+ int ret;
regcache_cache_only(regmap, false);
- regcache_sync(regmap);
+ ret = regcache_sync(regmap);
+ if (ret) {
+ regcache_cache_only(regmap, true);
+ regcache_mark_dirty(regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/meson/t9015.c b/sound/soc/meson/t9015.c
index f0b55aee5241..68b5323ca9c8 100644
--- a/sound/soc/meson/t9015.c
+++ b/sound/soc/meson/t9015.c
@@ -78,8 +78,14 @@ static int t9015_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return 0;
}
+static const u64 t9015_dai_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
static const struct snd_soc_dai_ops t9015_dai_ops = {
.set_fmt = t9015_dai_set_fmt,
+ .auto_selectable_formats = &t9015_dai_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static struct snd_soc_dai_driver t9015_dai = {
diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c
index 7925aa3f63ba..98b15a527e37 100644
--- a/sound/soc/qcom/sc8280xp.c
+++ b/sound/soc/qcom/sc8280xp.c
@@ -164,6 +164,7 @@ static int sc8280xp_platform_probe(struct platform_device *pdev)
}
static const struct of_device_id snd_sc8280xp_dt_match[] = {
+ {.compatible = "qcom,eliza-sndcard", "eliza"},
{.compatible = "qcom,kaanapali-sndcard", "kaanapali"},
{.compatible = "qcom,qcm6490-idp-sndcard", "qcm6490"},
{.compatible = "qcom,qcs615-sndcard", "qcs615"},
diff --git a/sound/soc/samsung/aries_wm8994.c b/sound/soc/samsung/aries_wm8994.c
index 6db91b73f25c..d8659973540f 100644
--- a/sound/soc/samsung/aries_wm8994.c
+++ b/sound/soc/samsung/aries_wm8994.c
@@ -701,3 +701,4 @@ module_platform_driver(aries_audio_driver);
MODULE_DESCRIPTION("ALSA SoC ARIES WM8994");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:aries-audio-wm8994");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/sound/soc/samsung/midas_wm1811.c b/sound/soc/samsung/midas_wm1811.c
index bc34dbbb50c9..d43af5069baf 100644
--- a/sound/soc/samsung/midas_wm1811.c
+++ b/sound/soc/samsung/midas_wm1811.c
@@ -773,3 +773,4 @@ module_platform_driver(midas_driver);
MODULE_AUTHOR("Simon Shields <simon@lineageos.org>");
MODULE_DESCRIPTION("ASoC support for Midas");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/sound/soc/spacemit/k1_i2s.c b/sound/soc/spacemit/k1_i2s.c
index 8871fc15b29c..cd461f2aa756 100644
--- a/sound/soc/spacemit/k1_i2s.c
+++ b/sound/soc/spacemit/k1_i2s.c
@@ -335,6 +335,11 @@ static int spacemit_i2s_dai_remove(struct snd_soc_dai *dai)
return 0;
}
+static const u64 spacemit_i2s_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_B;
+
static const struct snd_soc_dai_ops spacemit_i2s_dai_ops = {
.probe = spacemit_i2s_dai_probe,
.remove = spacemit_i2s_dai_remove,
@@ -343,6 +348,8 @@ static const struct snd_soc_dai_ops spacemit_i2s_dai_ops = {
.set_sysclk = spacemit_i2s_set_sysclk,
.set_fmt = spacemit_i2s_set_fmt,
.trigger = spacemit_i2s_trigger,
+ .auto_selectable_formats = &spacemit_i2s_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static struct snd_soc_dai_driver spacemit_i2s_dai = {
diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c
index 66efb9a0acb9..c8022f6efd8a 100644
--- a/sound/soc/stm/stm32_adfsdm.c
+++ b/sound/soc/stm/stm32_adfsdm.c
@@ -392,3 +392,4 @@ MODULE_DESCRIPTION("stm32 DFSDM DAI driver");
MODULE_AUTHOR("Arnaud Pouliquen <arnaud.pouliquen@st.com>");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" STM32_ADFSDM_DRV_NAME);
+MODULE_IMPORT_NS("IIO_CONSUMER");
diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c
index 7798957c6504..499e826d7120 100644
--- a/sound/soc/ux500/ux500_msp_dai.c
+++ b/sound/soc/ux500/ux500_msp_dai.c
@@ -14,7 +14,7 @@
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/regulator/consumer.h>
-#include <linux/mfd/dbx500-prcmu.h>
+#include <linux/mfd/db8500-prcmu.h>
#include <sound/soc.h>
#include <sound/soc-dai.h>
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 1cb588691e16..2949a0d2d961 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -2210,6 +2210,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
QUIRK_FLAG_FORCE_IFACE_RESET | QUIRK_FLAG_IFACE_DELAY),
DEVICE_FLG(0x03f0, 0x654a, /* HP 320 FHD Webcam */
QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16),
+ DEVICE_FLG(0x040b, 0x0897, /* Weltrend Semiconductor, sold as Redragon H510-PRO Wireless headset */
+ QUIRK_FLAG_MIXER_GET_CUR_BROKEN),
DEVICE_FLG(0x041e, 0x3000, /* Creative SB Extigy */
QUIRK_FLAG_IGNORE_CTL_ERROR),
DEVICE_FLG(0x041e, 0x4080, /* Creative Live Cam VF0610 */
diff --git a/tools/bpf/bpftool/gen.c b/tools/bpf/bpftool/gen.c
index 6ae7262ebe0c..a01d06d22d1a 100644
--- a/tools/bpf/bpftool/gen.c
+++ b/tools/bpf/bpftool/gen.c
@@ -793,6 +793,8 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
if (sign_progs) {
sopts.insns = opts.insns;
sopts.insns_sz = opts.insns_sz;
+ sopts.data = opts.data;
+ sopts.data_sz = opts.data_sz;
sopts.excl_prog_hash = prog_sha;
sopts.excl_prog_hash_sz = sizeof(prog_sha);
sopts.signature = sig_buf;
diff --git a/tools/bpf/bpftool/sign.c b/tools/bpf/bpftool/sign.c
index f9b742f4bb10..88726a6db6d0 100644
--- a/tools/bpf/bpftool/sign.c
+++ b/tools/bpf/bpftool/sign.c
@@ -135,9 +135,21 @@ int bpftool_prog_sign(struct bpf_load_and_run_opts *opts)
CMS_ContentInfo *cms = NULL;
long actual_sig_len = 0;
X509 *x509 = NULL;
+ void *data = NULL;
+ size_t data_sz;
int err = 0;
- bd_in = BIO_new_mem_buf(opts->insns, opts->insns_sz);
+ data_sz = (size_t)opts->insns_sz + opts->data_sz;
+ data = malloc(data_sz);
+ if (!data) {
+ err = -ENOMEM;
+ goto cleanup;
+ }
+ memcpy(data, opts->insns, opts->insns_sz);
+ if (opts->data_sz)
+ memcpy((char *)data + opts->insns_sz, opts->data, opts->data_sz);
+
+ bd_in = BIO_new_mem_buf(data, data_sz);
if (!bd_in) {
err = -ENOMEM;
goto cleanup;
@@ -175,10 +187,13 @@ int bpftool_prog_sign(struct bpf_load_and_run_opts *opts)
goto cleanup;
}
- EVP_Digest(opts->insns, opts->insns_sz, opts->excl_prog_hash,
- &opts->excl_prog_hash_sz, EVP_sha256(), NULL);
+ if (EVP_Digest(opts->insns, opts->insns_sz, opts->excl_prog_hash,
+ &opts->excl_prog_hash_sz, EVP_sha256(), NULL) != 1) {
+ err = -EIO;
+ goto cleanup;
+ }
- bd_out = BIO_new(BIO_s_mem());
+ bd_out = BIO_new(BIO_s_mem());
if (!bd_out) {
err = -ENOMEM;
goto cleanup;
@@ -212,6 +227,7 @@ cleanup:
X509_free(x509);
EVP_PKEY_free(private_key);
BIO_free(bd_in);
+ free(data);
DISPLAY_OSSL_ERR(err < 0);
return err;
}
diff --git a/tools/bpf/resolve_btfids/Makefile b/tools/bpf/resolve_btfids/Makefile
index 7672208f65e4..bb0463b380af 100644
--- a/tools/bpf/resolve_btfids/Makefile
+++ b/tools/bpf/resolve_btfids/Makefile
@@ -40,7 +40,6 @@ LIBBPF_DESTDIR := $(LIBBPF_OUT)
LIBBPF_INCLUDE := $(LIBBPF_DESTDIR)include
SUBCMD_DESTDIR := $(SUBCMD_OUT)
-SUBCMD_INCLUDE := $(SUBCMD_DESTDIR)include
BINARY := $(OUTPUT)/resolve_btfids
BINARY_IN := $(BINARY)-in.o
@@ -56,7 +55,7 @@ $(OUTPUT) $(OUTPUT)/libsubcmd $(LIBBPF_OUT):
$(SUBCMDOBJ): fixdep FORCE | $(OUTPUT)/libsubcmd
$(Q)$(MAKE) -C $(SUBCMD_SRC) OUTPUT=$(SUBCMD_OUT) \
DESTDIR=$(SUBCMD_DESTDIR) $(HOST_OVERRIDES) prefix= subdir= \
- $(abspath $@) install_headers
+ $(abspath $@)
$(BPFOBJ): $(wildcard $(LIBBPF_SRC)/*.[ch] $(LIBBPF_SRC)/Makefile) | $(LIBBPF_OUT)
$(Q)$(MAKE) $(submake_extras) -C $(LIBBPF_SRC) OUTPUT=$(LIBBPF_OUT) \
@@ -77,7 +76,7 @@ HOSTCFLAGS_resolve_btfids += -g \
-I$(srctree)/tools/include \
-I$(srctree)/tools/include/uapi \
-I$(LIBBPF_INCLUDE) \
- -I$(SUBCMD_INCLUDE) \
+ -I$(srctree)/tools/lib \
$(LIBELF_FLAGS) \
-Wall -Werror
diff --git a/tools/include/uapi/linux/fs.h b/tools/include/uapi/linux/fs.h
index 24ddf7bc4f25..f0a26309b6d5 100644
--- a/tools/include/uapi/linux/fs.h
+++ b/tools/include/uapi/linux/fs.h
@@ -364,6 +364,7 @@ typedef int __bitwise __kernel_rwf_t;
#define PAGE_IS_HUGE (1 << 6)
#define PAGE_IS_SOFT_DIRTY (1 << 7)
#define PAGE_IS_GUARD (1 << 8)
+#define PAGE_IS_ACCESSED (1 << 9)
/*
* struct page_region - Page region with flags
diff --git a/tools/include/uapi/linux/userfaultfd.h b/tools/include/uapi/linux/userfaultfd.h
index 4283de22d5b6..c8e99df95219 100644
--- a/tools/include/uapi/linux/userfaultfd.h
+++ b/tools/include/uapi/linux/userfaultfd.h
@@ -25,7 +25,8 @@
#define UFFD_API ((__u64)0xAA)
#define UFFD_API_REGISTER_MODES (UFFDIO_REGISTER_MODE_MISSING | \
UFFDIO_REGISTER_MODE_WP | \
- UFFDIO_REGISTER_MODE_MINOR)
+ UFFDIO_REGISTER_MODE_MINOR | \
+ UFFDIO_REGISTER_MODE_RWP)
#define UFFD_API_FEATURES (UFFD_FEATURE_PAGEFAULT_FLAG_WP | \
UFFD_FEATURE_EVENT_FORK | \
UFFD_FEATURE_EVENT_REMAP | \
@@ -42,10 +43,13 @@
UFFD_FEATURE_WP_UNPOPULATED | \
UFFD_FEATURE_POISON | \
UFFD_FEATURE_WP_ASYNC | \
- UFFD_FEATURE_MOVE)
+ UFFD_FEATURE_MOVE | \
+ UFFD_FEATURE_RWP | \
+ UFFD_FEATURE_RWP_ASYNC)
#define UFFD_API_IOCTLS \
((__u64)1 << _UFFDIO_REGISTER | \
(__u64)1 << _UFFDIO_UNREGISTER | \
+ (__u64)1 << _UFFDIO_SET_MODE | \
(__u64)1 << _UFFDIO_API)
#define UFFD_API_RANGE_IOCTLS \
((__u64)1 << _UFFDIO_WAKE | \
@@ -54,13 +58,15 @@
(__u64)1 << _UFFDIO_MOVE | \
(__u64)1 << _UFFDIO_WRITEPROTECT | \
(__u64)1 << _UFFDIO_CONTINUE | \
- (__u64)1 << _UFFDIO_POISON)
+ (__u64)1 << _UFFDIO_POISON | \
+ (__u64)1 << _UFFDIO_RWPROTECT)
#define UFFD_API_RANGE_IOCTLS_BASIC \
((__u64)1 << _UFFDIO_WAKE | \
(__u64)1 << _UFFDIO_COPY | \
(__u64)1 << _UFFDIO_WRITEPROTECT | \
(__u64)1 << _UFFDIO_CONTINUE | \
- (__u64)1 << _UFFDIO_POISON)
+ (__u64)1 << _UFFDIO_POISON | \
+ (__u64)1 << _UFFDIO_RWPROTECT)
/*
* Valid ioctl command number range with this API is from 0x00 to
@@ -79,6 +85,8 @@
#define _UFFDIO_WRITEPROTECT (0x06)
#define _UFFDIO_CONTINUE (0x07)
#define _UFFDIO_POISON (0x08)
+#define _UFFDIO_RWPROTECT (0x09)
+#define _UFFDIO_SET_MODE (0x0A)
#define _UFFDIO_API (0x3F)
/* userfaultfd ioctl ids */
@@ -103,6 +111,10 @@
struct uffdio_continue)
#define UFFDIO_POISON _IOWR(UFFDIO, _UFFDIO_POISON, \
struct uffdio_poison)
+#define UFFDIO_RWPROTECT _IOWR(UFFDIO, _UFFDIO_RWPROTECT, \
+ struct uffdio_rwprotect)
+#define UFFDIO_SET_MODE _IOW(UFFDIO, _UFFDIO_SET_MODE, \
+ struct uffdio_set_mode)
/* read() structure */
struct uffd_msg {
@@ -158,6 +170,7 @@ struct uffd_msg {
#define UFFD_PAGEFAULT_FLAG_WRITE (1<<0) /* If this was a write fault */
#define UFFD_PAGEFAULT_FLAG_WP (1<<1) /* If reason is VM_UFFD_WP */
#define UFFD_PAGEFAULT_FLAG_MINOR (1<<2) /* If reason is VM_UFFD_MINOR */
+#define UFFD_PAGEFAULT_FLAG_RWP (1<<3) /* If reason is VM_UFFD_RWP */
struct uffdio_api {
/* userland asks for an API number and the features to enable */
@@ -230,6 +243,18 @@ struct uffdio_api {
*
* UFFD_FEATURE_MOVE indicates that the kernel supports moving an
* existing page contents from userspace.
+ *
+ * UFFD_FEATURE_RWP indicates that the kernel supports
+ * UFFDIO_REGISTER_MODE_RWP for read-write protection tracking.
+ * Pages are made inaccessible via UFFDIO_RWPROTECT and faults
+ * are delivered when the pages are re-accessed.
+ *
+ * UFFD_FEATURE_RWP_ASYNC indicates asynchronous mode for
+ * UFFDIO_REGISTER_MODE_RWP. When set, faults on read-write
+ * protected pages are auto-resolved by the kernel (PTE
+ * permissions restored immediately) without delivering a message
+ * to the userfaultfd handler. Use PAGEMAP_SCAN with inverted
+ * PAGE_IS_ACCESSED to find pages that were not re-accessed.
*/
#define UFFD_FEATURE_PAGEFAULT_FLAG_WP (1<<0)
#define UFFD_FEATURE_EVENT_FORK (1<<1)
@@ -248,6 +273,8 @@ struct uffdio_api {
#define UFFD_FEATURE_POISON (1<<14)
#define UFFD_FEATURE_WP_ASYNC (1<<15)
#define UFFD_FEATURE_MOVE (1<<16)
+#define UFFD_FEATURE_RWP (1<<17)
+#define UFFD_FEATURE_RWP_ASYNC (1<<18)
__u64 features;
__u64 ioctls;
@@ -263,6 +290,7 @@ struct uffdio_register {
#define UFFDIO_REGISTER_MODE_MISSING ((__u64)1<<0)
#define UFFDIO_REGISTER_MODE_WP ((__u64)1<<1)
#define UFFDIO_REGISTER_MODE_MINOR ((__u64)1<<2)
+#define UFFDIO_REGISTER_MODE_RWP ((__u64)1<<3)
__u64 mode;
/*
@@ -356,6 +384,14 @@ struct uffdio_poison {
__s64 updated;
};
+struct uffdio_rwprotect {
+ struct uffdio_range range;
+ /* !RWP means undo RWP-protection */
+#define UFFDIO_RWPROTECT_MODE_RWP ((__u64)1<<0)
+#define UFFDIO_RWPROTECT_MODE_DONTWAKE ((__u64)1<<1)
+ __u64 mode;
+};
+
struct uffdio_move {
__u64 dst;
__u64 src;
@@ -374,6 +410,16 @@ struct uffdio_move {
__s64 move;
};
+struct uffdio_set_mode {
+ /*
+ * Toggle async mode for features at runtime.
+ * Supported: UFFD_FEATURE_RWP_ASYNC.
+ * Setting a bit in both enable and disable is invalid.
+ */
+ __u64 enable;
+ __u64 disable;
+};
+
/*
* Flags for the userfaultfd(2) system call itself.
*/
diff --git a/tools/lib/api/fd/array.c b/tools/lib/api/fd/array.c
index f0f195207fca..ffe8272af59b 100644
--- a/tools/lib/api/fd/array.c
+++ b/tools/lib/api/fd/array.c
@@ -122,6 +122,12 @@ int fdarray__filter(struct fdarray *fda, short revents,
if (entry_destructor)
entry_destructor(fda, fd, arg);
+ /*
+ * Set fd to -1 so poll() ignores this entry; otherwise
+ * POLLHUP/POLLERR are still reported for events=0 fds
+ * (POSIX: always checked), causing a poll storm.
+ */
+ fda->entries[fd].fd = -1;
fda->entries[fd].revents = fda->entries[fd].events = 0;
continue;
}
diff --git a/tools/lib/bpf/bpf_gen_internal.h b/tools/lib/bpf/bpf_gen_internal.h
index 49af4260b8e6..042569187752 100644
--- a/tools/lib/bpf/bpf_gen_internal.h
+++ b/tools/lib/bpf/bpf_gen_internal.h
@@ -51,7 +51,6 @@ struct bpf_gen {
__u32 nr_ksyms;
int fd_array;
int nr_fd_array;
- int hash_insn_offset[SHA256_DWORD_SIZE];
};
void bpf_gen__init(struct bpf_gen *gen, int log_level, int nr_progs, int nr_maps);
diff --git a/tools/lib/bpf/gen_loader.c b/tools/lib/bpf/gen_loader.c
index c7f2d2ac7bb3..6e3dd5242761 100644
--- a/tools/lib/bpf/gen_loader.c
+++ b/tools/lib/bpf/gen_loader.c
@@ -111,7 +111,6 @@ static void emit2(struct bpf_gen *gen, struct bpf_insn insn1, struct bpf_insn in
static int add_data(struct bpf_gen *gen, const void *data, __u32 size);
static void emit_sys_close_blob(struct bpf_gen *gen, int blob_off);
-static void emit_signature_match(struct bpf_gen *gen);
void bpf_gen__init(struct bpf_gen *gen, int log_level, int nr_progs, int nr_maps)
{
@@ -154,8 +153,6 @@ void bpf_gen__init(struct bpf_gen *gen, int log_level, int nr_progs, int nr_maps
/* R7 contains the error code from sys_bpf. Copy it into R0 and exit. */
emit(gen, BPF_MOV64_REG(BPF_REG_0, BPF_REG_7));
emit(gen, BPF_EXIT_INSN());
- if (OPTS_GET(gen->opts, gen_hash, false))
- emit_signature_match(gen);
}
static int add_data(struct bpf_gen *gen, const void *data, __u32 size)
@@ -377,8 +374,6 @@ static void emit_sys_close_blob(struct bpf_gen *gen, int blob_off)
__emit_sys_close(gen);
}
-static void compute_sha_update_offsets(struct bpf_gen *gen);
-
int bpf_gen__finish(struct bpf_gen *gen, int nr_progs, int nr_maps)
{
int i;
@@ -408,9 +403,6 @@ int bpf_gen__finish(struct bpf_gen *gen, int nr_progs, int nr_maps)
if (!gen->error) {
struct gen_loader_opts *opts = gen->opts;
- if (OPTS_GET(opts, gen_hash, false))
- compute_sha_update_offsets(gen);
-
opts->insns = gen->insn_start;
opts->insns_sz = gen->insn_cur - gen->insn_start;
opts->data = gen->data_start;
@@ -460,22 +452,6 @@ void bpf_gen__free(struct bpf_gen *gen)
_val; \
})
-static void compute_sha_update_offsets(struct bpf_gen *gen)
-{
- __u64 sha[SHA256_DWORD_SIZE];
- __u64 sha_dw;
- int i;
-
- libbpf_sha256(gen->data_start, gen->data_cur - gen->data_start, (__u8 *)sha);
- for (i = 0; i < SHA256_DWORD_SIZE; i++) {
- struct bpf_insn *insn =
- (struct bpf_insn *)(gen->insn_start + gen->hash_insn_offset[i]);
- sha_dw = tgt_endian(sha[i]);
- insn[0].imm = (__u32)sha_dw;
- insn[1].imm = sha_dw >> 32;
- }
-}
-
void bpf_gen__load_btf(struct bpf_gen *gen, const void *btf_raw_data,
__u32 btf_raw_size)
{
@@ -557,8 +533,9 @@ void bpf_gen__map_create(struct bpf_gen *gen,
* Conditionally update max_entries from the host-supplied loader
* ctx. This sizes the map at runtime, but for a signed loader
* (gen_hash) it would let an untrusted host re-dimension the
- * program's maps after emit_signature_match(), outside what the
- * signature attests to. Keep the signer-provided max_entries
+ * program's maps, outside what the signature attests to: the
+ * metadata blob is covered by the program signature and verified
+ * by the kernel at load time. Keep the signer-provided max_entries
* baked into the blob in that case.
*/
if (map_idx >= 0 && !OPTS_GET(gen->opts, gen_hash, false))
@@ -596,45 +573,6 @@ void bpf_gen__map_create(struct bpf_gen *gen,
emit_sys_close_stack(gen, stack_off(inner_map_fd));
}
-static void emit_signature_match(struct bpf_gen *gen)
-{
- __s64 off;
- int i;
-
- /*
- * Reject if the metadata map is not exclusive. Without exclusivity
- * the cached map->sha[] verified above can be stale: another BPF
- * program with map access could have mutated the contents between
- * BPF_OBJ_GET_INFO_BY_FD and loader execution.
- */
- emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_IDX,
- 0, 0, 0, 0));
- emit(gen, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, SHA256_DIGEST_LENGTH));
- off = -(gen->insn_cur - gen->insn_start - gen->cleanup_label) / 8 - 2;
- if (is_simm16(off)) {
- emit(gen, BPF_MOV64_IMM(BPF_REG_7, -EINVAL));
- emit(gen, BPF_JMP_IMM(BPF_JNE, BPF_REG_2, 1, off));
- } else {
- gen->error = -ERANGE;
- }
-
- for (i = 0; i < SHA256_DWORD_SIZE; i++) {
- emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_IDX,
- 0, 0, 0, 0));
- emit(gen, BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, i * sizeof(__u64)));
- gen->hash_insn_offset[i] = gen->insn_cur - gen->insn_start;
- emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_3, 0, 0, 0, 0, 0));
-
- off = -(gen->insn_cur - gen->insn_start - gen->cleanup_label) / 8 - 2;
- if (is_simm16(off)) {
- emit(gen, BPF_MOV64_IMM(BPF_REG_7, -EINVAL));
- emit(gen, BPF_JMP_REG(BPF_JNE, BPF_REG_2, BPF_REG_3, off));
- } else {
- gen->error = -ERANGE;
- }
- }
-}
-
void bpf_gen__record_attach_target(struct bpf_gen *gen, const char *attach_name,
enum bpf_attach_type type)
{
@@ -1211,10 +1149,10 @@ void bpf_gen__map_update_elem(struct bpf_gen *gen, int map_idx, void *pvalue,
* }
*
* The runtime initial_value comes from the host-supplied loader
- * ctx and would overwrite the blob value after emit_signature_match()
- * has already validated map->sha[]. For a signed loader (gen_hash)
- * the attested blob value must be authoritative, so skip the override
- * and leave the hashed value in place.
+ * ctx and would overwrite the blob value that the program signature
+ * covers and the kernel verifies at load time. For a signed loader
+ * (gen_hash) the attested blob value must be authoritative, so skip
+ * the override and leave the signed value in place.
*/
if (!OPTS_GET(gen->opts, gen_hash, false)) {
emit(gen, BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_6,
diff --git a/tools/lib/bpf/libbpf_internal.h b/tools/lib/bpf/libbpf_internal.h
index 04cd303fb5a8..d5b7db703b3f 100644
--- a/tools/lib/bpf/libbpf_internal.h
+++ b/tools/lib/bpf/libbpf_internal.h
@@ -768,7 +768,6 @@ int elf_resolve_pattern_offsets(const char *binary_path, const char *pattern,
int probe_fd(int fd);
#define SHA256_DIGEST_LENGTH 32
-#define SHA256_DWORD_SIZE SHA256_DIGEST_LENGTH / sizeof(__u64)
void libbpf_sha256(const void *data, size_t len, __u8 out[SHA256_DIGEST_LENGTH]);
int probe_sys_bpf_ext(void);
diff --git a/tools/lib/bpf/skel_internal.h b/tools/lib/bpf/skel_internal.h
index 74503d358bc8..53fee53d36d5 100644
--- a/tools/lib/bpf/skel_internal.h
+++ b/tools/lib/bpf/skel_internal.h
@@ -18,10 +18,6 @@
#include "bpf.h"
#endif
-#ifndef SHA256_DIGEST_LENGTH
-#define SHA256_DIGEST_LENGTH 32
-#endif
-
#ifndef __NR_bpf
# if defined(__mips__) && defined(_ABIO32)
# define __NR_bpf 4355
@@ -320,25 +316,6 @@ static inline int skel_link_create(int prog_fd, int target_fd,
return skel_sys_bpf(BPF_LINK_CREATE, &attr, attr_sz);
}
-static inline int skel_obj_get_info_by_fd(int fd)
-{
- const size_t attr_sz = offsetofend(union bpf_attr, info);
- __u8 sha[SHA256_DIGEST_LENGTH];
- struct bpf_map_info info;
- __u32 info_len = sizeof(info);
- union bpf_attr attr;
-
- memset(&info, 0, sizeof(info));
- info.hash = (long) &sha;
- info.hash_size = SHA256_DIGEST_LENGTH;
-
- memset(&attr, 0, attr_sz);
- attr.info.bpf_fd = fd;
- attr.info.info = (long) &info;
- attr.info.info_len = info_len;
- return skel_sys_bpf(BPF_OBJ_GET_INFO_BY_FD, &attr, attr_sz);
-}
-
static inline int skel_map_freeze(int fd)
{
const size_t attr_sz = offsetofend(union bpf_attr, map_fd);
@@ -384,12 +361,6 @@ static inline int bpf_load_and_run(struct bpf_load_and_run_opts *opts)
set_err;
goto out;
}
- err = skel_obj_get_info_by_fd(map_fd);
- if (err < 0) {
- opts->errstr = "failed to fetch obj info";
- set_err;
- goto out;
- }
#endif
memset(&attr, 0, prog_load_attr_sz);
@@ -400,6 +371,8 @@ static inline int bpf_load_and_run(struct bpf_load_and_run_opts *opts)
#ifndef __KERNEL__
attr.signature = (long) opts->signature;
attr.signature_size = opts->signature_sz;
+ if (opts->signature)
+ attr.fd_array_cnt = 1;
#else
if (opts->signature || opts->signature_sz)
pr_warn("signatures are not supported from bpf_preload\n");
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 92cdb2df7285..3f685beba384 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -2655,6 +2655,13 @@ int cmd_stat(int argc, const char **argv)
stat_config.aggr_mode = opt_aggr_mode_to_aggr_mode(&opt_mode);
+ if (stat_config.csv_sep && stat_config.json_output) {
+ fprintf(stderr, "cannot use both --field-separator and --json-output\n");
+ parse_options_usage(stat_usage, stat_options, "x", 1);
+ parse_options_usage(NULL, stat_options, "j", 1);
+ goto out;
+ }
+
if (stat_config.csv_sep) {
stat_config.csv_output = true;
if (!strcmp(stat_config.csv_sep, "\\t"))
diff --git a/tools/perf/pmu-events/arch/x86/amdzen5/floating-point.json b/tools/perf/pmu-events/arch/x86/amdzen5/floating-point.json
index 569975b53cc3..50d38434f8d3 100644
--- a/tools/perf/pmu-events/arch/x86/amdzen5/floating-point.json
+++ b/tools/perf/pmu-events/arch/x86/amdzen5/floating-point.json
@@ -384,6 +384,13 @@
"UMask": "0x0c"
},
{
+ "EventName": "sse_avx_ops_retired.mmx_pack",
+ "EventCode": "0x0b",
+ "BriefDescription": "This event is deprecated. Refer to new event sse_avx_ops_retired.mmx_vnni",
+ "Deprecated": "1",
+ "UMask": "0x0c"
+ },
+ {
"EventName": "sse_avx_ops_retired.mmx_logical",
"EventCode": "0x0b",
"BriefDescription": "Retired MMX integer logical ops.",
@@ -450,6 +457,13 @@
"UMask": "0x80"
},
{
+ "EventName": "sse_avx_ops_retired.sse_avx_clm",
+ "EventCode": "0x0b",
+ "BriefDescription": "This event is deprecated. Refer to new event sse_avx_ops_retired.sse_avx_cvt",
+ "Deprecated": "1",
+ "UMask": "0x80"
+ },
+ {
"EventName": "sse_avx_ops_retired.sse_avx_shift",
"EventCode": "0x0b",
"BriefDescription": "Retired SSE and AVX integer shift or rotate ops.",
@@ -474,6 +488,13 @@
"UMask": "0xc0"
},
{
+ "EventName": "sse_avx_ops_retired.sse_avx_pack",
+ "EventCode": "0x0b",
+ "BriefDescription": "This event is deprecated. Refer to new event sse_avx_ops_retired.sse_avx_vnni",
+ "Deprecated": "1",
+ "UMask": "0xc0"
+ },
+ {
"EventName": "sse_avx_ops_retired.sse_avx_logical",
"EventCode": "0x0b",
"BriefDescription": "Retired SSE and AVX integer logical ops.",
@@ -732,6 +753,13 @@
"UMask": "0x08"
},
{
+ "EventName": "packed_int_op_type.int128_clm",
+ "EventCode": "0x0d",
+ "BriefDescription": "This event is deprecated. Refer to new event packed_int_op_type.int128_cvt",
+ "Deprecated": "1",
+ "UMask": "0x08"
+ },
+ {
"EventName": "packed_int_op_type.int128_shift",
"EventCode": "0x0d",
"BriefDescription": "Retired 128-bit packed integer shift or rotate ops.",
@@ -756,6 +784,13 @@
"UMask": "0x0c"
},
{
+ "EventName": "packed_int_op_type.int128_pack",
+ "EventCode": "0x0d",
+ "BriefDescription": "This event is deprecated. Refer to new event packed_int_op_type.int128_vnni",
+ "Deprecated": "1",
+ "UMask": "0x0c"
+ },
+ {
"EventName": "packed_int_op_type.int128_logical",
"EventCode": "0x0d",
"BriefDescription": "Retired 128-bit packed integer logical ops.",
@@ -846,6 +881,13 @@
"UMask": "0xc0"
},
{
+ "EventName": "packed_int_op_type.int256_pack",
+ "EventCode": "0x0d",
+ "BriefDescription": "This event is deprecated. Refer to new event packed_int_op_type.int256_vnni",
+ "Deprecated": "1",
+ "UMask": "0xc0"
+ },
+ {
"EventName": "packed_int_op_type.int256_logical",
"EventCode": "0x0d",
"BriefDescription": "Retired 256-bit packed integer logical ops.",
diff --git a/tools/perf/tests/shell/stat.sh b/tools/perf/tests/shell/stat.sh
index 1e17bee026bd..649de1166fed 100755
--- a/tools/perf/tests/shell/stat.sh
+++ b/tools/perf/tests/shell/stat.sh
@@ -535,6 +535,17 @@ test_stat_delay() {
echo "stat -D test [Success]"
}
+test_csv_json_fail() {
+ echo "stat -x <sep> -j test"
+ if perf stat -x , -j true > /dev/null 2>&1
+ then
+ echo "stat -x <sep> -j test [Failed - command should have errored]"
+ err=1
+ else
+ echo "stat -x <sep> -j test [Success]"
+ fi
+}
+
test_default_stat
test_null_stat
test_offline_cpu_stat
@@ -551,6 +562,7 @@ test_stat_detailed
test_stat_repeat
test_stat_pid
test_stat_delay
+test_csv_json_fail
cleanup
exit $err
diff --git a/tools/perf/util/data-convert-json.c b/tools/perf/util/data-convert-json.c
index 40412c3dbdb2..40888b7c4467 100644
--- a/tools/perf/util/data-convert-json.c
+++ b/tools/perf/util/data-convert-json.c
@@ -258,6 +258,7 @@ static int process_sample_event(const struct perf_tool *tool,
trace_seq_init(&s);
tep_print_field(&s, sample->raw_data, fields[i]);
output_json_key_string(out, true, 3, fields[i]->name, s.buffer);
+ trace_seq_destroy(&s);
i++;
}
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index 2916b954a804..55c4aaa53c38 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -9,6 +9,7 @@
#include <stdbool.h>
#include <stdio.h>
#include <linux/bitops.h>
+#include <string.h>
#include "build-id.h"
#include "debuginfo.h"
#include "mutex.h"
@@ -20,6 +21,40 @@ struct perf_env;
#define DSO__NAME_KALLSYMS "[kernel.kallsyms]"
#define DSO__NAME_KCORE "[kernel.kcore]"
+#define DSO__NAME_GUEST_KALLSYMS "[guest.kernel.kallsyms]"
+#define DSO__NAME_GUEST_KALLSYMS_PID_PREFIX "[guest.kernel.kallsyms."
+
+/*
+ * Validate names of the form "[guest.kernel.kallsyms.<pid>]", where
+ * <pid> is the PID of the guest VM and varies per guest, so it
+ * cannot be matched with strcmp() against a fixed string.
+ *
+ * Every character after the fixed prefix must be a decimal digit,
+ * with ']' immediately terminating the digit run and nothing
+ * following it. This rules out '/', "..", or any other character
+ * being smuggled into the name.
+ */
+static inline bool is_guest_kallsyms_pid_name(const char *name)
+{
+ const size_t prefix_len = sizeof(DSO__NAME_GUEST_KALLSYMS_PID_PREFIX) - 1;
+ size_t digits;
+
+ if (strncmp(name, DSO__NAME_GUEST_KALLSYMS_PID_PREFIX, prefix_len) != 0)
+ return false;
+
+ digits = strspn(name + prefix_len, "0123456789");
+ if (digits == 0)
+ return false;
+
+ /* ']' must terminate the digit run, with nothing trailing it */
+ if (name[prefix_len + digits] != ']')
+ return false;
+
+ if (name[prefix_len + digits + 1] != '\0')
+ return false;
+
+ return true;
+}
/**
* enum dso_binary_type - The kind of DSO generally associated with a memory
@@ -924,8 +959,28 @@ static inline bool dso__is_kcore(const struct dso *dso)
static inline bool dso__is_kallsyms(const struct dso *dso)
{
enum dso_binary_type bt = dso__binary_type(dso);
+ const char *name;
+
+ if (bt == DSO_BINARY_TYPE__KALLSYMS || bt == DSO_BINARY_TYPE__GUEST_KALLSYMS)
+ return true;
+
+ if (bt != DSO_BINARY_TYPE__NOT_FOUND)
+ return false;
+
+ if (!dso__kernel(dso))
+ return false;
+
+ name = dso__long_name(dso);
+ if (!name)
+ return false;
+
+ if (!strcmp(name, DSO__NAME_KALLSYMS))
+ return true;
+
+ if (!strcmp(name, DSO__NAME_GUEST_KALLSYMS))
+ return true;
- return bt == DSO_BINARY_TYPE__KALLSYMS || bt == DSO_BINARY_TYPE__GUEST_KALLSYMS;
+ return is_guest_kallsyms_pid_name(name);
}
bool dso__is_object_file(const struct dso *dso);
diff --git a/tools/perf/util/sideband_evlist.c b/tools/perf/util/sideband_evlist.c
index c07dacf3c54c..ba043db6cedc 100644
--- a/tools/perf/util/sideband_evlist.c
+++ b/tools/perf/util/sideband_evlist.c
@@ -8,6 +8,7 @@
#include <perf/mmap.h>
#include <linux/perf_event.h>
#include <limits.h>
+#include <poll.h>
#include <pthread.h>
#include <sched.h>
#include <stdbool.h>
@@ -55,6 +56,19 @@ static void *perf_evlist__poll_thread(void *arg)
if (!draining)
evlist__poll(evlist, 1000);
+ /*
+ * When a thread of the monitored target exits, its per-cpu
+ * ring-buffer fd is closed and starts returning POLLHUP. Such
+ * dead fds are never requested for POLLIN, but poll() reports
+ * POLLHUP/POLLERR unconditionally, so leaving them in the
+ * pollfd array makes the following evlist__poll() return
+ * immediately forever, spinning this thread at 100% CPU.
+ *
+ * Filter them out here, mirroring what the 'perf record' main
+ * loop does after fdarray__poll().
+ */
+ evlist__filter_pollfd(evlist, POLLERR | POLLHUP);
+
for (i = 0; i < evlist__core(evlist)->nr_mmaps; i++) {
struct mmap *map = &evlist__mmap(evlist)[i];
union perf_event *event;
diff --git a/tools/sched_ext/include/scx/cid.bpf.h b/tools/sched_ext/include/scx/cid.bpf.h
index db247e42fb45..6b0b4e41b288 100644
--- a/tools/sched_ext/include/scx/cid.bpf.h
+++ b/tools/sched_ext/include/scx/cid.bpf.h
@@ -391,7 +391,9 @@ static __always_inline bool cmask_equal(const struct scx_cmask __arena *a,
if (a->base != b->base || a->nr_cids != b->nr_cids)
return false;
- nr_words = CMASK_NR_WORDS(a->nr_cids);
+ if (a->nr_cids == 0)
+ return true;
+ nr_words = (a->base + a->nr_cids - 1) / 64 - a->base / 64 + 1;
bpf_for(i, 0, CMASK_MAX_WORDS) {
if (i >= nr_words)
@@ -402,36 +404,6 @@ static __always_inline bool cmask_equal(const struct scx_cmask __arena *a,
return true;
}
-/*
- * True iff every bit set in @a is also set in @b over the intersection of
- * their ranges. Bits of @a outside @b's range fail the test.
- */
-static __always_inline bool cmask_subset(const struct scx_cmask __arena *a,
- const struct scx_cmask __arena *b)
-{
- u32 a_end = a->base + a->nr_cids;
- u32 b_end = b->base + b->nr_cids;
- u32 a_wbase = a->base / 64;
- u32 b_wbase = b->base / 64;
- u32 nr_words, i;
-
- /* any bit of @a outside @b's range is a subset violation */
- if (a->base < b->base || a_end > b_end)
- return false;
-
- nr_words = CMASK_NR_WORDS(a->nr_cids);
- bpf_for(i, 0, CMASK_MAX_WORDS) {
- u32 wi_b;
-
- if (i >= nr_words)
- break;
- wi_b = a_wbase + i - b_wbase;
- if (a->bits[i] & ~b->bits[wi_b])
- return false;
- }
- return true;
-}
-
/**
* cmask_next_set - find the first set bit at or after @cid
* @m: cmask to search
@@ -489,15 +461,65 @@ static __always_inline u32 cmask_first_set(const struct scx_cmask __arena *m)
(cid) = cmask_next_set((m), (cid) + 1))
/*
+ * True iff every bit set in @a is also set in @b. Matches the kernel-side
+ * scx_cmask_subset(): ranges don't need to nest, and set bits of @a outside
+ * @b's range fail the test.
+ */
+static __always_inline bool cmask_subset(const struct scx_cmask __arena *a,
+ const struct scx_cmask __arena *b)
+{
+ u32 a_end = a->base + a->nr_cids;
+ u32 b_end = b->base + b->nr_cids;
+ u32 a_wbase = a->base / 64;
+ u32 b_wbase = b->base / 64;
+ u32 lo = a->base > b->base ? a->base : b->base;
+ u32 hi = a_end < b_end ? a_end : b_end;
+ u32 lo_word, hi_word, i;
+
+ /* set bits of @a outside @b's range can't be in @b */
+ if (a->base < b->base &&
+ cmask_next_set(a, a->base) < (b->base < a_end ? b->base : a_end))
+ return false;
+ if (a_end > b_end &&
+ cmask_next_set(a, a->base > b_end ? a->base : b_end) < a_end)
+ return false;
+
+ if (lo >= hi)
+ return true;
+
+ /*
+ * Walk the words the range intersection spans. Plain word tests
+ * suffice: the scans above guarantee @a has no set bit outside @b's
+ * range and padding bits are kept clear by all cmask helpers.
+ */
+ lo_word = lo / 64;
+ hi_word = (hi - 1) / 64;
+
+ bpf_for(i, 0, CMASK_MAX_WORDS) {
+ u32 w = lo_word + i;
+
+ if (w > hi_word)
+ break;
+ if (a->bits[w - a_wbase] & ~b->bits[w - b_wbase])
+ return false;
+ }
+ return true;
+}
+
+/*
* Population count over [base, base + nr_cids). Padding bits in the head/tail
* words are guaranteed zero by the mutating helpers, so a flat popcount over
- * all words is correct.
+ * the words the range spans is correct.
*/
static __always_inline u32 cmask_weight(const struct scx_cmask __arena *m)
{
- u32 nr_words = CMASK_NR_WORDS(m->nr_cids), i;
+ u32 nr_words, i;
u32 count = 0;
+ if (!m->nr_cids)
+ return 0;
+ nr_words = (m->base + m->nr_cids - 1) / 64 - m->base / 64 + 1;
+
bpf_for(i, 0, CMASK_MAX_WORDS) {
if (i >= nr_words)
break;
diff --git a/tools/sched_ext/include/scx/common.bpf.h b/tools/sched_ext/include/scx/common.bpf.h
index bd51986c4c42..e7b3ba491c5e 100644
--- a/tools/sched_ext/include/scx/common.bpf.h
+++ b/tools/sched_ext/include/scx/common.bpf.h
@@ -104,7 +104,7 @@ void scx_bpf_events(struct scx_event_stats *events, size_t events__sz) __ksym __
s32 scx_bpf_cpu_to_cid(s32 cpu) __ksym __weak;
s32 scx_bpf_cid_to_cpu(s32 cid) __ksym __weak;
void scx_bpf_cid_topo(s32 cid, struct scx_cid_topo *out) __ksym __weak;
-s32 scx_bpf_kick_cid(s32 cid, u64 flags) __ksym __weak;
+void scx_bpf_kick_cid(s32 cid, u64 flags) __ksym __weak;
s32 scx_bpf_task_cid(const struct task_struct *p) __ksym __weak;
s32 scx_bpf_this_cid(void) __ksym __weak;
struct task_struct *scx_bpf_cid_curr(s32 cid) __ksym __weak;
diff --git a/tools/sched_ext/scx_qmap.c b/tools/sched_ext/scx_qmap.c
index 67ddd483a4c7..f1eaebcab5dc 100644
--- a/tools/sched_ext/scx_qmap.c
+++ b/tools/sched_ext/scx_qmap.c
@@ -67,8 +67,8 @@ int main(int argc, char **argv)
struct scx_qmap *skel;
struct bpf_link *link;
struct qmap_arena *qa;
- __u32 test_error_cnt = 0;
- __u64 ecode;
+ u32 test_error_cnt = 0;
+ u64 ecode;
int opt;
libbpf_set_print(libbpf_print_fn);
@@ -202,15 +202,16 @@ restart:
printf("stats : enq=%lu dsp=%lu delta=%ld reenq/cid0=%llu/%llu deq=%llu core=%llu enq_ddsp=%llu\n",
nr_enqueued, nr_dispatched, nr_enqueued - nr_dispatched,
- qa->nr_reenqueued, qa->nr_reenqueued_cid0,
- qa->nr_dequeued,
- qa->nr_core_sched_execed,
- qa->nr_ddsp_from_enq);
+ (unsigned long long)qa->nr_reenqueued,
+ (unsigned long long)qa->nr_reenqueued_cid0,
+ (unsigned long long)qa->nr_dequeued,
+ (unsigned long long)qa->nr_core_sched_execed,
+ (unsigned long long)qa->nr_ddsp_from_enq);
printf(" exp_local=%llu exp_remote=%llu exp_timer=%llu exp_lost=%llu\n",
- qa->nr_expedited_local,
- qa->nr_expedited_remote,
- qa->nr_expedited_from_timer,
- qa->nr_expedited_lost);
+ (unsigned long long)qa->nr_expedited_local,
+ (unsigned long long)qa->nr_expedited_remote,
+ (unsigned long long)qa->nr_expedited_from_timer,
+ (unsigned long long)qa->nr_expedited_lost);
if (__COMPAT_has_ksym("scx_bpf_cidperf_cur"))
printf("cpuperf: cur min/avg/max=%u/%u/%u target min/avg/max=%u/%u/%u\n",
qa->cpuperf_min,
diff --git a/tools/sched_ext/scx_qmap.h b/tools/sched_ext/scx_qmap.h
index d15a705d5ac5..808237540f5c 100644
--- a/tools/sched_ext/scx_qmap.h
+++ b/tools/sched_ext/scx_qmap.h
@@ -28,10 +28,10 @@
#define SCX_QMAP_MAX_CPUS 1024
struct cpu_ctx {
- __u64 dsp_idx; /* dispatch index */
- __u64 dsp_cnt; /* remaining count */
- __u32 avg_weight;
- __u32 cpuperf_target;
+ u64 dsp_idx; /* dispatch index */
+ u64 dsp_cnt; /* remaining count */
+ u32 avg_weight;
+ u32 cpuperf_target;
};
/* Opaque to userspace; defined in scx_qmap.bpf.c. */
@@ -40,25 +40,25 @@ struct task_ctx;
struct qmap_fifo {
struct task_ctx __arena *head;
struct task_ctx __arena *tail;
- __s32 idx;
+ s32 idx;
};
struct qmap_arena {
/* userspace-visible stats */
- __u64 nr_enqueued, nr_dispatched, nr_reenqueued, nr_reenqueued_cid0;
- __u64 nr_dequeued, nr_ddsp_from_enq;
- __u64 nr_core_sched_execed;
- __u64 nr_expedited_local, nr_expedited_remote;
- __u64 nr_expedited_lost, nr_expedited_from_timer;
- __u64 nr_highpri_queued;
- __u32 test_error_cnt;
- __u32 cpuperf_min, cpuperf_avg, cpuperf_max;
- __u32 cpuperf_target_min, cpuperf_target_avg, cpuperf_target_max;
+ u64 nr_enqueued, nr_dispatched, nr_reenqueued, nr_reenqueued_cid0;
+ u64 nr_dequeued, nr_ddsp_from_enq;
+ u64 nr_core_sched_execed;
+ u64 nr_expedited_local, nr_expedited_remote;
+ u64 nr_expedited_lost, nr_expedited_from_timer;
+ u64 nr_highpri_queued;
+ u32 test_error_cnt;
+ u32 cpuperf_min, cpuperf_avg, cpuperf_max;
+ u32 cpuperf_target_min, cpuperf_target_avg, cpuperf_target_max;
/* kernel-side runtime state */
- __u64 sub_sched_cgroup_ids[MAX_SUB_SCHEDS];
- __u64 core_sched_head_seqs[5];
- __u64 core_sched_tail_seqs[5];
+ u64 sub_sched_cgroup_ids[MAX_SUB_SCHEDS];
+ u64 core_sched_head_seqs[5];
+ u64 core_sched_tail_seqs[5];
struct cpu_ctx cpu_ctxs[SCX_QMAP_MAX_CPUS];
diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c b/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c
index fe30181e6336..eb05fc82f81b 100644
--- a/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c
+++ b/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c
@@ -14,6 +14,7 @@
#include "tcp_ca_incompl_cong_ops.skel.h"
#include "tcp_ca_unsupp_cong_op.skel.h"
#include "tcp_ca_kfunc.skel.h"
+#include "tcp_ca_untrusted_btf_write.skel.h"
#include "bpf_cc_cubic.skel.h"
static const unsigned int total_bytes = 10 * 1024 * 1024;
@@ -579,6 +580,15 @@ static void test_tcp_ca_kfunc(void)
tcp_ca_kfunc__destroy(skel);
}
+static void test_untrusted_btf_write(void)
+{
+ struct tcp_ca_untrusted_btf_write *skel;
+
+ skel = tcp_ca_untrusted_btf_write__open_and_load();
+ ASSERT_ERR_PTR(skel, "tcp_ca_untrusted_btf_write__open_and_load");
+ tcp_ca_untrusted_btf_write__destroy(skel);
+}
+
static void test_cc_cubic(void)
{
struct cb_opts cb_opts = {
@@ -637,6 +647,8 @@ void test_bpf_tcp_ca(void)
test_link_replace();
if (test__start_subtest("tcp_ca_kfunc"))
test_tcp_ca_kfunc();
+ if (test__start_subtest("untrusted_btf_write"))
+ test_untrusted_btf_write();
if (test__start_subtest("cc_cubic"))
test_cc_cubic();
if (test__start_subtest("dctcp_autoattach_map"))
diff --git a/tools/testing/selftests/bpf/prog_tests/icmp_send_kfunc.c b/tools/testing/selftests/bpf/prog_tests/icmp_send_kfunc.c
new file mode 100644
index 000000000000..9318d4bc7ce8
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/icmp_send_kfunc.c
@@ -0,0 +1,292 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <test_progs.h>
+#include <network_helpers.h>
+#include <cgroup_helpers.h>
+#include <linux/errqueue.h>
+#include <poll.h>
+#include <unistd.h>
+#include "icmp_send.skel.h"
+
+#define TIMEOUT_MS 1000
+
+#define ICMP_DEST_UNREACH 3
+#define ICMPV6_DEST_UNREACH 1
+
+#define ICMP_HOST_UNREACH 1
+#define ICMP_FRAG_NEEDED 4
+#define NR_ICMP_UNREACH 15
+#define ICMPV6_REJECT_ROUTE 6
+
+#define KFUNC_RET_UNSET -1
+
+static int connect_to_fd_nonblock(int server_fd)
+{
+ struct sockaddr_storage addr;
+ socklen_t len = sizeof(addr);
+ int fd, err, on = 1;
+
+ if (getsockname(server_fd, (struct sockaddr *)&addr, &len))
+ return -1;
+
+ fd = socket(addr.ss_family, SOCK_STREAM | SOCK_NONBLOCK, 0);
+ if (fd < 0)
+ return -1;
+
+ if (addr.ss_family == AF_INET6 &&
+ setsockopt(fd, IPPROTO_IPV6, IPV6_RECVERR, &on, sizeof(on)) < 0) {
+ close(fd);
+ return -1;
+ }
+
+ err = connect(fd, (struct sockaddr *)&addr, len);
+ if (err < 0 && errno != EINPROGRESS) {
+ close(fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+static void read_icmp_errqueue(int sockfd, int expected_code, int af)
+{
+ int expected_ee_type = (af == AF_INET) ? ICMP_DEST_UNREACH :
+ ICMPV6_DEST_UNREACH;
+ int expected_origin = (af == AF_INET) ? SO_EE_ORIGIN_ICMP :
+ SO_EE_ORIGIN_ICMP6;
+ int expected_level = (af == AF_INET) ? IPPROTO_IP : IPPROTO_IPV6;
+ int expected_type = (af == AF_INET) ? IP_RECVERR : IPV6_RECVERR;
+ struct sock_extended_err *sock_err;
+ char ctrl_buf[512];
+ struct msghdr msg = {
+ .msg_control = ctrl_buf,
+ .msg_controllen = sizeof(ctrl_buf),
+ };
+ struct pollfd pfd = {
+ .fd = sockfd,
+ .events = POLLERR,
+ };
+ struct cmsghdr *cm;
+ ssize_t n;
+
+ if (!ASSERT_GE(poll(&pfd, 1, TIMEOUT_MS), 1, "poll_errqueue"))
+ return;
+
+ n = recvmsg(sockfd, &msg, MSG_ERRQUEUE);
+ if (!ASSERT_GE(n, 0, "recvmsg_errqueue"))
+ return;
+
+ cm = CMSG_FIRSTHDR(&msg);
+ if (!ASSERT_NEQ(cm, NULL, "cm_firsthdr_null"))
+ return;
+
+ for (; cm; cm = CMSG_NXTHDR(&msg, cm)) {
+ if (cm->cmsg_level != expected_level ||
+ cm->cmsg_type != expected_type)
+ continue;
+
+ sock_err = (struct sock_extended_err *)CMSG_DATA(cm);
+
+ if (!ASSERT_EQ(sock_err->ee_origin, expected_origin,
+ "sock_err_origin"))
+ return;
+ if (!ASSERT_EQ(sock_err->ee_type, expected_ee_type,
+ "sock_err_type_dest_unreach"))
+ return;
+ ASSERT_EQ(sock_err->ee_code, expected_code, "sock_err_code");
+ return;
+ }
+
+ ASSERT_FAIL("no IP_RECVERR/IPV6_RECVERR control message found");
+}
+
+static bool valid_unreach_code(int code, int af)
+{
+ if (code < 0)
+ return false;
+
+ if (af == AF_INET)
+ return code <= NR_ICMP_UNREACH && code != ICMP_FRAG_NEEDED;
+
+ return code <= ICMPV6_REJECT_ROUTE;
+}
+
+static void trigger_prog_read_icmp_errqueue(struct icmp_send *skel, int code,
+ int af, const char *ip)
+{
+ int srv_fd = -1, client_fd = -1;
+ int port;
+
+ srv_fd = start_server(af, SOCK_STREAM, ip, 0, TIMEOUT_MS);
+ if (!ASSERT_OK_FD(srv_fd, "start_server"))
+ return;
+
+ port = get_socket_local_port(srv_fd);
+ if (!ASSERT_GE(port, 0, "get_socket_local_port")) {
+ close(srv_fd);
+ return;
+ }
+
+ skel->bss->server_port = ntohs(port);
+ skel->bss->unreach_type = (af == AF_INET) ? ICMP_DEST_UNREACH :
+ ICMPV6_DEST_UNREACH;
+ skel->bss->unreach_code = code;
+ skel->data->kfunc_ret = KFUNC_RET_UNSET;
+
+ client_fd = connect_to_fd_nonblock(srv_fd);
+ if (!ASSERT_OK_FD(client_fd, "client_connect_nonblock")) {
+ close(srv_fd);
+ return;
+ }
+
+ if (valid_unreach_code(code, af))
+ read_icmp_errqueue(client_fd, code, af);
+
+ close(client_fd);
+ close(srv_fd);
+}
+
+static void run_icmp_test(struct icmp_send *skel, int af, const char *ip,
+ int max_code)
+{
+ for (int code = 0; code <= max_code; code++) {
+ if (af == AF_INET && code == ICMP_FRAG_NEEDED)
+ continue;
+
+ trigger_prog_read_icmp_errqueue(skel, code, af, ip);
+ ASSERT_EQ(skel->data->kfunc_ret, 0, "kfunc_ret");
+ }
+
+ /* Test invalid codes */
+ trigger_prog_read_icmp_errqueue(skel, -1, af, ip);
+ ASSERT_EQ(skel->data->kfunc_ret, -EINVAL, "kfunc_ret");
+
+ trigger_prog_read_icmp_errqueue(skel, max_code + 1, af, ip);
+ ASSERT_EQ(skel->data->kfunc_ret, -EINVAL, "kfunc_ret");
+
+ if (af == AF_INET) {
+ trigger_prog_read_icmp_errqueue(skel, ICMP_FRAG_NEEDED, af, ip);
+ ASSERT_EQ(skel->data->kfunc_ret, -EINVAL, "kfunc_ret");
+ }
+}
+
+static void run_icmp_no_route_test(struct icmp_send *skel, int af)
+{
+ union {
+ struct ipv4_packet v4;
+ struct ipv6_packet v6;
+ } pkt;
+ DECLARE_LIBBPF_OPTS(bpf_test_run_opts, opts,
+ .data_in = &pkt,
+ );
+ int err;
+
+ switch (af) {
+ case AF_INET:
+ pkt.v4 = pkt_v4;
+ pkt.v4.iph.version = 4;
+ pkt.v4.iph.daddr = htonl(INADDR_LOOPBACK);
+ pkt.v4.tcp.dest = htons(80);
+ opts.data_size_in = sizeof(pkt.v4);
+ skel->bss->unreach_type = ICMP_DEST_UNREACH;
+ break;
+ case AF_INET6:
+ pkt.v6 = pkt_v6;
+ pkt.v6.iph.version = 6;
+ pkt.v6.iph.daddr = in6addr_loopback;
+ pkt.v6.tcp.dest = htons(80);
+ opts.data_size_in = sizeof(pkt.v6);
+ skel->bss->unreach_type = ICMPV6_DEST_UNREACH;
+ break;
+ default:
+ ASSERT_FAIL("af_not_supported");
+ return;
+ }
+
+ skel->bss->server_port = 80;
+ skel->data->kfunc_ret = KFUNC_RET_UNSET;
+
+ err = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.egress), &opts);
+ if (!ASSERT_OK(err, "test_run"))
+ return;
+
+ ASSERT_EQ(skel->data->kfunc_ret, -ENETUNREACH, "kfunc_ret_no_route");
+}
+
+void test_icmp_send_unreach_cgroup(void)
+{
+ struct icmp_send *skel;
+ int cgroup_fd = -1;
+
+ skel = icmp_send__open_and_load();
+ if (!ASSERT_OK_PTR(skel, "skel_open"))
+ goto cleanup;
+
+ cgroup_fd = test__join_cgroup("/icmp_send_unreach_cgroup");
+ if (!ASSERT_OK_FD(cgroup_fd, "join_cgroup"))
+ goto cleanup;
+
+ skel->links.egress =
+ bpf_program__attach_cgroup(skel->progs.egress, cgroup_fd);
+ if (!ASSERT_OK_PTR(skel->links.egress, "prog_attach_cgroup"))
+ goto cleanup;
+
+ if (test__start_subtest("ipv4"))
+ run_icmp_test(skel, AF_INET, "127.0.0.1", NR_ICMP_UNREACH);
+
+ if (test__start_subtest("ipv6"))
+ run_icmp_test(skel, AF_INET6, "::1", ICMPV6_REJECT_ROUTE);
+
+ if (test__start_subtest("no_route_ipv4"))
+ run_icmp_no_route_test(skel, AF_INET);
+
+ if (test__start_subtest("no_route_ipv6"))
+ run_icmp_no_route_test(skel, AF_INET6);
+
+cleanup:
+ icmp_send__destroy(skel);
+ if (cgroup_fd >= 0)
+ close(cgroup_fd);
+}
+
+void test_icmp_send_unreach_recursion(void)
+{
+ struct icmp_send *skel;
+ int cgroup_fd = -1;
+ int err;
+
+ err = setup_cgroup_environment();
+ if (!ASSERT_OK(err, "setup_cgroup_environment"))
+ return;
+
+ skel = icmp_send__open_and_load();
+ if (!ASSERT_OK_PTR(skel, "skel_open"))
+ goto cleanup;
+
+ cgroup_fd = get_root_cgroup();
+ if (!ASSERT_OK_FD(cgroup_fd, "get_root_cgroup"))
+ goto cleanup;
+
+ skel->data->target_pid = getpid();
+ skel->links.recursion =
+ bpf_program__attach_cgroup(skel->progs.recursion, cgroup_fd);
+ if (!ASSERT_OK_PTR(skel->links.recursion, "prog_attach_cgroup"))
+ goto cleanup;
+
+ trigger_prog_read_icmp_errqueue(skel, ICMP_HOST_UNREACH, AF_INET,
+ "127.0.0.1");
+
+ /*
+ * Because there's recursion involved, the first call will return at
+ * index 1 since it will return the second, and the second call will
+ * return at index 0 since it will return the first.
+ */
+ ASSERT_EQ(skel->bss->rec_count, 2, "rec_count");
+ ASSERT_EQ(skel->data->rec_kfunc_rets[0], -EBUSY, "kfunc_rets[0]");
+ ASSERT_EQ(skel->data->rec_kfunc_rets[1], 0, "kfunc_rets[1]");
+
+cleanup:
+ icmp_send__destroy(skel);
+ if (cgroup_fd >= 0)
+ close(cgroup_fd);
+ cleanup_cgroup_environment();
+}
diff --git a/tools/testing/selftests/bpf/prog_tests/kfunc_call.c b/tools/testing/selftests/bpf/prog_tests/kfunc_call.c
index 3df07680f9e0..67a30bf69509 100644
--- a/tools/testing/selftests/bpf/prog_tests/kfunc_call.c
+++ b/tools/testing/selftests/bpf/prog_tests/kfunc_call.c
@@ -66,6 +66,7 @@ static struct kfunc_test_params kfunc_tests[] = {
TC_FAIL(kfunc_call_test_get_mem_fail_rdonly, 0, "R0 cannot write into rdonly_mem"),
TC_FAIL(kfunc_call_test_get_mem_fail_use_after_free, 0, "invalid mem access 'scalar'"),
TC_FAIL(kfunc_call_test_get_mem_fail_oob, 0, "min value is outside of the allowed memory range"),
+ TC_FAIL(kfunc_call_test_get_mem_fail_oversized, 0, "rdonly/rdwr_buf_size exceeds u32 max"),
TC_FAIL(kfunc_call_test_get_mem_fail_not_const, 0, "is not a const"),
TC_FAIL(kfunc_call_test_mem_acquire_fail, 0, "acquire kernel function does not return PTR_TO_BTF_ID"),
TC_FAIL(kfunc_call_test_pointer_arg_type_mismatch, 0, "R1 expected pointer to ctx, but got scalar"),
diff --git a/tools/testing/selftests/bpf/prog_tests/res_spin_lock.c b/tools/testing/selftests/bpf/prog_tests/res_spin_lock.c
index f0a8c828f8f1..7541f4966abc 100644
--- a/tools/testing/selftests/bpf/prog_tests/res_spin_lock.c
+++ b/tools/testing/selftests/bpf/prog_tests/res_spin_lock.c
@@ -3,6 +3,8 @@
#include <test_progs.h>
#include <network_helpers.h>
#include <sys/sysinfo.h>
+#include <sys/syscall.h>
+#include <linux/perf_event.h>
#include "res_spin_lock.skel.h"
#include "res_spin_lock_fail.skel.h"
@@ -102,11 +104,29 @@ end:
void serial_test_res_spin_lock_stress(void)
{
+ struct perf_event_attr attr = {
+ .size = sizeof(attr),
+ .type = PERF_TYPE_HARDWARE,
+ .config = PERF_COUNT_HW_CPU_CYCLES,
+ };
+ int pmu_fd;
+
if (libbpf_num_possible_cpus() < 3) {
test__skip();
return;
}
+ pmu_fd = syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0);
+ if (pmu_fd < 0) {
+ if (errno == ENOENT || errno == EOPNOTSUPP) {
+ test__skip();
+ return;
+ }
+ ASSERT_OK(-errno, "perf_event_open pmu probe");
+ return;
+ }
+ close(pmu_fd);
+
ASSERT_OK(load_module("bpf_test_rqspinlock.ko", false), "load module AA");
sleep(5);
unload_module("bpf_test_rqspinlock", false);
diff --git a/tools/testing/selftests/bpf/prog_tests/signed_loader.c b/tools/testing/selftests/bpf/prog_tests/signed_loader.c
index 5fc417e31fc6..77381d345435 100644
--- a/tools/testing/selftests/bpf/prog_tests/signed_loader.c
+++ b/tools/testing/selftests/bpf/prog_tests/signed_loader.c
@@ -11,6 +11,8 @@
#include <linux/keyctl.h>
#include <linux/bpf.h>
+#include <bpf/btf.h>
+
#include "bpf/libbpf_internal.h" /* for libbpf_sha256() */
#include "bpf/skel_internal.h" /* for loader ctx layout (bpf_loader_ctx etc) */
@@ -19,8 +21,6 @@
#include "test_signed_loader_data.skel.h"
#include "test_signed_loader_lsm.skel.h"
-#define SIG_MATCH_INSNS 33 /* excl (5) + 4 * sha-dword (7) */
-
enum {
BPF_SIG_UNSIGNED = 0,
BPF_SIG_VERIFIED,
@@ -35,7 +35,8 @@ enum {
};
static int load_loader(const void *insns, __u32 insns_sz, int map_fd,
- const void *sig, __u32 sig_sz, __s32 keyring_id)
+ const void *sig, __u32 sig_sz, __s32 keyring_id,
+ __u32 fd_array_cnt)
{
union bpf_attr attr;
int fd;
@@ -52,6 +53,7 @@ static int load_loader(const void *insns, __u32 insns_sz, int map_fd,
attr.signature_size = sig_sz;
attr.keyring_id = keyring_id;
}
+ attr.fd_array_cnt = fd_array_cnt;
memcpy(attr.prog_name, "__loader.prog", sizeof("__loader.prog"));
fd = syscall(__NR_bpf, BPF_PROG_LOAD, &attr,
offsetofend(union bpf_attr, keyring_id));
@@ -62,14 +64,12 @@ static int run_gen_loader(const void *insns, __u32 insns_sz,
const void *data, __u32 data_sz,
const void *excl, __u32 excl_sz,
const void *sig, __u32 sig_sz,
- bool get_hash, void *ctx, __u32 ctx_sz, bool *loader_ran)
+ void *ctx, __u32 ctx_sz, bool *loader_ran)
{
LIBBPF_OPTS(bpf_map_create_opts, mopts,
.excl_prog_hash = excl,
.excl_prog_hash_size = excl_sz);
- __u8 hbuf[SHA256_DIGEST_LENGTH];
- struct bpf_map_info info;
- __u32 ilen = sizeof(info), key = 0;
+ __u32 key = 0;
union bpf_attr attr;
int map_fd, prog_fd, ret;
@@ -87,15 +87,6 @@ static int run_gen_loader(const void *insns, __u32 insns_sz,
ret = -errno;
goto out_map;
}
- if (get_hash) {
- memset(&info, 0, sizeof(info));
- info.hash = ptr_to_u64(hbuf);
- info.hash_size = sizeof(hbuf);
- if (bpf_map_get_info_by_fd(map_fd, &info, &ilen)) {
- ret = -errno;
- goto out_map;
- }
- }
memset(&attr, 0, sizeof(attr));
attr.prog_type = BPF_PROG_TYPE_SYSCALL;
@@ -108,6 +99,7 @@ static int run_gen_loader(const void *insns, __u32 insns_sz,
attr.signature = ptr_to_u64(sig);
attr.signature_size = sig_sz;
attr.keyring_id = KEY_SPEC_SESSION_KEYRING;
+ attr.fd_array_cnt = 1;
}
memcpy(attr.prog_name, "__loader.prog", sizeof("__loader.prog"));
prog_fd = syscall(__NR_bpf, BPF_PROG_LOAD, &attr,
@@ -236,79 +228,6 @@ out:
return ret;
}
-static void check_sig_match_shape(const struct bpf_insn *in, int n)
-{
- int a = -1, cleanup = -1, i, base, t, br[5], nb = 0;
-
- /* BPF_PSEUDO_MAP_IDX (the struct bpf_map * form) is used only here. */
- for (i = 0; i + 1 < n; i++) {
- if (in[i].code == (BPF_LD | BPF_IMM | BPF_DW) &&
- in[i].src_reg == BPF_PSEUDO_MAP_IDX) {
- a = i;
- break;
- }
- }
- if (!ASSERT_GE(a, 0, "emit_signature_match present"))
- return;
- if (!ASSERT_LE(a + SIG_MATCH_INSNS, n, "block fits in program"))
- return;
-
- /* excl check: r2 = *(u32 *)(map + 32); if r2 != 1 goto cleanup */
- ASSERT_EQ(in[a + 2].code, (BPF_LDX | BPF_MEM | BPF_W), "excl load width");
- ASSERT_EQ(in[a + 2].off, SHA256_DIGEST_LENGTH, "excl field offset");
- ASSERT_EQ(in[a + 4].code, (BPF_JMP | BPF_JNE | BPF_K), "excl branch op");
- ASSERT_EQ(in[a + 4].imm, 1, "excl compared to 1");
- br[nb++] = a + 4;
-
- /* 4 sha-dword checks: r2 = *(u64 *)(map + i*8); if r2 != r3 goto cleanup */
- for (i = 0; i < 4; i++) {
- base = a + 5 + i * 7;
- ASSERT_EQ(in[base + 2].code, (BPF_LDX | BPF_MEM | BPF_DW), "sha load width");
- ASSERT_EQ(in[base + 2].off, i * 8, "sha dword offset");
- ASSERT_EQ(in[base + 3].code, (BPF_LD | BPF_IMM | BPF_DW), "sha imm64 (H_meta)");
- ASSERT_EQ(in[base + 6].code, (BPF_JMP | BPF_JNE | BPF_X), "sha branch op");
- br[nb++] = base + 6;
- }
-
- /*
- * Locate the real cleanup label so we can pin the exact jump target,
- * not just "some backward label". bpf_gen__init() emits the cleanup
- * block as a prog-fd close loop whose first instruction is the label
- * every error branch jumps to.
- */
- for (i = 0; i + 2 < a; i++) {
- if (in[i].code == (BPF_LDX | BPF_MEM | BPF_W) &&
- in[i].dst_reg == BPF_REG_1 && in[i].src_reg == BPF_REG_10 &&
- in[i + 1].code == (BPF_JMP | BPF_JSLE | BPF_K) &&
- in[i + 1].dst_reg == BPF_REG_1 && in[i + 1].imm == 0 &&
- in[i + 1].off == 1 &&
- in[i + 2].code == (BPF_JMP | BPF_CALL) &&
- in[i + 2].imm == BPF_FUNC_sys_close) {
- cleanup = i;
- break;
- }
- }
- if (!ASSERT_GE(cleanup, 0, "cleanup label located"))
- return;
- for (i = 0; i < nb; i++) {
- t = br[i] + 1 + in[br[i]].off;
- ASSERT_EQ(t, cleanup, "sig-match lands on cleanup");
- }
- /*
- * Same invariant for every other cleanup-bound jump in the program:
- * emit_check_err() is the only source of "if (r7 < 0) goto cleanup",
- * so each of those must also resolve exactly to cleanup.
- */
- for (i = 0, t = 0; i < n; i++) {
- if (in[i].code != (BPF_JMP | BPF_JSLT | BPF_K) ||
- in[i].dst_reg != BPF_REG_7 || in[i].imm != 0 || in[i].off >= 0)
- continue;
- ASSERT_EQ(i + 1 + in[i].off, cleanup, "err-check lands on cleanup");
- t++;
- }
- ASSERT_GT(t, 0, "found emit_check_err jumps");
-}
-
struct gen_loader_fixture {
struct test_signed_loader *skel;
struct gen_loader_opts gopts;
@@ -372,16 +291,6 @@ static void gen_loader_fixture_fini(struct gen_loader_fixture *f)
test_signed_loader__destroy(f->skel);
}
-static void metadata_check_shape(void)
-{
- struct gen_loader_fixture f;
-
- if (gen_loader_fixture_init(&f) == 0)
- check_sig_match_shape((const struct bpf_insn *)f.gopts.insns,
- f.gopts.insns_sz / sizeof(struct bpf_insn));
- gen_loader_fixture_fini(&f);
-}
-
static void metadata_match(void)
{
struct gen_loader_fixture f;
@@ -391,94 +300,265 @@ static void metadata_match(void)
if (gen_loader_fixture_init(&f) == 0) {
r = run_gen_loader(f.gopts.insns, f.gopts.insns_sz, f.blob,
f.data_sz, f.excl, sizeof(f.excl), NULL, 0,
- true, f.ctx, f.ctx_sz, &ran);
+ f.ctx, f.ctx_sz, &ran);
ASSERT_TRUE(ran, "loader ran");
ASSERT_EQ(r, 0, "honest loader retval");
}
gen_loader_fixture_fini(&f);
}
-static void metadata_sha_mismatch(void)
+static void signature_enforced(void)
{
+ static const __u8 junk[64] = { 0x30, 0x42, 0x13, 0x37, };
struct gen_loader_fixture f;
- bool ran;
- int r;
+ int fd;
if (gen_loader_fixture_init(&f) == 0) {
/*
- * blob[0] lives in the loader's fd_array scratch (first add_data in
- * bpf_gen__init); a 0-map program never reads it, so flipping it
- * changes only map->sha. The metadata check is the only thing that
- * can notice -> isolates emit_signature_match.
+ * A present-but-invalid signature (the cert bytes are not a
+ * PKCS#7 signature) must be rejected at load: the signature
+ * path is honored, not ignored. (The valid path is covered by
+ * the signed lskels.) Pin -EBADMSG, the PKCS#7 parse failure:
+ * a looser fd < 0 check could also be satisfied by the sparse
+ * fd_array rejection (-EACCES) that the loader's map reference
+ * would trip even if the signature were silently ignored.
*/
- f.blob[0] ^= 0xff;
- r = run_gen_loader(f.gopts.insns, f.gopts.insns_sz, f.blob,
- f.data_sz, f.excl, sizeof(f.excl), NULL, 0,
- true, f.ctx, f.ctx_sz, &ran);
- ASSERT_TRUE(ran, "loader ran");
- ASSERT_EQ(r, -EINVAL, "tampered blob rejected by emit_signature_match");
+ fd = load_loader(f.gopts.insns, f.gopts.insns_sz, -1, junk,
+ sizeof(junk), KEY_SPEC_SESSION_KEYRING, 0);
+ ASSERT_EQ(fd, -EBADMSG, "invalid signature rejected at load");
+ if (fd >= 0)
+ close(fd);
}
gen_loader_fixture_fini(&f);
}
-static void metadata_not_exclusive(void)
+static void signed_nonexcl_fd_array_rejected(void)
{
+ static const __u8 junk[64] = { 0x30, 0x42, 0x13, 0x37, };
struct gen_loader_fixture f;
- bool ran;
- int r;
+ int map_fd, fd;
if (gen_loader_fixture_init(&f) == 0) {
/*
- * Correct blob but a non-exclusive metadata map: the verifier does
- * not reject (excl_prog_sha unset), so the runtime map->excl == 1
- * check in the loader must.
+ * A signed program may only bind exclusive maps through fd_array
+ * (their contents are folded into the signature). Binding a
+ * non-exclusive map is rejected, before the signature is even
+ * examined.
*/
- r = run_gen_loader(f.gopts.insns, f.gopts.insns_sz, f.blob,
- f.data_sz, NULL, 0, NULL, 0, true, f.ctx,
- f.ctx_sz, &ran);
- ASSERT_TRUE(ran, "loader ran");
- ASSERT_EQ(r, -EINVAL, "non-exclusive metadata map rejected");
+ map_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "nonexcl", 4,
+ f.data_sz, 1, NULL);
+ if (ASSERT_OK_FD(map_fd, "nonexcl_map")) {
+ if (ASSERT_OK(bpf_map_freeze(map_fd), "freeze")) {
+ fd = load_loader(f.gopts.insns, f.gopts.insns_sz,
+ map_fd, junk, sizeof(junk),
+ KEY_SPEC_SESSION_KEYRING, 1);
+ ASSERT_EQ(fd, -EPERM,
+ "non-exclusive map in signed fd_array rejected");
+ if (fd >= 0)
+ close(fd);
+ }
+ close(map_fd);
+ }
}
gen_loader_fixture_fini(&f);
}
-static void metadata_hash_not_computed(void)
+static void signed_unfrozen_fd_array_rejected(void)
{
+ static const __u8 junk[64] = { 0x30, 0x42, 0x13, 0x37, };
+ LIBBPF_OPTS(bpf_map_create_opts, mopts);
struct gen_loader_fixture f;
- bool ran;
- int r;
+ __u32 key = 0;
+ int map_fd, fd;
if (gen_loader_fixture_init(&f) == 0) {
/*
- * Correct, exclusive, frozen map, but its hash was never computed
- * (no OBJ_GET_INFO_BY_FD), so map->sha stays zero. The loader must
- * fail closed rather than treat an unset hash as a match.
+ * The metadata map must be frozen before a signed load so the
+ * folded bytes cannot change afterwards. Bind an exclusive map
+ * with matching contents but skip the freeze: the load must be
+ * rejected by the frozen check with -EPERM. The exclusivity
+ * check right after it would pass, so the errno uniquely pins
+ * the freeze requirement.
*/
- r = run_gen_loader(f.gopts.insns, f.gopts.insns_sz, f.blob,
- f.data_sz, f.excl, sizeof(f.excl), NULL, 0,
- false, f.ctx, f.ctx_sz, &ran);
- ASSERT_TRUE(ran, "loader ran");
- ASSERT_EQ(r, -EINVAL, "uncomputed metadata hash rejected");
+ mopts.excl_prog_hash = f.excl;
+ mopts.excl_prog_hash_size = sizeof(f.excl);
+ map_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "unfrozen", 4,
+ f.data_sz, 1, &mopts);
+ if (ASSERT_OK_FD(map_fd, "unfrozen_map")) {
+ if (ASSERT_OK(bpf_map_update_elem(map_fd, &key, f.blob, 0),
+ "update")) {
+ fd = load_loader(f.gopts.insns, f.gopts.insns_sz,
+ map_fd, junk, sizeof(junk),
+ KEY_SPEC_SESSION_KEYRING, 1);
+ ASSERT_EQ(fd, -EPERM,
+ "unfrozen map in signed fd_array rejected");
+ if (fd >= 0)
+ close(fd);
+ }
+ close(map_fd);
+ }
}
gen_loader_fixture_fini(&f);
}
-static void signature_enforced(void)
+static void signed_nonarray_fd_array_rejected(void)
+{
+ static const __u8 junk[64] = { 0x30, 0x42, 0x13, 0x37, };
+ LIBBPF_OPTS(bpf_map_create_opts, mopts);
+ struct gen_loader_fixture f;
+ int map_fd, fd;
+
+ if (gen_loader_fixture_init(&f) == 0) {
+ /*
+ * Only a plain BPF_MAP_TYPE_ARRAY may be folded into the
+ * signature. An exclusive map of any other type is rejected
+ * (-EINVAL) rather than folded - this is the type gate that
+ * keeps arena maps (map_direct_value_addr() returns a user
+ * address) and insn-array maps (buffer smaller than value_size)
+ * out of the hashed region, where the old code would have
+ * memcpy()'d from them. A hash map stands in here: it is
+ * exclusive (bound to the loader digest) but not an array.
+ */
+ mopts.excl_prog_hash = f.excl;
+ mopts.excl_prog_hash_size = sizeof(f.excl);
+ map_fd = bpf_map_create(BPF_MAP_TYPE_HASH, "excl_hash", 4, 4, 1,
+ &mopts);
+ if (ASSERT_OK_FD(map_fd, "excl_hash_map")) {
+ fd = load_loader(f.gopts.insns, f.gopts.insns_sz, map_fd,
+ junk, sizeof(junk),
+ KEY_SPEC_SESSION_KEYRING, 1);
+ ASSERT_EQ(fd, -EINVAL,
+ "non-array map in signed fd_array rejected");
+ if (fd >= 0)
+ close(fd);
+ close(map_fd);
+ }
+ }
+ gen_loader_fixture_fini(&f);
+}
+
+static int setup_meta_map(const struct gen_loader_fixture *f);
+
+static void signed_btf_fd_array_rejected(void)
+{
+ char dir_tmpl[] = "/tmp/signed_loader_btfXXXXXX", *dir = NULL;
+ __u32 sig_sz = 8192;
+ int map_fd = -1, prog_fd = -1;
+ unsigned char *buf = NULL;
+ struct gen_loader_fixture f;
+ bool have_fixture = false;
+ struct btf *btf = NULL;
+ union bpf_attr attr;
+ int fds[2];
+ __u8 sig[8192];
+
+ syscall(__NR_request_key, "keyring", "_uid.0", NULL,
+ KEY_SPEC_SESSION_KEYRING);
+ dir = mkdtemp(dir_tmpl);
+ if (!ASSERT_OK_PTR(dir, "mkdtemp"))
+ return;
+ if (!ASSERT_OK(run_setup("setup", dir), "verify_sig_setup")) {
+ rmdir(dir);
+ return;
+ }
+ have_fixture = true;
+ if (gen_loader_fixture_init(&f) != 0)
+ goto out;
+
+ /*
+ * fd_array binds maps and BTFs alike, but only exclusive array maps are
+ * folded into the signature. Build an otherwise genuinely signed load -
+ * insns || metadata, exclusive frozen map at fd_array[0] - then smuggle
+ * an extra BTF into fd_array[1]. A signed program may not bind any BTF,
+ * so resolving the fd_array entries rejects the BTF with -EACCES (in
+ * __add_used_btf(), before the signature is even verified).
+ */
+ buf = malloc((size_t)f.gopts.insns_sz + f.data_sz);
+ if (!ASSERT_OK_PTR(buf, "signbuf"))
+ goto out;
+ memcpy(buf, f.gopts.insns, f.gopts.insns_sz);
+ memcpy(buf + f.gopts.insns_sz, f.blob, f.data_sz);
+ if (!ASSERT_OK(sign_buf(dir, buf, f.gopts.insns_sz + f.data_sz, sig,
+ &sig_sz), "sign insns||metadata"))
+ goto out;
+
+ map_fd = setup_meta_map(&f);
+ if (!ASSERT_OK_FD(map_fd, "meta_map"))
+ goto out;
+ btf = btf__new_empty();
+ if (!ASSERT_OK_PTR(btf, "btf_new_empty"))
+ goto out;
+ btf__add_int(btf, "int", 4, BTF_INT_SIGNED);
+ if (!ASSERT_OK(btf__load_into_kernel(btf), "btf_load"))
+ goto out;
+
+ fds[0] = map_fd;
+ fds[1] = btf__fd(btf);
+ memset(&attr, 0, sizeof(attr));
+ attr.prog_type = BPF_PROG_TYPE_SYSCALL;
+ attr.insns = ptr_to_u64(f.gopts.insns);
+ attr.insn_cnt = f.gopts.insns_sz / sizeof(struct bpf_insn);
+ attr.license = ptr_to_u64("Dual BSD/GPL");
+ attr.prog_flags = BPF_F_SLEEPABLE;
+ attr.fd_array = ptr_to_u64(fds);
+ attr.fd_array_cnt = 2;
+ attr.signature = ptr_to_u64(sig);
+ attr.signature_size = sig_sz;
+ attr.keyring_id = KEY_SPEC_SESSION_KEYRING;
+ memcpy(attr.prog_name, "__loader.prog", sizeof("__loader.prog"));
+ prog_fd = syscall(__NR_bpf, BPF_PROG_LOAD, &attr,
+ offsetofend(union bpf_attr, keyring_id));
+ ASSERT_EQ(prog_fd < 0 ? -errno : prog_fd, -EACCES,
+ "BTF in signed fd_array rejected");
+ if (prog_fd >= 0)
+ close(prog_fd);
+out:
+ if (btf)
+ btf__free(btf);
+ if (map_fd >= 0)
+ close(map_fd);
+ if (have_fixture)
+ gen_loader_fixture_fini(&f);
+ if (dir)
+ run_setup("cleanup", dir);
+ free(buf);
+}
+
+static void signature_failure_logs(void)
{
static const __u8 junk[64] = { 0x30, 0x42, 0x13, 0x37, };
+ char log_buf[1024] = {};
struct gen_loader_fixture f;
+ union bpf_attr attr;
int fd;
if (gen_loader_fixture_init(&f) == 0) {
/*
- * A present-but-invalid signature (the cert bytes are not a
- * PKCS#7 signature) must be rejected at load: the signature
- * path is honored, not ignored. (The valid path is covered by
- * the signed lskels.)
+ * Signature verification now runs inside bpf_check(), so a
+ * failure is reported through the verifier log. A present-but-
+ * invalid signature is rejected and the log says why.
*/
- fd = load_loader(f.gopts.insns, f.gopts.insns_sz, -1, junk,
- sizeof(junk), KEY_SPEC_SESSION_KEYRING);
+ memset(&attr, 0, sizeof(attr));
+ attr.prog_type = BPF_PROG_TYPE_SYSCALL;
+ attr.insns = ptr_to_u64(f.gopts.insns);
+ attr.insn_cnt = f.gopts.insns_sz / sizeof(struct bpf_insn);
+ attr.license = ptr_to_u64("Dual BSD/GPL");
+ attr.prog_flags = BPF_F_SLEEPABLE;
+ attr.signature = ptr_to_u64(junk);
+ attr.signature_size = sizeof(junk);
+ attr.keyring_id = KEY_SPEC_SESSION_KEYRING;
+ attr.log_level = 1;
+ attr.log_buf = ptr_to_u64(log_buf);
+ attr.log_size = sizeof(log_buf);
+ memcpy(attr.prog_name, "__loader.prog", sizeof("__loader.prog"));
+
+ fd = syscall(__NR_bpf, BPF_PROG_LOAD, &attr,
+ offsetofend(union bpf_attr, keyring_id));
ASSERT_LT(fd, 0, "invalid signature rejected at load");
+ if (fd >= 0)
+ close(fd);
+ ASSERT_HAS_SUBSTR(log_buf, "signature verification failed",
+ "verifier logs signature failure");
}
gen_loader_fixture_fini(&f);
}
@@ -495,8 +575,31 @@ static void signature_too_large(void)
* is rejected before the buffer is read.
*/
fd = load_loader(f.gopts.insns, f.gopts.insns_sz, -1, junk,
- 64 << 20, KEY_SPEC_SESSION_KEYRING);
+ 64 << 20, KEY_SPEC_SESSION_KEYRING, 0);
ASSERT_EQ(fd, -EINVAL, "oversized signature rejected");
+ if (fd >= 0)
+ close(fd);
+ }
+ gen_loader_fixture_fini(&f);
+}
+
+static void signature_zero_size(void)
+{
+ static const __u8 junk[64] = {};
+ struct gen_loader_fixture f;
+ int fd;
+
+ if (gen_loader_fixture_init(&f) == 0) {
+ /*
+ * A present signature with signature_size == 0 is rejected
+ * up front, before the keyring is resolved or the signature
+ * buffer is read.
+ */
+ fd = load_loader(f.gopts.insns, f.gopts.insns_sz, -1, junk,
+ 0, KEY_SPEC_SESSION_KEYRING, 0);
+ ASSERT_EQ(fd, -EINVAL, "zero-size signature rejected");
+ if (fd >= 0)
+ close(fd);
}
gen_loader_fixture_fini(&f);
}
@@ -515,8 +618,10 @@ static void signature_bad_keyring(void)
* large positive serial takes the user-keyring path and won't exist.
*/
fd = load_loader(f.gopts.insns, f.gopts.insns_sz, -1, junk,
- sizeof(junk), INT_MAX);
+ sizeof(junk), INT_MAX, 0);
ASSERT_EQ(fd, -EINVAL, "signature with bad keyring_id rejected");
+ if (fd >= 0)
+ close(fd);
}
gen_loader_fixture_fini(&f);
}
@@ -575,7 +680,7 @@ static void metadata_ctx_max_entries_ignored(void)
memcpy(blob, gopts.data, data_sz);
r = run_gen_loader(gopts.insns, gopts.insns_sz, blob, data_sz,
- excl, sizeof(excl), NULL, 0, true, ctx, ctx_sz, &ran);
+ excl, sizeof(excl), NULL, 0, ctx, ctx_sz, &ran);
if (!ASSERT_TRUE(ran, "loader ran") ||
!ASSERT_EQ(r, 0, "loader retval"))
goto free_blob;
@@ -661,7 +766,7 @@ static void metadata_ctx_initial_value_ignored(void)
memcpy(blob, gopts.data, data_sz);
r = run_gen_loader(gopts.insns, gopts.insns_sz, blob, data_sz,
- excl, sizeof(excl), NULL, 0, true, ctx, ctx_sz, &ran);
+ excl, sizeof(excl), NULL, 0, ctx, ctx_sz, &ran);
if (!ASSERT_TRUE(ran, "loader ran") ||
!ASSERT_EQ(r, 0, "loader retval"))
goto free_blob;
@@ -714,6 +819,7 @@ static void signature_authenticates_insns(void)
__u8 excl[SHA256_DIGEST_LENGTH], sig[8192];
__u32 sig_sz = sizeof(sig), insns_sz, data_sz, ctx_sz;
unsigned char *insns = NULL, *tampered = NULL, *blob = NULL;
+ unsigned char *signbuf = NULL;
int nr_maps = 0, nr_progs = 0, r;
struct bpf_program *p;
struct bpf_map *m;
@@ -760,29 +866,141 @@ static void signature_authenticates_insns(void)
memcpy(blob, gopts.data, data_sz);
libbpf_sha256(insns, insns_sz, excl);
- if (!ASSERT_OK(sign_buf(dir, insns, insns_sz, sig, &sig_sz), "sign-file"))
+ signbuf = malloc((size_t)insns_sz + data_sz);
+ if (!ASSERT_OK_PTR(signbuf, "signbuf"))
+ goto cleanup;
+ memcpy(signbuf, insns, insns_sz);
+ memcpy(signbuf + insns_sz, blob, data_sz);
+ if (!ASSERT_OK(sign_buf(dir, signbuf, insns_sz + data_sz, sig, &sig_sz),
+ "sign-file"))
goto cleanup;
memset(ctx, 0, ctx_sz);
((struct bpf_loader_ctx *)ctx)->sz = ctx_sz;
r = run_gen_loader(insns, insns_sz, blob, data_sz, excl, sizeof(excl),
- sig, sig_sz, true, ctx, ctx_sz, &ran);
+ sig, sig_sz, ctx, ctx_sz, &ran);
ASSERT_TRUE(ran, "valid signature: loader loaded and ran");
ASSERT_EQ(r, 0, "valid signature accepted");
close_loader_ctx_fds(ctx, nr_maps, nr_progs);
memcpy(tampered, insns, insns_sz);
tampered[insns_sz / 2] ^= 0xff;
+ /*
+ * Bind the metadata map to the tampered loader's own digest, so the
+ * verifier's exclusive-map check (excl_prog_sha == prog->digest) passes
+ * and the signature - verified after the maps are resolved - is what
+ * rejects the load. This is the attacker's best case: even after
+ * re-binding the exclusive map to their tampered loader, the signature
+ * over the original insns || metadata still fails. (Leaving the map
+ * bound to the original digest would instead trip the excl check first.)
+ */
+ libbpf_sha256(tampered, insns_sz, excl);
memset(ctx, 0, ctx_sz);
((struct bpf_loader_ctx *)ctx)->sz = ctx_sz;
r = run_gen_loader(tampered, insns_sz, blob, data_sz, excl, sizeof(excl),
- sig, sig_sz, true, ctx, ctx_sz, &ran);
+ sig, sig_sz, ctx, ctx_sz, &ran);
ASSERT_FALSE(ran, "tampered loader rejected before run");
ASSERT_EQ(r, -EKEYREJECTED, "signature is bound to the instructions");
cleanup:
free(insns);
free(tampered);
free(blob);
+ free(signbuf);
+ free(ctx);
+ test_signed_loader__destroy(skel);
+ run_setup("cleanup", dir);
+}
+
+static void signature_authenticates_metadata(void)
+{
+ LIBBPF_OPTS(gen_loader_opts, gopts, .gen_hash = true);
+ char dir_tmpl[] = "/tmp/signed_loaderXXXXXX", *dir;
+ struct test_signed_loader *skel = NULL;
+ __u8 excl[SHA256_DIGEST_LENGTH], sig[8192];
+ __u32 sig_sz = sizeof(sig), insns_sz, data_sz, ctx_sz;
+ unsigned char *insns = NULL, *blob = NULL;
+ unsigned char *signbuf = NULL;
+ int nr_maps = 0, nr_progs = 0, r;
+ struct bpf_program *p;
+ struct bpf_map *m;
+ void *ctx = NULL;
+ bool ran;
+
+ syscall(__NR_request_key, "keyring", "_uid.0", NULL,
+ KEY_SPEC_SESSION_KEYRING);
+ dir = mkdtemp(dir_tmpl);
+ if (!ASSERT_OK_PTR(dir, "mkdtemp"))
+ return;
+ if (!ASSERT_OK(run_setup("setup", dir), "verify_sig_setup")) {
+ rmdir(dir);
+ return;
+ }
+
+ skel = test_signed_loader__open();
+ if (!ASSERT_OK_PTR(skel, "skel_open"))
+ goto cleanup;
+ if (!ASSERT_OK(bpf_object__gen_loader(skel->obj, &gopts), "gen_loader"))
+ goto cleanup;
+ if (!ASSERT_OK(bpf_object__load(skel->obj), "gen_load"))
+ goto cleanup;
+
+ bpf_object__for_each_program(p, skel->obj)
+ nr_progs++;
+ bpf_object__for_each_map(m, skel->obj)
+ nr_maps++;
+ ctx_sz = sizeof(struct bpf_loader_ctx) +
+ nr_maps * sizeof(struct bpf_map_desc) +
+ nr_progs * sizeof(struct bpf_prog_desc);
+ insns_sz = gopts.insns_sz;
+ data_sz = gopts.data_sz;
+ ctx = calloc(1, ctx_sz);
+ insns = malloc(insns_sz);
+ blob = malloc(data_sz);
+ if (!ASSERT_OK_PTR(ctx, "ctx") ||
+ !ASSERT_OK_PTR(insns, "insns") ||
+ !ASSERT_OK_PTR(blob, "blob"))
+ goto cleanup;
+ memcpy(insns, gopts.insns, insns_sz);
+ memcpy(blob, gopts.data, data_sz);
+ libbpf_sha256(insns, insns_sz, excl);
+
+ signbuf = malloc((size_t)insns_sz + data_sz);
+ if (!ASSERT_OK_PTR(signbuf, "signbuf"))
+ goto cleanup;
+ memcpy(signbuf, insns, insns_sz);
+ memcpy(signbuf + insns_sz, blob, data_sz);
+ if (!ASSERT_OK(sign_buf(dir, signbuf, insns_sz + data_sz, sig, &sig_sz),
+ "sign-file"))
+ goto cleanup;
+
+ memset(ctx, 0, ctx_sz);
+ ((struct bpf_loader_ctx *)ctx)->sz = ctx_sz;
+ r = run_gen_loader(insns, insns_sz, blob, data_sz, excl, sizeof(excl),
+ sig, sig_sz, ctx, ctx_sz, &ran);
+ ASSERT_TRUE(ran, "valid signature: loader loaded and ran");
+ ASSERT_EQ(r, 0, "valid signature accepted");
+ close_loader_ctx_fds(ctx, nr_maps, nr_progs);
+
+ /*
+ * Tamper the metadata after signing while leaving the instructions
+ * and thus the exclusive hash binding untouched: the map freezes
+ * fine and excl_prog_sha still matches the loader's digest, so the
+ * load reaches signature verification, which folds the live frozen
+ * map bytes into the checked payload and must reject the modified
+ * blob. A kernel folding anything but the map contents themselves
+ * would wrongly accept this load.
+ */
+ blob[data_sz / 2] ^= 0xff;
+ memset(ctx, 0, ctx_sz);
+ ((struct bpf_loader_ctx *)ctx)->sz = ctx_sz;
+ r = run_gen_loader(insns, insns_sz, blob, data_sz, excl, sizeof(excl),
+ sig, sig_sz, ctx, ctx_sz, &ran);
+ ASSERT_FALSE(ran, "tampered metadata rejected before run");
+ ASSERT_EQ(r, -EKEYREJECTED, "signature is bound to the metadata");
+cleanup:
+ free(insns);
+ free(blob);
+ free(signbuf);
free(ctx);
test_signed_loader__destroy(skel);
run_setup("cleanup", dir);
@@ -1007,10 +1225,11 @@ static void lsm_signature_verdict(void)
{
char dir_tmpl[] = "/tmp/signed_loader_lsmXXXXXX", *dir = NULL;
struct test_signed_loader_lsm *lsm = NULL;
+ __u32 sig_sz = 8192, msig_sz = 8192;
int map_fd = -1, prog_fd = -1;
bool have_fixture = false;
struct gen_loader_fixture f;
- __u32 sig_sz = 8192;
+ unsigned char *buf;
__s32 ses_serial;
__u8 sig[8192];
@@ -1029,7 +1248,7 @@ static void lsm_signature_verdict(void)
if (!ASSERT_OK_FD(map_fd, "meta_map_unsigned"))
goto out;
lsm->bss->seen = 0;
- prog_fd = load_loader(f.gopts.insns, f.gopts.insns_sz, map_fd, NULL, 0, 0);
+ prog_fd = load_loader(f.gopts.insns, f.gopts.insns_sz, map_fd, NULL, 0, 0, 0);
close(map_fd);
map_fd = -1;
if (!ASSERT_OK_FD(prog_fd, "unsigned loader load"))
@@ -1062,22 +1281,51 @@ static void lsm_signature_verdict(void)
goto out;
lsm->bss->seen = 0;
prog_fd = load_loader(f.gopts.insns, f.gopts.insns_sz, map_fd, sig,
- sig_sz, KEY_SPEC_SESSION_KEYRING);
+ sig_sz, KEY_SPEC_SESSION_KEYRING, 0);
close(map_fd);
map_fd = -1;
- if (!ASSERT_OK_FD(prog_fd, "signed loader load"))
- goto out;
- close(prog_fd);
+ ASSERT_EQ(prog_fd, -EACCES, "unfolded metadata rejected");
+ if (prog_fd >= 0)
+ close(prog_fd);
prog_fd = -1;
ses_serial = syscall(__NR_keyctl, KEYCTL_GET_KEYRING_ID,
KEY_SPEC_SESSION_KEYRING, 0);
ASSERT_EQ(lsm->bss->seen, 1, "signed: one observed load");
- ASSERT_EQ(lsm->bss->sig_verdict, BPF_SIG_VERIFIED, "signed verdict");
+ ASSERT_EQ(lsm->bss->sig_verdict, BPF_SIG_VERIFIED,
+ "admission saw a valid signature");
ASSERT_EQ(lsm->bss->sig_keyring_type, BPF_SIG_KEYRING_USER, "signed keyring type");
ASSERT_GT(ses_serial, 0, "session keyring serial resolved");
ASSERT_EQ(lsm->bss->sig_keyring_serial, ses_serial,
"signed: validated against session keyring");
+
+ buf = malloc((size_t)f.gopts.insns_sz + f.data_sz);
+ if (!ASSERT_OK_PTR(buf, "meta_signbuf"))
+ goto out;
+ memcpy(buf, f.gopts.insns, f.gopts.insns_sz);
+ memcpy(buf + f.gopts.insns_sz, f.blob, f.data_sz);
+ if (!ASSERT_OK(sign_buf(dir, buf, f.gopts.insns_sz + f.data_sz,
+ sig, &msig_sz), "sign insns||metadata")) {
+ free(buf);
+ goto out;
+ }
+ free(buf);
+
+ map_fd = setup_meta_map(&f);
+ if (!ASSERT_OK_FD(map_fd, "meta_map_bound"))
+ goto out;
+ lsm->bss->seen = 0;
+ prog_fd = load_loader(f.gopts.insns, f.gopts.insns_sz, map_fd, sig,
+ msig_sz, KEY_SPEC_SESSION_KEYRING, 1);
+ close(map_fd);
+ map_fd = -1;
+ if (!ASSERT_OK_FD(prog_fd, "metadata-bound loader load"))
+ goto out;
+ close(prog_fd);
+ prog_fd = -1;
+ ASSERT_EQ(lsm->bss->seen, 1, "metadata: one observed load");
+ ASSERT_EQ(lsm->bss->sig_verdict, BPF_SIG_VERIFIED,
+ "metadata-bound verdict");
out:
if (map_fd >= 0)
close(map_fd);
@@ -1090,22 +1338,471 @@ out:
test_signed_loader_lsm__destroy(lsm);
}
+/*
+ * Load-time metadata verification: the kernel folds the frozen metadata map
+ * into the signature (insns || metadata) and checks it at BPF_PROG_LOAD via
+ * fd_array_cnt, rather than the loader checking from within BPF. Sign that
+ * concatenation, hand the kernel the map, and confirm the signed loader loads,
+ * runs, and installs its target.
+ */
+static int loadtime_drive(const char *dir, const void *insns, __u32 insns_sz,
+ const void *data, __u32 data_sz, const __u8 *excl,
+ void *ctx, __u32 ctx_sz, int *load_ret, bool *ran)
+{
+ LIBBPF_OPTS(bpf_map_create_opts, mopts,
+ .excl_prog_hash = excl,
+ .excl_prog_hash_size = SHA256_DIGEST_LENGTH);
+ __u32 sig_sz = 8192, key = 0;
+ unsigned char *buf = NULL;
+ int map_fd, prog_fd, ret = 0;
+ union bpf_attr attr;
+ __u8 sig[8192];
+
+ *ran = false;
+ *load_ret = 0;
+
+ /*
+ * Metadata map, bound to the loader digest and frozen, exactly as
+ * skel_internal.h's bpf_load_and_run() sets it up.
+ */
+ map_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "__loader.map", 4,
+ data_sz, 1, &mopts);
+ if (map_fd < 0) {
+ ret = -errno;
+ goto out_load;
+ }
+ if (bpf_map_update_elem(map_fd, &key, data, 0) || bpf_map_freeze(map_fd)) {
+ ret = -errno;
+ goto out_load;
+ }
+
+ /* Sign insns || metadata, the same bytes the kernel reconstructs. */
+ buf = malloc((size_t)insns_sz + data_sz);
+ if (!buf) {
+ ret = -ENOMEM;
+ goto out_load;
+ }
+ memcpy(buf, insns, insns_sz);
+ memcpy(buf + insns_sz, data, data_sz);
+ ret = sign_buf(dir, buf, insns_sz + data_sz, sig, &sig_sz);
+ if (ret)
+ goto out_load;
+
+ memset(&attr, 0, sizeof(attr));
+ attr.prog_type = BPF_PROG_TYPE_SYSCALL;
+ attr.insns = ptr_to_u64(insns);
+ attr.insn_cnt = insns_sz / sizeof(struct bpf_insn);
+ attr.license = ptr_to_u64("Dual BSD/GPL");
+ attr.prog_flags = BPF_F_SLEEPABLE;
+ attr.fd_array = ptr_to_u64(&map_fd);
+ attr.signature = ptr_to_u64(sig);
+ attr.signature_size = sig_sz;
+ attr.keyring_id = KEY_SPEC_SESSION_KEYRING;
+ attr.fd_array_cnt = 1;
+ memcpy(attr.prog_name, "__loader.prog", sizeof("__loader.prog"));
+ prog_fd = syscall(__NR_bpf, BPF_PROG_LOAD, &attr,
+ offsetofend(union bpf_attr, keyring_id));
+ if (prog_fd < 0) {
+ ret = -errno;
+ goto out_load;
+ }
+
+ memset(&attr, 0, sizeof(attr));
+ attr.test.prog_fd = prog_fd;
+ attr.test.ctx_in = ptr_to_u64(ctx);
+ attr.test.ctx_size_in = ctx_sz;
+ if (syscall(__NR_bpf, BPF_PROG_RUN, &attr,
+ offsetofend(union bpf_attr, test)) < 0) {
+ ret = -errno;
+ goto out_prog;
+ }
+ *ran = true;
+ ret = (int)attr.test.retval;
+out_prog:
+ close(prog_fd);
+ goto out_map;
+out_load:
+ *load_ret = ret;
+out_map:
+ free(buf);
+ if (map_fd >= 0)
+ close(map_fd);
+ return ret;
+}
+
+static void loadtime_verify(struct bpf_object *obj, int expect_maps)
+{
+ LIBBPF_OPTS(gen_loader_opts, gopts, .gen_hash = true);
+ char dir_tmpl[] = "/tmp/signed_loader_ltXXXXXX", *dir = NULL;
+ int nr_maps = 0, nr_progs = 0, load_ret = 0, r;
+ __u8 excl[SHA256_DIGEST_LENGTH];
+ struct bpf_prog_desc *pd;
+ struct bpf_map_desc *md;
+ unsigned char *blob = NULL;
+ struct bpf_program *p;
+ struct bpf_map *m;
+ __u32 ctx_sz, data_sz;
+ void *ctx = NULL;
+ bool ran = false;
+
+ syscall(__NR_request_key, "keyring", "_uid.0", NULL,
+ KEY_SPEC_SESSION_KEYRING);
+ dir = mkdtemp(dir_tmpl);
+ if (!ASSERT_OK_PTR(dir, "mkdtemp"))
+ return;
+ if (!ASSERT_OK(run_setup("setup", dir), "verify_sig_setup")) {
+ rmdir(dir);
+ return;
+ }
+
+ if (!ASSERT_OK(bpf_object__gen_loader(obj, &gopts), "gen_loader"))
+ goto out;
+ if (!ASSERT_OK(bpf_object__load(obj), "gen_load"))
+ goto out;
+
+ bpf_object__for_each_program(p, obj)
+ nr_progs++;
+ bpf_object__for_each_map(m, obj)
+ nr_maps++;
+ if (!ASSERT_EQ(nr_maps, expect_maps, "fixture map count"))
+ goto out;
+
+ ctx_sz = sizeof(struct bpf_loader_ctx) +
+ nr_maps * sizeof(struct bpf_map_desc) +
+ nr_progs * sizeof(struct bpf_prog_desc);
+ ctx = calloc(1, ctx_sz);
+ if (!ASSERT_OK_PTR(ctx, "ctx_alloc"))
+ goto out;
+ ((struct bpf_loader_ctx *)ctx)->sz = ctx_sz;
+
+ data_sz = gopts.data_sz;
+ blob = malloc(data_sz);
+ if (!ASSERT_OK_PTR(blob, "blob_alloc"))
+ goto out;
+ memcpy(blob, gopts.data, data_sz);
+
+ /* excl_prog_hash = SHA256(loader insns) == the loader's prog->digest. */
+ libbpf_sha256(gopts.insns, gopts.insns_sz, excl);
+
+ r = loadtime_drive(dir, gopts.insns, gopts.insns_sz, blob, data_sz,
+ excl, ctx, ctx_sz, &load_ret, &ran);
+ ASSERT_OK(load_ret, "signed loader loaded (insns || metadata)");
+ ASSERT_TRUE(ran, "loader ran");
+ ASSERT_EQ(r, 0, "loader installed its target");
+
+ md = (struct bpf_map_desc *)((char *)ctx + sizeof(struct bpf_loader_ctx));
+ pd = (struct bpf_prog_desc *)(md + nr_maps);
+ ASSERT_GT(pd[0].prog_fd, 0, "target program installed");
+ if (nr_maps)
+ ASSERT_GT(md[0].map_fd, 0, "target map installed");
+
+ close_loader_ctx_fds(ctx, nr_maps, nr_progs);
+out:
+ free(blob);
+ free(ctx);
+ if (dir)
+ run_setup("cleanup", dir);
+}
+
+static void loadtime_no_map(void)
+{
+ struct test_signed_loader *skel = test_signed_loader__open();
+
+ if (!ASSERT_OK_PTR(skel, "skel_open"))
+ return;
+ loadtime_verify(skel->obj, 0);
+ test_signed_loader__destroy(skel);
+}
+
+static void loadtime_with_map(void)
+{
+ struct test_signed_loader_map *skel = test_signed_loader_map__open();
+
+ if (!ASSERT_OK_PTR(skel, "skel_open"))
+ return;
+ loadtime_verify(skel->obj, 1);
+ test_signed_loader_map__destroy(skel);
+}
+
+/*
+ * A signed program need not bind any map. A plain BPF_PROG_TYPE_SYSCALL
+ * program with no fd_array is signed over its instructions alone: the kernel
+ * verifies the signature, folds no metadata, and the program loads. Exercise
+ * the fd_array == NULL / fd_array_cnt == 0 path, and confirm the signature
+ * still authenticates the instructions (a tampered copy is rejected).
+ */
+static void signed_no_fd_array(void)
+{
+ struct bpf_insn insns[] = {
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_EXIT_INSN(),
+ };
+ char dir_tmpl[] = "/tmp/signed_loaderXXXXXX", *dir;
+ __u32 sig_sz = 8192;
+ union bpf_attr attr;
+ __u8 sig[8192];
+ int prog_fd, err;
+
+ syscall(__NR_request_key, "keyring", "_uid.0", NULL,
+ KEY_SPEC_SESSION_KEYRING);
+ dir = mkdtemp(dir_tmpl);
+ if (!ASSERT_OK_PTR(dir, "mkdtemp"))
+ return;
+ if (!ASSERT_OK(run_setup("setup", dir), "verify_sig_setup")) {
+ rmdir(dir);
+ return;
+ }
+
+ /* No metadata map: the signed payload is the instructions alone. */
+ if (!ASSERT_OK(sign_buf(dir, insns, sizeof(insns), sig, &sig_sz),
+ "sign-file"))
+ goto cleanup;
+
+ memset(&attr, 0, sizeof(attr));
+ attr.prog_type = BPF_PROG_TYPE_SYSCALL;
+ attr.insns = ptr_to_u64(insns);
+ attr.insn_cnt = ARRAY_SIZE(insns);
+ attr.license = ptr_to_u64("Dual BSD/GPL");
+ attr.prog_flags = BPF_F_SLEEPABLE;
+ attr.signature = ptr_to_u64(sig);
+ attr.signature_size = sig_sz;
+ attr.keyring_id = KEY_SPEC_SESSION_KEYRING;
+ /* fd_array and fd_array_cnt deliberately left NULL/0. */
+ memcpy(attr.prog_name, "signed_nomap", sizeof("signed_nomap"));
+
+ prog_fd = syscall(__NR_bpf, BPF_PROG_LOAD, &attr,
+ offsetofend(union bpf_attr, keyring_id));
+ if (!ASSERT_GE(prog_fd, 0, "map-less signed program loaded")) {
+ if (prog_fd >= 0)
+ close(prog_fd);
+ goto cleanup;
+ }
+ close(prog_fd);
+
+ /* The signature covers the instructions, so tampering must be rejected. */
+ insns[0].imm = 1;
+ prog_fd = syscall(__NR_bpf, BPF_PROG_LOAD, &attr,
+ offsetofend(union bpf_attr, keyring_id));
+ err = prog_fd < 0 ? -errno : prog_fd;
+ ASSERT_EQ(err, -EKEYREJECTED, "tampered map-less program rejected");
+ if (prog_fd >= 0)
+ close(prog_fd);
+cleanup:
+ run_setup("cleanup", dir);
+}
+
+/*
+ * A signed program may reach maps only through fd_array indices, so the kernel
+ * folds (and thus attests) them. A direct BPF_PSEUDO_MAP_FD reference - a raw,
+ * unfolded fd baked into the signed instructions - is rejected by the verifier.
+ */
+static void signed_map_by_fd_rejected(void)
+{
+ struct bpf_insn insns[] = {
+ BPF_LD_MAP_FD(BPF_REG_1, 0),
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_EXIT_INSN(),
+ };
+ char dir_tmpl[] = "/tmp/signed_loaderXXXXXX", *dir;
+ __u32 sig_sz = 8192;
+ union bpf_attr attr;
+ __u8 sig[8192];
+ int map_fd, prog_fd, err;
+
+ map_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "sig_mapfd", 4, 4, 1, NULL);
+ if (!ASSERT_GE(map_fd, 0, "map_create"))
+ return;
+ insns[0].imm = map_fd; /* bake the raw map fd into the ld_imm64 */
+
+ syscall(__NR_request_key, "keyring", "_uid.0", NULL,
+ KEY_SPEC_SESSION_KEYRING);
+ dir = mkdtemp(dir_tmpl);
+ if (!ASSERT_OK_PTR(dir, "mkdtemp"))
+ goto out_map;
+ if (!ASSERT_OK(run_setup("setup", dir), "verify_sig_setup")) {
+ rmdir(dir);
+ goto out_map;
+ }
+
+ /* Sign the instructions, raw map fd and all. */
+ if (!ASSERT_OK(sign_buf(dir, insns, sizeof(insns), sig, &sig_sz),
+ "sign-file"))
+ goto cleanup;
+
+ memset(&attr, 0, sizeof(attr));
+ attr.prog_type = BPF_PROG_TYPE_SYSCALL;
+ attr.insns = ptr_to_u64(insns);
+ attr.insn_cnt = ARRAY_SIZE(insns);
+ attr.license = ptr_to_u64("Dual BSD/GPL");
+ attr.prog_flags = BPF_F_SLEEPABLE;
+ attr.signature = ptr_to_u64(sig);
+ attr.signature_size = sig_sz;
+ attr.keyring_id = KEY_SPEC_SESSION_KEYRING;
+ /* No fd_array: the map is reached by a raw fd in the instructions. */
+ memcpy(attr.prog_name, "signed_mapfd", sizeof("signed_mapfd"));
+
+ prog_fd = syscall(__NR_bpf, BPF_PROG_LOAD, &attr,
+ offsetofend(union bpf_attr, keyring_id));
+ err = prog_fd < 0 ? -errno : prog_fd;
+ ASSERT_EQ(err, -EINVAL, "signed program referencing a map by fd rejected");
+ if (prog_fd >= 0)
+ close(prog_fd);
+cleanup:
+ run_setup("cleanup", dir);
+out_map:
+ close(map_fd);
+}
+
+/*
+ * A signed program may reach maps only through the continuous fd_array, so the
+ * kernel folds (and thus attests) them. Referencing a map by fd_array *index*
+ * while leaving fd_array_cnt at 0 selects the sparse path, which resolves a map
+ * the signature never covered; the verifier rejects it up front with -EACCES.
+ */
+static void signed_sparse_fd_array_rejected(void)
+{
+ struct bpf_insn insns[] = {
+ BPF_LD_IMM64_RAW(BPF_REG_1, BPF_PSEUDO_MAP_IDX, 0),
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_EXIT_INSN(),
+ };
+ char dir_tmpl[] = "/tmp/signed_loader_spXXXXXX", *dir;
+ __u32 sig_sz = 8192;
+ union bpf_attr attr;
+ __u8 sig[8192];
+ int map_fd, prog_fd, err;
+
+ map_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "sig_sparse", 4, 4, 1, NULL);
+ if (!ASSERT_GE(map_fd, 0, "map_create"))
+ return;
+
+ syscall(__NR_request_key, "keyring", "_uid.0", NULL,
+ KEY_SPEC_SESSION_KEYRING);
+ dir = mkdtemp(dir_tmpl);
+ if (!ASSERT_OK_PTR(dir, "mkdtemp"))
+ goto out_map;
+ if (!ASSERT_OK(run_setup("setup", dir), "verify_sig_setup")) {
+ rmdir(dir);
+ goto out_map;
+ }
+
+ /* Sign the instructions alone; the sparse map is not folded. */
+ if (!ASSERT_OK(sign_buf(dir, insns, sizeof(insns), sig, &sig_sz),
+ "sign-file"))
+ goto cleanup;
+
+ memset(&attr, 0, sizeof(attr));
+ attr.prog_type = BPF_PROG_TYPE_SYSCALL;
+ attr.insns = ptr_to_u64(insns);
+ attr.insn_cnt = ARRAY_SIZE(insns);
+ attr.license = ptr_to_u64("Dual BSD/GPL");
+ attr.prog_flags = BPF_F_SLEEPABLE;
+ attr.fd_array = ptr_to_u64(&map_fd);
+ attr.fd_array_cnt = 0; /* sparse: force lazy map resolution */
+ attr.signature = ptr_to_u64(sig);
+ attr.signature_size = sig_sz;
+ attr.keyring_id = KEY_SPEC_SESSION_KEYRING;
+ memcpy(attr.prog_name, "signed_sparse", sizeof("signed_sparse"));
+
+ prog_fd = syscall(__NR_bpf, BPF_PROG_LOAD, &attr,
+ offsetofend(union bpf_attr, keyring_id));
+ err = prog_fd < 0 ? -errno : prog_fd;
+ ASSERT_EQ(err, -EACCES, "signed program binding a sparse fd_array map rejected");
+ if (prog_fd >= 0)
+ close(prog_fd);
+cleanup:
+ run_setup("cleanup", dir);
+out_map:
+ close(map_fd);
+}
+
+static void signed_module_kfunc_rejected(void)
+{
+ struct bpf_insn insns[] = {
+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, BPF_PSEUDO_KFUNC_CALL, 1, 1),
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_EXIT_INSN(),
+ };
+ char dir_tmpl[] = "/tmp/signed_loader_kfnXXXXXX", *dir;
+ int prog_fd, err, fds[2];
+ struct btf *btf = NULL;
+ __u32 sig_sz = 8192;
+ union bpf_attr attr;
+ __u8 sig[8192];
+
+ syscall(__NR_request_key, "keyring", "_uid.0", NULL,
+ KEY_SPEC_SESSION_KEYRING);
+ dir = mkdtemp(dir_tmpl);
+ if (!ASSERT_OK_PTR(dir, "mkdtemp"))
+ return;
+ if (!ASSERT_OK(run_setup("setup", dir), "verify_sig_setup")) {
+ rmdir(dir);
+ return;
+ }
+ if (!ASSERT_OK(sign_buf(dir, insns, sizeof(insns), sig, &sig_sz),
+ "sign-file"))
+ goto cleanup;
+ btf = btf__new_empty();
+ if (!ASSERT_OK_PTR(btf, "btf_new_empty"))
+ goto cleanup;
+ btf__add_int(btf, "int", 4, BTF_INT_SIGNED);
+ if (!ASSERT_OK(btf__load_into_kernel(btf), "btf_load"))
+ goto cleanup;
+ fds[0] = -1;
+ fds[1] = btf__fd(btf);
+
+ memset(&attr, 0, sizeof(attr));
+ attr.prog_type = BPF_PROG_TYPE_SYSCALL;
+ attr.insns = ptr_to_u64(insns);
+ attr.insn_cnt = ARRAY_SIZE(insns);
+ attr.license = ptr_to_u64("Dual BSD/GPL");
+ attr.prog_flags = BPF_F_SLEEPABLE;
+ attr.fd_array = ptr_to_u64(fds);
+ attr.fd_array_cnt = 0; /* sparse: force lazy kfunc BTF resolution */
+ attr.signature = ptr_to_u64(sig);
+ attr.signature_size = sig_sz;
+ attr.keyring_id = KEY_SPEC_SESSION_KEYRING;
+ memcpy(attr.prog_name, "signed_kfunc", sizeof("signed_kfunc"));
+
+ prog_fd = syscall(__NR_bpf, BPF_PROG_LOAD, &attr,
+ offsetofend(union bpf_attr, keyring_id));
+ err = prog_fd < 0 ? -errno : prog_fd;
+ if (prog_fd >= 0)
+ close(prog_fd);
+
+ ASSERT_EQ(err, -EACCES, "module kfunc BTF in signed program rejected");
+cleanup:
+ if (btf)
+ btf__free(btf);
+ run_setup("cleanup", dir);
+}
+
void test_signed_loader(void)
{
- if (test__start_subtest("metadata_check_shape"))
- metadata_check_shape();
+ if (test__start_subtest("loadtime_no_map"))
+ loadtime_no_map();
+ if (test__start_subtest("loadtime_with_map"))
+ loadtime_with_map();
if (test__start_subtest("metadata_match"))
metadata_match();
- if (test__start_subtest("metadata_sha_mismatch"))
- metadata_sha_mismatch();
- if (test__start_subtest("metadata_not_exclusive"))
- metadata_not_exclusive();
- if (test__start_subtest("metadata_hash_not_computed"))
- metadata_hash_not_computed();
if (test__start_subtest("signature_enforced"))
signature_enforced();
+ if (test__start_subtest("signed_nonexcl_fd_array_rejected"))
+ signed_nonexcl_fd_array_rejected();
+ if (test__start_subtest("signed_unfrozen_fd_array_rejected"))
+ signed_unfrozen_fd_array_rejected();
+ if (test__start_subtest("signed_nonarray_fd_array_rejected"))
+ signed_nonarray_fd_array_rejected();
+ if (test__start_subtest("signed_btf_fd_array_rejected"))
+ signed_btf_fd_array_rejected();
+ if (test__start_subtest("signed_module_kfunc_rejected"))
+ signed_module_kfunc_rejected();
+ if (test__start_subtest("signature_failure_logs"))
+ signature_failure_logs();
if (test__start_subtest("signature_too_large"))
signature_too_large();
+ if (test__start_subtest("signature_zero_size"))
+ signature_zero_size();
if (test__start_subtest("signature_bad_keyring"))
signature_bad_keyring();
if (test__start_subtest("metadata_ctx_max_entries_ignored"))
@@ -1114,6 +1811,8 @@ void test_signed_loader(void)
metadata_ctx_initial_value_ignored();
if (test__start_subtest("signature_authenticates_insns"))
signature_authenticates_insns();
+ if (test__start_subtest("signature_authenticates_metadata"))
+ signature_authenticates_metadata();
if (test__start_subtest("hash_requires_frozen"))
hash_requires_frozen();
if (test__start_subtest("no_update_after_freeze"))
@@ -1132,4 +1831,10 @@ void test_signed_loader(void)
map_hash_unsupported_type();
if (test__start_subtest("lsm_signature_verdict"))
lsm_signature_verdict();
+ if (test__start_subtest("signed_no_fd_array"))
+ signed_no_fd_array();
+ if (test__start_subtest("signed_map_by_fd_rejected"))
+ signed_map_by_fd_rejected();
+ if (test__start_subtest("signed_sparse_fd_array_rejected"))
+ signed_sparse_fd_array_rejected();
}
diff --git a/tools/testing/selftests/bpf/progs/icmp_send.c b/tools/testing/selftests/bpf/progs/icmp_send.c
new file mode 100644
index 000000000000..c642ccdf9fd5
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/icmp_send.c
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "vmlinux.h"
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_endian.h>
+
+/* 127.0.0.1 in host byte order */
+#define SERVER_IP 0x7F000001
+/* ::1 in host byte order (last 32-bit word) */
+#define SERVER_IP6_LO 0x00000001
+
+__u16 server_port = 0;
+int unreach_type = 0;
+int unreach_code = 0;
+int kfunc_ret = -1;
+int target_pid = -1;
+
+unsigned int rec_count = 0;
+int rec_kfunc_rets[] = { -1, -1 };
+
+SEC("cgroup_skb/egress")
+int egress(struct __sk_buff *skb)
+{
+ void *data = (void *)(long)skb->data;
+ void *data_end = (void *)(long)skb->data_end;
+ struct iphdr *iph;
+ struct ipv6hdr *ip6h;
+ struct tcphdr *tcph;
+ __u8 version;
+
+ if (data + 1 > data_end)
+ return SK_PASS;
+
+ version = (*((__u8 *)data)) >> 4;
+
+ if (version == 4) {
+ iph = data;
+ if ((void *)(iph + 1) > data_end ||
+ iph->protocol != IPPROTO_TCP ||
+ iph->daddr != bpf_htonl(SERVER_IP))
+ return SK_PASS;
+
+ tcph = (void *)iph + iph->ihl * 4;
+ if ((void *)(tcph + 1) > data_end ||
+ tcph->dest != bpf_htons(server_port))
+ return SK_PASS;
+
+ } else if (version == 6) {
+ ip6h = data;
+ if ((void *)(ip6h + 1) > data_end ||
+ ip6h->nexthdr != IPPROTO_TCP)
+ return SK_PASS;
+
+ if (ip6h->daddr.in6_u.u6_addr32[0] != 0 ||
+ ip6h->daddr.in6_u.u6_addr32[1] != 0 ||
+ ip6h->daddr.in6_u.u6_addr32[2] != 0 ||
+ ip6h->daddr.in6_u.u6_addr32[3] != bpf_htonl(SERVER_IP6_LO))
+ return SK_PASS;
+
+ tcph = (void *)(ip6h + 1);
+ if ((void *)(tcph + 1) > data_end ||
+ tcph->dest != bpf_htons(server_port))
+ return SK_PASS;
+ } else {
+ return SK_PASS;
+ }
+
+ kfunc_ret = bpf_icmp_send(skb, unreach_type, unreach_code);
+
+ return SK_DROP;
+}
+
+SEC("cgroup_skb/egress")
+int recursion(struct __sk_buff *skb)
+{
+ void *data = (void *)(long)skb->data;
+ void *data_end = (void *)(long)skb->data_end;
+ struct icmphdr *icmph;
+ struct tcphdr *tcph;
+ struct iphdr *iph;
+ int ret;
+
+ if ((bpf_get_current_pid_tgid() >> 32) != target_pid)
+ return SK_PASS;
+
+ iph = data;
+ if ((void *)(iph + 1) > data_end || iph->version != 4)
+ return SK_PASS;
+
+ if (iph->daddr != bpf_htonl(SERVER_IP))
+ return SK_PASS;
+
+ if (iph->protocol == IPPROTO_TCP) {
+ tcph = (void *)iph + iph->ihl * 4;
+ if ((void *)(tcph + 1) > data_end ||
+ tcph->dest != bpf_htons(server_port))
+ return SK_PASS;
+ } else if (iph->protocol == IPPROTO_ICMP) {
+ icmph = (void *)iph + iph->ihl * 4;
+ if ((void *)(icmph + 1) > data_end ||
+ icmph->type != unreach_type || icmph->code != unreach_code)
+ return SK_PASS;
+ } else {
+ return SK_PASS;
+ }
+
+ /*
+ * This call will provoke a recursion: the ICMP packet generated by the
+ * kfunc will re-trigger this program since we are in the root cgroup in
+ * which the kernel ICMP socket belongs. However when re-entering the
+ * kfunc, it should return EBUSY.
+ */
+ ret = bpf_icmp_send(skb, unreach_type, unreach_code);
+ rec_kfunc_rets[rec_count & 1] = ret;
+ __sync_fetch_and_add(&rec_count, 1);
+
+ /* Let the first ICMP error message pass */
+ if (iph->protocol == IPPROTO_ICMP)
+ return SK_PASS;
+
+ return SK_DROP;
+}
+
+char LICENSE[] SEC("license") = "Dual BSD/GPL";
diff --git a/tools/testing/selftests/bpf/progs/kfunc_call_fail.c b/tools/testing/selftests/bpf/progs/kfunc_call_fail.c
index a1963497f0bf..6144ce3ff0b2 100644
--- a/tools/testing/selftests/bpf/progs/kfunc_call_fail.c
+++ b/tools/testing/selftests/bpf/progs/kfunc_call_fail.c
@@ -103,6 +103,39 @@ int kfunc_call_test_get_mem_fail_oob(struct __sk_buff *skb)
return ret;
}
+SEC("?tc")
+int kfunc_call_test_get_mem_fail_oversized(struct __sk_buff *skb)
+{
+ struct prog_test_ref_kfunc *pt;
+ unsigned long s = 0;
+ int *p = NULL;
+ int ret = 0;
+
+ pt = bpf_kfunc_call_test_acquire(&s);
+ if (pt) {
+ /*
+ * rdwr_buf_size is a const int, so a C literal is narrowed to
+ * 32 bits before the call. Force the full 64-bit value 2^64 - 192
+ * (0xffffffffffffff40, > U32_MAX) into the argument register with
+ * a 64-bit immediate load. The verifier records r0_size from the
+ * full register value and must reject it before that value is
+ * truncated into R0's u32 mem_size.
+ */
+ asm volatile (
+ "r1 = %[pt];"
+ "r2 = %[oversized] ll;"
+ "call %[get_rdwr_mem];"
+ "%[p] = r0;"
+ : [p] "=r"(p)
+ : [pt] "r"(pt),
+ [oversized] "i"(0xffffffffffffff40LL),
+ [get_rdwr_mem] "i"(bpf_kfunc_call_test_get_rdwr_mem)
+ : "r0", "r1", "r2", "r3", "r4", "r5");
+ bpf_kfunc_call_test_release(pt);
+ }
+ return ret;
+}
+
int not_const_size = 2 * sizeof(int);
SEC("?tc")
diff --git a/tools/testing/selftests/bpf/progs/tcp_ca_untrusted_btf_write.c b/tools/testing/selftests/bpf/progs/tcp_ca_untrusted_btf_write.c
new file mode 100644
index 000000000000..eda4697aac80
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/tcp_ca_untrusted_btf_write.c
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "bpf_tracing_net.h"
+#include <bpf/bpf_core_read.h>
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_tracing.h>
+
+char _license[] SEC("license") = "GPL";
+
+SEC("struct_ops")
+void BPF_PROG(untrusted_btf_write_init, struct sock *sk)
+{
+ struct tcp_sock *tp;
+ int v = 1;
+ void *p;
+
+ p = bpf_rdonly_cast(&v, 0);
+ tp = bpf_rdonly_cast(p, bpf_core_type_id_kernel(struct tcp_sock));
+ tp->snd_cwnd = 1;
+}
+
+SEC(".struct_ops")
+struct tcp_congestion_ops untrusted_btf_write = {
+ .init = (void *)untrusted_btf_write_init,
+ .name = "bpf_ro_btf",
+};
diff --git a/tools/testing/selftests/bpf/progs/test_signed_loader.c b/tools/testing/selftests/bpf/progs/test_signed_loader.c
index d9a4b85f9391..50451a69b99a 100644
--- a/tools/testing/selftests/bpf/progs/test_signed_loader.c
+++ b/tools/testing/selftests/bpf/progs/test_signed_loader.c
@@ -4,10 +4,11 @@
/*
* Minimal, map-less program. Driven through libbpf's gen_loader (gen_hash)
- * by prog_tests/signed_loader.c so the generated light-skeleton loader (with
- * the emit_signature_match metadata check) can be exercised against good
- * and tampered metadata. A socket filter needs no load-time attach resolution,
- * and having no maps keeps the generated loader's ctx trivial (0 maps, 1 prog).
+ * by prog_tests/signed_loader.c so the generated light-skeleton loader can be
+ * exercised against good and tampered metadata, which the kernel now verifies
+ * at load time via the insns||metadata signature. A socket filter needs no
+ * load-time attach resolution, and having no maps keeps the generated loader's
+ * ctx trivial (0 maps, 1 prog).
*/
SEC("socket")
int probe(void *ctx)
diff --git a/tools/testing/selftests/bpf/progs/verifier_map_ptr.c b/tools/testing/selftests/bpf/progs/verifier_map_ptr.c
index 166193659870..e0a65835c861 100644
--- a/tools/testing/selftests/bpf/progs/verifier_map_ptr.c
+++ b/tools/testing/selftests/bpf/progs/verifier_map_ptr.c
@@ -72,14 +72,15 @@ __naked void bpf_map_ptr_write_rejected(void)
/*
* struct bpf_map starts with the SHA256 hash sha[32] at offset 0 (a readable
- * byte array), the u32 excl field at offset 32, and the ops pointer at offset
- * 40. Reading a u32 at offset 41 reaches into the middle of the ops pointer,
- * i.e. a partial pointer access, which is rejected.
+ * byte array), followed by the ops pointer at offset 32 and the inner_map_meta
+ * pointer at offset 40. Reading a u32 at offset 41 reaches into the middle of
+ * the inner_map_meta pointer, i.e. a partial pointer access, which is
+ * rejected.
*/
SEC("socket")
__description("bpf_map_ptr: read non-existent field rejected")
__failure
-__msg("cannot access ptr member ops with moff 40 in struct bpf_map with off 41 size 4")
+__msg("cannot access ptr member inner_map_meta with moff 40 in struct bpf_map with off 41 size 4")
__failure_unpriv
__msg_unpriv("access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN")
__flag(BPF_F_ANY_ALIGNMENT)
@@ -97,23 +98,23 @@ __naked void read_non_existent_field_rejected(void)
}
/*
- * The u32 excl field spans offsets 32..35 (mend 36). Reading a u32 at offset
- * 33 starts inside excl but extends past its end, which the verifier rejects
+ * The sha byte array spans offsets 0..31 (mend 32). Reading a u32 at offset
+ * 30 starts inside sha but extends past its end, which the verifier rejects
* as an out-of-bounds scalar access.
*/
SEC("socket")
-__description("bpf_map_ptr: read beyond excl field rejected")
+__description("bpf_map_ptr: read beyond sha field rejected")
__failure
-__msg("access beyond the end of member excl (mend:36) in struct bpf_map with off 33 size 4")
+__msg("access beyond the end of member sha (mend:32) in struct bpf_map with off 30 size 4")
__failure_unpriv
__msg_unpriv("access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN")
__flag(BPF_F_ANY_ALIGNMENT)
-__naked void read_beyond_excl_field_rejected(void)
+__naked void read_beyond_sha_field_rejected(void)
{
asm volatile (" \
r6 = 0; \
r1 = %[map_array_48b] ll; \
- r6 = *(u32*)(r1 + 33); \
+ r6 = *(u32*)(r1 + 30); \
r0 = 1; \
exit; \
" :
@@ -131,7 +132,7 @@ __naked void ptr_read_ops_field_accepted(void)
asm volatile (" \
r6 = 0; \
r1 = %[map_array_48b] ll; \
- r6 = *(u64*)(r1 + 40); \
+ r6 = *(u64*)(r1 + 32); \
r0 = 1; \
exit; \
" :
diff --git a/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c b/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c
index e38f102da45f..663d15fc5fd2 100644
--- a/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c
+++ b/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c
@@ -4,6 +4,13 @@
#include <bpf/bpf_helpers.h>
#include "bpf_misc.h"
+struct {
+ __uint(type, BPF_MAP_TYPE_HASH);
+ __uint(max_entries, 1);
+ __type(key, long long);
+ __type(value, long long);
+} map_hash_8b SEC(".maps");
+
/* Check that precision marks propagate through scalar IDs.
* Registers r{0,1,2} have the same scalar ID.
* Range information is propagated for scalars sharing same ID.
@@ -915,4 +922,53 @@ __naked void linked_regs_and_subreg_def(void)
: __clobber_all);
}
+/*
+ * A scalar is spilled to the stack and then filled twice: once via a
+ * sign-extending load (BPF_MEMSX) into r4 and once via a zero-extending
+ * load (BPF_MEM) into r5. coerce_reg_to_size_sx() gives r4 a different
+ * value than the spilled/zero-extended siblings, so r4 must not keep the
+ * shared scalar id. Otherwise the later 'if r5 == 0x80000000' refines r4
+ * through sync_linked_regs() to a known 0x80000000, while at runtime r4
+ * is the sign-extended 0xffffffff80000000. The test turns that discrepancy
+ * into an out-of-bounds map value access (r4 >> 63 is believed 0 but is 1
+ * at runtime), which must be rejected.
+ */
+SEC("socket")
+__failure __msg("R0 max value is outside of the allowed memory range")
+__naked void ldsx_fill_scalar_id_not_shared(void)
+{
+ asm volatile (" \
+ r1 = 0; \
+ *(u64*)(r10 - 8) = r1; \
+ r2 = r10; \
+ r2 += -8; \
+ r1 = %[map_hash_8b] ll; \
+ call %[bpf_map_lookup_elem]; \
+ if r0 == 0 goto l0_%=; \
+ /* r7 = unknown u32, keep only bit 31 */ \
+ r7 = *(u32*)(r0 + 0); \
+ r2 = 0x80000000 ll; \
+ r7 &= r2; \
+ /* link r6 and r7 via a fresh scalar id */ \
+ r6 = r7; \
+ /* spill r7 (u32) to the stack */ \
+ *(u32*)(r10 - 8) = r7; \
+ /* sign-extending fill: must drop the id */ \
+ r4 = *(s32*)(r10 - 8); \
+ /* zero-extending fill: keeps the id */ \
+ r5 = *(u32*)(r10 - 8); \
+ /* r5 becomes known 0x80000000 on fall-through */\
+ if r5 != r2 goto l0_%=; \
+ /* verifier believes r4 == 0 here, runtime is 1 */\
+ r4 >>= 63; \
+ r0 += r4; \
+ r0 = *(u8*)(r0 + 7); \
+l0_%=: r0 = 0; \
+ exit; \
+" :
+ : __imm(bpf_map_lookup_elem),
+ __imm_addr(map_hash_8b)
+ : __clobber_all);
+}
+
char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/drivers/net/hw/rss_ctx.py b/tools/testing/selftests/drivers/net/hw/rss_ctx.py
index f36f76d6ca59..5b25fa89c629 100755
--- a/tools/testing/selftests/drivers/net/hw/rss_ctx.py
+++ b/tools/testing/selftests/drivers/net/hw/rss_ctx.py
@@ -651,9 +651,14 @@ def test_rss_context_overlap(cfg, other_ctx=0):
ntuple = defer(ethtool, f"-N {cfg.ifname} delete {ntuple_id}")
# Test the main context
- cnts = _get_rx_cnts(cfg)
- GenerateTraffic(cfg, port=port).wait_pkts_and_stop(20000)
- cnts = _get_rx_cnts(cfg, prev=cnts)
+ attempts = 3
+ for attempt in range(attempts):
+ cnts = _get_rx_cnts(cfg)
+ GenerateTraffic(cfg, port=port).wait_pkts_and_stop(20000)
+ cnts = _get_rx_cnts(cfg, prev=cnts)
+ if sum(cnts[:2]) >= 7000 and sum(cnts[2:4]) >= 7000:
+ break
+ ksft_pr(f"Skewed queue distribution, attempt {attempt + 1}/{attempts}: " + str(cnts))
ksft_ge(sum(cnts[ :4]), 20000, "traffic on main context: " + str(cnts))
ksft_ge(sum(cnts[ :2]), 7000, "traffic on main context (1/2): " + str(cnts))
diff --git a/tools/testing/selftests/drivers/net/lib/py/env.py b/tools/testing/selftests/drivers/net/lib/py/env.py
index e4ab99b905b1..e4acf3d8333f 100644
--- a/tools/testing/selftests/drivers/net/lib/py/env.py
+++ b/tools/testing/selftests/drivers/net/lib/py/env.py
@@ -159,13 +159,7 @@ class NetDrvEpEnv(NetDrvEnvBase):
self.remote = Remote(kind, args, src_path)
- self.addr_ipver = "6" if self.addr_v["6"] else "4"
- self.addr = self.addr_v[self.addr_ipver]
- self.remote_addr = self.remote_addr_v[self.addr_ipver]
-
- # Bracketed addresses, some commands need IPv6 to be inside []
- self.baddr = f"[{self.addr_v['6']}]" if self.addr_v["6"] else self.addr_v["4"]
- self.remote_baddr = f"[{self.remote_addr_v['6']}]" if self.remote_addr_v["6"] else self.remote_addr_v["4"]
+ self.set_ipver("6" if self.addr_v["6"] else "4")
self.ifname = self.dev['ifname']
self.ifindex = self.dev['ifindex']
@@ -252,6 +246,25 @@ class NetDrvEpEnv(NetDrvEnvBase):
if not self.addr_v[ipver] or not self.remote_addr_v[ipver]:
raise KsftSkipEx(f"Test requires IPv{ipver} connectivity")
+ def set_ipver(self, ipver):
+ """
+ Modify the IP version used by the generic address fields.
+ """
+ if ipver == getattr(self, "addr_ipver", None):
+ return
+
+ self.require_ipver(ipver)
+
+ self.addr_ipver = ipver
+ self.addr = self.addr_v[ipver]
+ self.remote_addr = self.remote_addr_v[ipver]
+
+ # Bracketed addresses, some commands need IPv6 to be inside []
+ self.baddr = (f"[{self.addr_v['6']}]" if ipver == "6"
+ else self.addr_v["4"])
+ self.remote_baddr = (f"[{self.remote_addr_v['6']}]" if ipver == "6"
+ else self.remote_addr_v["4"])
+
def require_nsim(self, nsim_test=True):
"""Require or exclude netdevsim for this test"""
if nsim_test and self._ns is None:
diff --git a/tools/testing/selftests/drivers/net/xdp.py b/tools/testing/selftests/drivers/net/xdp.py
index 2ad5932299e8..0369929f3c51 100755
--- a/tools/testing/selftests/drivers/net/xdp.py
+++ b/tools/testing/selftests/drivers/net/xdp.py
@@ -172,25 +172,45 @@ def _test_pass(cfg, bpf_info, msg_sz):
ksft_eq(stats[XDPStats.RX.value], stats[XDPStats.PASS.value], "RX and PASS stats mismatch")
-def test_xdp_native_pass_sb(cfg):
+_ipvers = [
+ KsftNamedVariant("ipv4", "4"),
+ KsftNamedVariant("ipv6", "6"),
+]
+
+
+def _set_ipver_defer_restore(cfg, ipver):
+ old_ipver = cfg.addr_ipver
+ cfg.set_ipver(ipver)
+ defer(cfg.set_ipver, old_ipver)
+
+
+@ksft_variants(_ipvers)
+def test_xdp_native_pass_sb(cfg, ipver):
"""
Tests the XDP_PASS action for single buffer case.
Args:
cfg: Configuration object containing network settings.
+ ipver: IP version to use ("4" or "6").
"""
+ _set_ipver_defer_restore(cfg, ipver)
+
bpf_info = BPFProgInfo("xdp_prog", "xdp_native.bpf.o", "xdp", 1500)
_test_pass(cfg, bpf_info, 256)
-def test_xdp_native_pass_mb(cfg):
+@ksft_variants(_ipvers)
+def test_xdp_native_pass_mb(cfg, ipver):
"""
Tests the XDP_PASS action for a multi-buff size.
Args:
cfg: Configuration object containing network settings.
+ ipver: IP version to use ("4" or "6").
"""
+ _set_ipver_defer_restore(cfg, ipver)
+
bpf_info = BPFProgInfo("xdp_prog_frags", "xdp_native.bpf.o", "xdp.frags", 9000)
_test_pass(cfg, bpf_info, 8000)
@@ -219,25 +239,33 @@ def _test_drop(cfg, bpf_info, msg_sz):
ksft_eq(stats[XDPStats.RX.value], stats[XDPStats.DROP.value], "RX and DROP stats mismatch")
-def test_xdp_native_drop_sb(cfg):
+@ksft_variants(_ipvers)
+def test_xdp_native_drop_sb(cfg, ipver):
"""
Tests the XDP_DROP action for a signle-buff case.
Args:
cfg: Configuration object containing network settings.
+ ipver: IP version to use ("4" or "6").
"""
+ _set_ipver_defer_restore(cfg, ipver)
+
bpf_info = BPFProgInfo("xdp_prog", "xdp_native.bpf.o", "xdp", 1500)
_test_drop(cfg, bpf_info, 256)
-def test_xdp_native_drop_mb(cfg):
+@ksft_variants(_ipvers)
+def test_xdp_native_drop_mb(cfg, ipver):
"""
Tests the XDP_DROP action for a multi-buff case.
Args:
cfg: Configuration object containing network settings.
+ ipver: IP version to use ("4" or "6").
"""
+ _set_ipver_defer_restore(cfg, ipver)
+
bpf_info = BPFProgInfo("xdp_prog_frags", "xdp_native.bpf.o", "xdp.frags", 9000)
_test_drop(cfg, bpf_info, 8000)
@@ -287,13 +315,17 @@ def _test_xdp_native_tx(cfg, bpf_info, payload_lens):
ksft_eq(stats[XDPStats.TX.value], expected_pkts, "TX stats mismatch")
-def test_xdp_native_tx_sb(cfg):
+@ksft_variants(_ipvers)
+def test_xdp_native_tx_sb(cfg, ipver):
"""
Tests the XDP_TX action for a single-buff case.
Args:
cfg: Configuration object containing network settings.
+ ipver: IP version to use ("4" or "6").
"""
+ _set_ipver_defer_restore(cfg, ipver)
+
bpf_info = BPFProgInfo("xdp_prog", "xdp_native.bpf.o", "xdp", 1500)
# Ensure there's enough room for an ETH / IP / UDP header
@@ -302,13 +334,17 @@ def test_xdp_native_tx_sb(cfg):
_test_xdp_native_tx(cfg, bpf_info, [0, 1500 // 2, 1500 - pkt_hdr_len])
-def test_xdp_native_tx_mb(cfg):
+@ksft_variants(_ipvers)
+def test_xdp_native_tx_mb(cfg, ipver):
"""
Tests the XDP_TX action for a multi-buff case.
Args:
cfg: Configuration object containing network settings.
+ ipver: IP version to use ("4" or "6").
"""
+ _set_ipver_defer_restore(cfg, ipver)
+
bpf_info = BPFProgInfo("xdp_prog_frags", "xdp_native.bpf.o",
"xdp.frags", 9000)
# The first packet ensures we exercise the fragmented code path.
@@ -447,13 +483,17 @@ def _test_xdp_native_tail_adjst(cfg, pkt_sz_lst, offset_lst):
return {"status": "pass"}
-def test_xdp_native_adjst_tail_grow_data(cfg):
+@ksft_variants(_ipvers)
+def test_xdp_native_adjst_tail_grow_data(cfg, ipver):
"""
Tests the XDP tail adjustment by growing packet data.
Args:
cfg: Configuration object containing network settings.
+ ipver: IP version to use ("4" or "6").
"""
+ _set_ipver_defer_restore(cfg, ipver)
+
pkt_sz_lst = [512, 1024, 2048]
offset_lst = [1, 16, 32, 64, 128, 256]
res = _test_xdp_native_tail_adjst(
@@ -465,13 +505,17 @@ def test_xdp_native_adjst_tail_grow_data(cfg):
_validate_res(res, offset_lst, pkt_sz_lst)
-def test_xdp_native_adjst_tail_shrnk_data(cfg):
+@ksft_variants(_ipvers)
+def test_xdp_native_adjst_tail_shrnk_data(cfg, ipver):
"""
Tests the XDP tail adjustment by shrinking packet data.
Args:
cfg: Configuration object containing network settings.
+ ipver: IP version to use ("4" or "6").
"""
+ _set_ipver_defer_restore(cfg, ipver)
+
pkt_sz_lst = [512, 1024, 2048]
offset_lst = [-16, -32, -64, -128, -256]
res = _test_xdp_native_tail_adjst(
@@ -535,7 +579,7 @@ def _test_xdp_native_head_adjst(cfg, prog, pkt_sz_lst, offset_lst):
# after we eat into it. We send large-enough packets, but if HDS
# is enabled head will only contain headers. Don't try to eat
# more than 28 bytes (UDPv4 + eth hdr left: (14 + 20 + 8) - 14)
- l2_cut_off = 28 if cfg.addr_ipver == 4 else 48
+ l2_cut_off = 28 if cfg.addr_ipver == "4" else 48
if pkt_sz > hds_thresh and offset > l2_cut_off:
ksft_pr(
f"Failed run: pkt_sz ({pkt_sz}) > HDS threshold ({hds_thresh}) and "
@@ -579,18 +623,22 @@ def _test_xdp_native_head_adjst(cfg, prog, pkt_sz_lst, offset_lst):
return {"status": "pass"}
-def test_xdp_native_adjst_head_grow_data(cfg):
+@ksft_variants(_ipvers)
+def test_xdp_native_adjst_head_grow_data(cfg, ipver):
"""
Tests the XDP headroom growth support.
Args:
cfg: Configuration object containing network settings.
+ ipver: IP version to use ("4" or "6").
This function sets up the packet size and offset lists, then calls the
_test_xdp_native_head_adjst_mb function to perform the actual test. The
test is passed if the headroom is successfully extended for given packet
sizes and offsets.
"""
+ _set_ipver_defer_restore(cfg, ipver)
+
pkt_sz_lst = [512, 1024, 2048]
# Negative values result in headroom shrinking, resulting in growing of payload
@@ -600,18 +648,22 @@ def test_xdp_native_adjst_head_grow_data(cfg):
_validate_res(res, offset_lst, pkt_sz_lst)
-def test_xdp_native_adjst_head_shrnk_data(cfg):
+@ksft_variants(_ipvers)
+def test_xdp_native_adjst_head_shrnk_data(cfg, ipver):
"""
Tests the XDP headroom shrinking support.
Args:
cfg: Configuration object containing network settings.
+ ipver: IP version to use ("4" or "6").
This function sets up the packet size and offset lists, then calls the
_test_xdp_native_head_adjst_mb function to perform the actual test. The
test is passed if the headroom is successfully shrunk for given packet
sizes and offsets.
"""
+ _set_ipver_defer_restore(cfg, ipver)
+
pkt_sz_lst = [512, 1024, 2048]
# Positive values result in headroom growing, resulting in shrinking of payload
@@ -621,12 +673,19 @@ def test_xdp_native_adjst_head_shrnk_data(cfg):
_validate_res(res, offset_lst, pkt_sz_lst)
-@ksft_variants([
- KsftNamedVariant("pass", XDPAction.PASS),
- KsftNamedVariant("drop", XDPAction.DROP),
- KsftNamedVariant("tx", XDPAction.TX),
-])
-def test_xdp_native_qstats(cfg, act):
+def _qstats_variants():
+ actions = [
+ ("pass", XDPAction.PASS),
+ ("drop", XDPAction.DROP),
+ ("tx", XDPAction.TX),
+ ]
+ for ipver in ["4", "6"]:
+ for name, act in actions:
+ yield KsftNamedVariant(f"{name}_ipv{ipver}", act, ipver)
+
+
+@ksft_variants(_qstats_variants())
+def test_xdp_native_qstats(cfg, act, ipver):
"""
Send 1000 messages. Expect XDP action specified in @act.
Make sure the packets were counted to interface level qstats
@@ -634,6 +693,7 @@ def test_xdp_native_qstats(cfg, act):
"""
cfg.require_cmd("socat")
+ _set_ipver_defer_restore(cfg, ipver)
bpf_info = BPFProgInfo("xdp_prog", "xdp_native.bpf.o", "xdp", 1500)
prog_info = _load_xdp_prog(cfg, bpf_info)
diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index 665f0be0a97e..eb8af7b8a29a 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -11,6 +11,7 @@ LIBKVM += lib/kvm_util.c
LIBKVM += lib/lru_gen_util.c
LIBKVM += lib/memstress.c
LIBKVM += lib/guest_sprintf.c
+LIBKVM += lib/proc_util.c
LIBKVM += lib/rbtree.c
LIBKVM += lib/sparsebit.c
LIBKVM += lib/test_util.c
@@ -157,6 +158,7 @@ TEST_GEN_PROGS_x86 += coalesced_io_test
TEST_GEN_PROGS_x86 += dirty_log_perf_test
TEST_GEN_PROGS_x86 += guest_memfd_test
TEST_GEN_PROGS_x86 += hardware_disable_test
+TEST_GEN_PROGS_x86 += irq_test
TEST_GEN_PROGS_x86 += mmu_stress_test
TEST_GEN_PROGS_x86 += rseq_test
TEST_GEN_PROGS_x86 += steal_time
@@ -260,6 +262,7 @@ OVERRIDE_TARGETS = 1
# which causes the environment variable to override the makefile).
include ../lib.mk
include ../cgroup/lib/libcgroup.mk
+include ../vfio/lib/libvfio.mk
INSTALL_HDR_PATH = $(top_srcdir)/usr
LINUX_HDR_PATH = $(INSTALL_HDR_PATH)/include/
@@ -314,7 +317,9 @@ LIBKVM_S := $(filter %.S,$(LIBKVM))
LIBKVM_C_OBJ := $(patsubst %.c, $(OUTPUT)/%.o, $(LIBKVM_C))
LIBKVM_S_OBJ := $(patsubst %.S, $(OUTPUT)/%.o, $(LIBKVM_S))
LIBKVM_STRING_OBJ := $(patsubst %.c, $(OUTPUT)/%.o, $(LIBKVM_STRING))
-LIBKVM_OBJS = $(LIBKVM_C_OBJ) $(LIBKVM_S_OBJ) $(LIBKVM_STRING_OBJ) $(LIBCGROUP_O)
+LIBKVM_OBJS = $(LIBKVM_C_OBJ) $(LIBKVM_S_OBJ) $(LIBKVM_STRING_OBJ)
+LIBKVM_OBJS += $(LIBCGROUP_O)
+LIBKVM_OBJS += $(LIBVFIO_O)
SPLIT_TEST_GEN_PROGS := $(patsubst %, $(OUTPUT)/%, $(SPLIT_TESTS))
SPLIT_TEST_GEN_OBJ := $(patsubst %, $(OUTPUT)/$(ARCH)/%.o, $(SPLIT_TESTS))
diff --git a/tools/testing/selftests/kvm/arch_timer.c b/tools/testing/selftests/kvm/arch_timer.c
index 90c475a61b22..f8b02597897b 100644
--- a/tools/testing/selftests/kvm/arch_timer.c
+++ b/tools/testing/selftests/kvm/arch_timer.c
@@ -85,7 +85,7 @@ static u32 test_get_pcpu(void)
cpu_set_t online_cpuset;
nproc_conf = get_nprocs_conf();
- sched_getaffinity(0, sizeof(cpu_set_t), &online_cpuset);
+ kvm_sched_getaffinity(0, sizeof(cpu_set_t), &online_cpuset);
/* Randomly find an available pCPU to place a vCPU on */
do {
diff --git a/tools/testing/selftests/kvm/arm64/arch_timer_edge_cases.c b/tools/testing/selftests/kvm/arm64/arch_timer_edge_cases.c
index f7625eb711d6..d9c9377a6325 100644
--- a/tools/testing/selftests/kvm/arm64/arch_timer_edge_cases.c
+++ b/tools/testing/selftests/kvm/arm64/arch_timer_edge_cases.c
@@ -1039,7 +1039,7 @@ int main(int argc, char *argv[])
if (!parse_args(argc, argv))
exit(KSFT_SKIP);
- sched_getaffinity(0, sizeof(default_cpuset), &default_cpuset);
+ kvm_sched_getaffinity(0, sizeof(default_cpuset), &default_cpuset);
set_counter_defaults();
if (test_args.test_virtual) {
diff --git a/tools/testing/selftests/kvm/demand_paging_test.c b/tools/testing/selftests/kvm/demand_paging_test.c
index 302c4923d093..f8b3d0b68830 100644
--- a/tools/testing/selftests/kvm/demand_paging_test.c
+++ b/tools/testing/selftests/kvm/demand_paging_test.c
@@ -57,7 +57,7 @@ static void vcpu_worker(struct memstress_vcpu_args *vcpu_args)
static int handle_uffd_page_request(int uffd_mode, int uffd,
struct uffd_msg *msg)
{
- pid_t tid = syscall(__NR_gettid);
+ pid_t tid = kvm_gettid();
u64 addr = msg->arg.pagefault.address;
struct timespec start;
struct timespec ts_diff;
diff --git a/tools/testing/selftests/kvm/dirty_log_perf_test.c b/tools/testing/selftests/kvm/dirty_log_perf_test.c
index ef779fa91827..7c5abe1ae9e0 100644
--- a/tools/testing/selftests/kvm/dirty_log_perf_test.c
+++ b/tools/testing/selftests/kvm/dirty_log_perf_test.c
@@ -311,7 +311,7 @@ int main(int argc, char *argv[])
int opt;
/* Override the seed to be deterministic by default. */
- guest_random_seed = 1;
+ kvm_random_seed = 1;
dirty_log_manual_caps =
kvm_check_cap(KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2);
@@ -357,7 +357,7 @@ int main(int argc, char *argv[])
p.phys_offset = strtoull(optarg, NULL, 0);
break;
case 'r':
- guest_random_seed = atoi_positive("Random seed", optarg);
+ kvm_random_seed = atoi_positive("Random seed", optarg);
break;
case 's':
p.backing_src = parse_backing_src_type(optarg);
diff --git a/tools/testing/selftests/kvm/dirty_log_test.c b/tools/testing/selftests/kvm/dirty_log_test.c
index 74ca096bf976..e8419d7da1ea 100644
--- a/tools/testing/selftests/kvm/dirty_log_test.c
+++ b/tools/testing/selftests/kvm/dirty_log_test.c
@@ -121,7 +121,7 @@ static void guest_code(void)
while (true) {
while (!READ_ONCE(vcpu_stop)) {
addr = guest_test_virt_mem;
- addr += (guest_random_u64(&guest_rng) % guest_num_pages)
+ addr += (kvm_random_u64(&kvm_rng) % guest_num_pages)
* guest_page_size;
addr = align_down(addr, host_page_size);
@@ -708,8 +708,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)
sync_global_to_guest(vm, iteration);
- WRITE_ONCE(nr_writes, 0);
- sync_global_to_guest(vm, nr_writes);
+ WRITE_AND_SYNC_TO_GUEST(vm, nr_writes, 0);
dirty_ring_prev_iteration_last_page = dirty_ring_last_page;
WRITE_ONCE(dirty_ring_vcpu_ring_full, false);
@@ -775,16 +774,14 @@ static void run_test(enum vm_guest_mode mode, void *arg)
* writing memory during verification, pages that this thread
* sees as clean may be written with this iteration's value.
*/
- WRITE_ONCE(vcpu_stop, true);
- sync_global_to_guest(vm, vcpu_stop);
+ WRITE_AND_SYNC_TO_GUEST(vm, vcpu_stop, true);
sem_wait(&sem_vcpu_stop);
/*
* Clear vcpu_stop after the vCPU thread has acknowledge the
* stop request and is waiting, i.e. is definitely not running!
*/
- WRITE_ONCE(vcpu_stop, false);
- sync_global_to_guest(vm, vcpu_stop);
+ WRITE_AND_SYNC_TO_GUEST(vm, vcpu_stop, false);
/*
* Sync the number of writes performed before verification, the
diff --git a/tools/testing/selftests/kvm/include/kvm_syscalls.h b/tools/testing/selftests/kvm/include/kvm_syscalls.h
index 6cb3bed29b81..5dae6143ddb0 100644
--- a/tools/testing/selftests/kvm/include/kvm_syscalls.h
+++ b/tools/testing/selftests/kvm/include/kvm_syscalls.h
@@ -12,6 +12,7 @@
#include <sys/mman.h>
#include <sys/syscall.h>
+#include <sched.h>
#include <test_util.h>
#define MAP_ARGS0(m,...)
@@ -83,11 +84,17 @@ static inline int kvm_dup(int fd)
return new_fd;
}
+static inline pid_t kvm_gettid(void)
+{
+ return syscall(__NR_gettid);
+}
+
__KVM_SYSCALL_DEFINE(munmap, 2, void *, mem, size_t, size);
__KVM_SYSCALL_DEFINE(close, 1, int, fd);
__KVM_SYSCALL_DEFINE(fallocate, 4, int, fd, int, mode, loff_t, offset, loff_t, len);
__KVM_SYSCALL_DEFINE(ftruncate, 2, unsigned int, fd, off_t, length);
__KVM_SYSCALL_DEFINE(madvise, 3, void *, addr, size_t, length, int, advice);
+__KVM_SYSCALL_DEFINE(sched_getaffinity, 3, pid_t, pid, size_t, cpusetsize, cpu_set_t *, mask);
#define kvm_free_fd(fd) \
do { \
diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index 04a910164a29..b39e713c30a4 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -1094,6 +1094,8 @@ static inline void pin_task_to_cpu(pthread_t task, int cpu)
TEST_ASSERT(!r, "Failed to set thread affinity to pCPU '%u'", cpu);
}
+void pin_task_to_random_cpu(pthread_t task, cpu_set_t *possible_cpus);
+
static inline int pin_task_to_any_cpu(pthread_t task)
{
int cpu = sched_getcpu();
@@ -1138,6 +1140,16 @@ vm_adjust_num_guest_pages(enum vm_guest_mode mode, unsigned int num_guest_pages)
memcpy(&(g), _p, sizeof(g)); \
})
+#define SYNC_FROM_GUEST_AND_READ(_vm, _variable) ({ \
+ sync_global_from_guest(_vm, _variable); \
+ READ_ONCE(_variable); \
+})
+
+#define WRITE_AND_SYNC_TO_GUEST(_vm, _variable, _value) do { \
+ WRITE_ONCE(_variable, _value); \
+ sync_global_to_guest(_vm, _variable); \
+} while (0)
+
/*
* Write a global value, but only in the VM's (guest's) domain. Primarily used
* for "globals" that hold per-VM values (VMs always duplicate code and global
diff --git a/tools/testing/selftests/kvm/include/proc_util.h b/tools/testing/selftests/kvm/include/proc_util.h
new file mode 100644
index 000000000000..d1ddc967d11d
--- /dev/null
+++ b/tools/testing/selftests/kvm/include/proc_util.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef SELFTEST_KVM_PROC_UTIL_H
+#define SELFTEST_KVM_PROC_UTIL_H
+
+#include <stdint.h>
+
+unsigned int vfio_msix_to_host_irq(const char *vfio_device_bdf, int msix);
+
+void proc_irq_set_smp_affinity(unsigned int irq, int cpu);
+
+#endif /* SELFTEST_KVM_PROC_UTIL_H */
diff --git a/tools/testing/selftests/kvm/include/test_util.h b/tools/testing/selftests/kvm/include/test_util.h
index a56271c237ae..d64c8a228207 100644
--- a/tools/testing/selftests/kvm/include/test_util.h
+++ b/tools/testing/selftests/kvm/include/test_util.h
@@ -108,32 +108,35 @@ struct timespec timespec_sub(struct timespec ts1, struct timespec ts2);
struct timespec timespec_elapsed(struct timespec start);
struct timespec timespec_div(struct timespec ts, int divisor);
-struct guest_random_state {
+struct kvm_random_state {
u32 seed;
};
-extern u32 guest_random_seed;
-extern struct guest_random_state guest_rng;
+extern u32 kvm_random_seed;
+extern struct kvm_random_state kvm_rng;
-struct guest_random_state new_guest_random_state(u32 seed);
-u32 guest_random_u32(struct guest_random_state *state);
+struct kvm_random_state new_kvm_random_state(u32 seed);
+u32 kvm_random_u32(struct kvm_random_state *state);
-static inline bool __guest_random_bool(struct guest_random_state *state,
+static inline bool __kvm_random_bool(struct kvm_random_state *state,
u8 percent)
{
- return (guest_random_u32(state) % 100) < percent;
+ return (kvm_random_u32(state) % 100) < percent;
}
-static inline bool guest_random_bool(struct guest_random_state *state)
+static inline bool kvm_random_bool(struct kvm_random_state *state)
{
- return __guest_random_bool(state, 50);
+ return __kvm_random_bool(state, 50);
}
-static inline u64 guest_random_u64(struct guest_random_state *state)
+static inline u64 kvm_random_u64(struct kvm_random_state *state)
{
- return ((u64)guest_random_u32(state) << 32) | guest_random_u32(state);
+ return ((u64)kvm_random_u32(state) << 32) | kvm_random_u32(state);
}
+u64 kvm_random_u64_in_range(struct kvm_random_state *state, u64 min,
+ u64 max);
+
enum vm_mem_backing_src_type {
VM_MEM_SRC_ANONYMOUS,
VM_MEM_SRC_ANONYMOUS_THP,
diff --git a/tools/testing/selftests/kvm/include/x86/kvm_util_arch.h b/tools/testing/selftests/kvm/include/x86/kvm_util_arch.h
index c33ab6e04171..6904dbda79f9 100644
--- a/tools/testing/selftests/kvm/include/x86/kvm_util_arch.h
+++ b/tools/testing/selftests/kvm/include/x86/kvm_util_arch.h
@@ -55,9 +55,9 @@ static inline bool __vm_arch_has_protected_memory(struct kvm_vm_arch *arch)
do { \
const typeof(mem) val = (__val); \
\
- if (!is_forced_emulation_enabled || guest_random_bool(&guest_rng)) { \
+ if (!is_forced_emulation_enabled || kvm_random_bool(&kvm_rng)) { \
(mem) = val; \
- } else if (guest_random_bool(&guest_rng)) { \
+ } else if (kvm_random_bool(&kvm_rng)) { \
__asm__ __volatile__(KVM_FEP "mov %1, %0" \
: "+m" (mem) \
: "r" (val) : "memory"); \
diff --git a/tools/testing/selftests/kvm/irq_test.c b/tools/testing/selftests/kvm/irq_test.c
new file mode 100644
index 000000000000..240f6f0fdbe4
--- /dev/null
+++ b/tools/testing/selftests/kvm/irq_test.c
@@ -0,0 +1,362 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "kvm_util.h"
+#include "test_util.h"
+#include "apic.h"
+#include "processor.h"
+#include "proc_util.h"
+
+#include <libvfio.h>
+#include <linux/sizes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <sys/eventfd.h>
+#include <sys/sysinfo.h>
+
+static u64 timeout_ns = 2ULL * 1000 * 1000 * 1000;
+static bool guest_ready_for_irqs[KVM_MAX_VCPUS];
+static bool guest_received_irq[KVM_MAX_VCPUS];
+static bool guest_received_nmi[KVM_MAX_VCPUS];
+static bool x2apic = true;
+static bool irq_affinity;
+static bool done;
+
+#define GUEST_RECEIVED_IRQ(__vcpu) \
+ SYNC_FROM_GUEST_AND_READ((__vcpu)->vm, guest_received_irq[(__vcpu)->id])
+#define GUEST_RECEIVED_NMI(__vcpu) \
+ SYNC_FROM_GUEST_AND_READ((__vcpu)->vm, guest_received_nmi[(__vcpu)->id])
+
+#define GUEST_RECEIVED_INTERRUPT(__vcpu, __nmi) \
+ ((__nmi) ? GUEST_RECEIVED_NMI(__vcpu) : GUEST_RECEIVED_IRQ(__vcpu))
+
+static u32 guest_get_vcpu_id(void)
+{
+ if (x2apic)
+ return x2apic_read_reg(APIC_ID);
+ else
+ return xapic_read_reg(APIC_ID) >> 24;
+}
+
+static void guest_irq_handler(struct ex_regs *regs)
+{
+ WRITE_ONCE(guest_received_irq[guest_get_vcpu_id()], true);
+
+ if (x2apic)
+ x2apic_write_reg(APIC_EOI, 0);
+ else
+ xapic_write_reg(APIC_EOI, 0);
+}
+
+static void guest_nmi_handler(struct ex_regs *regs)
+{
+ WRITE_ONCE(guest_received_nmi[guest_get_vcpu_id()], true);
+}
+
+static void guest_code(void)
+{
+ if (x2apic)
+ x2apic_enable();
+ else
+ xapic_enable();
+
+ sti_nop();
+
+ WRITE_ONCE(guest_ready_for_irqs[guest_get_vcpu_id()], true);
+
+ while (!READ_ONCE(done))
+ cpu_relax();
+
+ GUEST_DONE();
+}
+
+static void *vcpu_thread_main(void *arg)
+{
+ struct kvm_vcpu *vcpu = arg;
+ struct ucall uc;
+
+ vcpu_run(vcpu);
+ TEST_ASSERT_EQ(UCALL_DONE, get_ucall(vcpu, &uc));
+
+ return NULL;
+}
+
+static int vfio_setup_msi(struct vfio_pci_device *device)
+{
+ const int flags = MAP_SHARED | MAP_ANONYMOUS;
+ const int prot = PROT_READ | PROT_WRITE;
+ struct iova_allocator *allocator;
+ struct dma_region *region;
+
+ /* Sanity check that the device+driver can actually send MSIs. */
+ TEST_REQUIRE(device->driver.ops);
+ TEST_REQUIRE(device->driver.ops->send_msi);
+
+ /*
+ * Set up a DMA-able region for the driver to use. Very few devices
+ * provide a way to arbitrarily send interrupts (MSIs), e.g. by writing
+ * an MMIO register. Instead, most devices send MSIs when an action is
+ * completed, and practically all actions involve DMA of some form.
+ */
+ allocator = iova_allocator_init(device->iommu);
+
+ region = &device->driver.region;
+ region->size = SZ_2M;
+ region->iova = iova_allocator_alloc(allocator, region->size);
+ region->vaddr = kvm_mmap(region->size, prot, flags, -1);
+ TEST_ASSERT(region->vaddr != MAP_FAILED, "mmap() failed\n");
+ iommu_map(device->iommu, region);
+
+ iova_allocator_cleanup(allocator);
+
+ vfio_pci_driver_init(device);
+
+ return device->driver.msi;
+}
+
+static void trigger_interrupt(struct vfio_pci_device *device, int eventfd)
+{
+ if (device)
+ vfio_pci_driver_send_msi(device);
+ else
+ eventfd_write(eventfd, 1);
+}
+
+
+static void kvm_route_msi(struct kvm_vm *vm, u32 gsi, struct kvm_vcpu *vcpu,
+ u8 vector, bool use_nmi)
+{
+ struct {
+ struct kvm_irq_routing header;
+ struct kvm_irq_routing_entry entry;
+ } routing = {
+ .header.nr = 1,
+ .entry = {
+ .gsi = gsi,
+ .type = KVM_IRQ_ROUTING_MSI,
+ .u.msi.address_lo = 0xFEE00000 | (vcpu->id & GENMASK(7, 0)) << 12,
+ .u.msi.address_hi = vcpu->id & GENMASK(31, 8),
+ .u.msi.data = use_nmi ? NMI_VECTOR | (4 << 8) : vector,
+ },
+ };
+
+ vm_ioctl(vm, KVM_SET_GSI_ROUTING, &routing.header);
+}
+
+static void kvm_set_empty_gsi_routing(struct kvm_vm *vm)
+{
+ struct kvm_irq_routing routing = {};
+
+ vm_ioctl(vm, KVM_SET_GSI_ROUTING, &routing);
+}
+
+static const char *probe_iommu_type(void)
+{
+ int io_fd;
+
+ io_fd = open("/dev/iommu", O_RDONLY);
+ if (io_fd >= 0) {
+ close(io_fd);
+ return MODE_IOMMUFD;
+ }
+
+ io_fd = __open_path_or_exit("/dev/vfio/vfio", O_RDONLY,
+ "Is VFIO (or IOMMUFD) loaded and enabled?");
+ close(io_fd);
+ return MODE_VFIO_TYPE1_IOMMU;
+}
+
+static void help(const char *name)
+{
+ printf("Usage: %s [-a] [-d <segment:bus:device.function>] [-e] [-h] [-i nr_irqs] [-m] [-n] [-t iommu_type] [-v nr_vcpus] [-x]\n", name);
+ printf("\n");
+ printf("Tests KVM interrupt routing and delivery via irqfd.\n");
+ printf("-a Affine the device's host IRQ to a random physical CPU\n");
+ printf("-d Use a VFIO device to send MSI-X interrupts instead of manually signaling the eventfd\n");
+ printf("-e Set empty GSI routing in-between some interrupts\n");
+ printf("-i The number of IRQs to generate during the test\n");
+ printf("-m Pin target vCPU to random physical CPU before triggering interrupt\n");
+ printf("-n Deliver 50 percent of IRQs as non-maskable interrupts\n");
+ printf("-t Override the IOMMU type to use (vfio_type1_iommu or iommufd)\n");
+ printf("-v Number of vCPUS to run\n");
+ printf("-x Use xAPIC mode instead of x2APIC mode in the guest\n");
+ printf("\n");
+ exit(KSFT_FAIL);
+}
+
+int main(int argc, char **argv)
+{
+ /*
+ * Pick a random vector and a random GSI to use for device IRQ.
+ *
+ * Pick an IRQ vector in range [32, UINT8_MAX]. Min value is 32 because
+ * Linux/x86 reserves vectors 0-31 for exceptions and architecture
+ * defined NMIs and interrupts.
+ *
+ * Pick a GSI in range [24, KVM_MAX_IRQ_ROUTES - 1]. The min value is 24
+ * because KVM reserves GSIs 0-15 for legacy ISA IRQs and 16-23 only go
+ * to the IOAPIC. The max is KVM_MAX_IRQ_ROUTES - 1, because
+ * KVM_MAX_IRQ_ROUTES is exclusive.
+ */
+ u32 gsi = kvm_random_u64_in_range(&kvm_rng, 24, KVM_MAX_IRQ_ROUTES - 1);
+ u8 vector = kvm_random_u64_in_range(&kvm_rng, 32, UINT8_MAX);
+
+ pthread_t vcpu_threads[KVM_MAX_VCPUS];
+ struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];
+ struct vfio_pci_device *device = NULL;
+ int nr_irqs = 1000, nr_vcpus = 1;
+ bool set_empty_routing = false;
+ const char *device_bdf = NULL;
+ const char *iommu_type = NULL;
+ int i, j, c, msix, eventfd;
+ bool migrate_vcpus = false;
+ cpu_set_t available_cpus;
+ bool use_nmi = false;
+ struct iommu *iommu;
+ struct kvm_vm *vm;
+ int irq, irq_cpu;
+
+ while ((c = getopt(argc, argv, "ad:ehi:mnt:v:x")) != -1) {
+ switch (c) {
+ case 'a':
+ irq_affinity = true;
+ break;
+ case 'd':
+ device_bdf = optarg;
+ break;
+ case 'e':
+ set_empty_routing = true;
+ break;
+ case 'i':
+ nr_irqs = atoi_positive("Number of IRQs", optarg);
+ break;
+ case 'm':
+ migrate_vcpus = true;
+ break;
+ case 'n':
+ use_nmi = true;
+ break;
+ case 't':
+ iommu_type = optarg;
+ break;
+ case 'v':
+ nr_vcpus = atoi_positive("Number of vCPUS", optarg);
+ TEST_ASSERT(nr_vcpus <= KVM_MAX_VCPUS,
+ "KVM selftests support at most %u vCPUs", KVM_MAX_VCPUS);
+ break;
+ case 'x':
+ x2apic = false;
+ break;
+ case 'h':
+ default:
+ help(argv[0]);
+ }
+ }
+
+ TEST_REQUIRE(kvm_arch_has_default_irqchip());
+
+ vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus);
+ vm_enable_cap(vm, KVM_CAP_X2APIC_API, KVM_X2APIC_API_USE_32BIT_IDS |
+ KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK);
+
+ vm_install_exception_handler(vm, vector, guest_irq_handler);
+ vm_install_exception_handler(vm, NMI_VECTOR, guest_nmi_handler);
+
+ if (!x2apic) {
+ TEST_ASSERT(nr_vcpus < 256, "xAPIC can only target IDs [0-254] (255 vCPUs)");
+ virt_pg_map(vm, APIC_DEFAULT_GPA, APIC_DEFAULT_GPA);
+ }
+
+ if (device_bdf) {
+ if (!iommu_type)
+ iommu_type = probe_iommu_type();
+ iommu = iommu_init(iommu_type);
+ device = vfio_pci_device_init(device_bdf, iommu);
+ msix = vfio_setup_msi(device);
+ irq = vfio_msix_to_host_irq(device_bdf, msix);
+ eventfd = device->msi_eventfds[msix];
+ printf("Using device %s MSI-X[%d] (IRQ-%u)\n", device_bdf, msix,
+ irq);
+ } else {
+ TEST_ASSERT(!irq_affinity,
+ "Setting IRQ affinity (-a) requires a backing device (-d)");
+
+ eventfd = kvm_new_eventfd();
+ irq = -1;
+ }
+
+ pr_info("Injecting interrupts for GSI %d (guest vector 0x%x) %d times\n",
+ gsi, vector, nr_irqs);
+
+ kvm_assign_irqfd(vm, gsi, eventfd);
+
+ sync_global_to_guest(vm, x2apic);
+
+ if (migrate_vcpus)
+ kvm_sched_getaffinity(0, sizeof(available_cpus), &available_cpus);
+
+ for (i = 0; i < nr_vcpus; i++)
+ pthread_create(&vcpu_threads[i], NULL, vcpu_thread_main, vcpus[i]);
+
+ for (i = 0; i < nr_vcpus; i++) {
+ struct kvm_vcpu *vcpu = vcpus[i];
+
+ while (!SYNC_FROM_GUEST_AND_READ(vm, guest_ready_for_irqs[vcpu->id]))
+ continue;
+ }
+
+ irq_cpu = -1;
+
+ for (i = 0; i < nr_irqs; i++) {
+ const bool do_set_empty_routing = set_empty_routing && (i & BIT(3));
+ const bool do_use_nmi = use_nmi && (i & BIT(2));
+ struct kvm_vcpu *vcpu = vcpus[i % nr_vcpus];
+ struct timespec start;
+
+ if (do_set_empty_routing)
+ kvm_set_empty_gsi_routing(vm);
+
+ kvm_route_msi(vm, gsi, vcpu, vector, do_use_nmi);
+
+ if (irq_affinity) {
+ irq_cpu = kvm_random_u64(&kvm_rng) % get_nprocs();
+ proc_irq_set_smp_affinity(irq, irq_cpu);
+ }
+
+ if (migrate_vcpus)
+ pin_task_to_random_cpu(vcpu_threads[i % nr_vcpus], &available_cpus);
+
+ for (j = 0; j < nr_vcpus; j++) {
+ TEST_ASSERT(!GUEST_RECEIVED_IRQ(vcpus[j]),
+ "IRQ flag for vCPU %d not clear prior to test",
+ vcpus[j]->id);
+ TEST_ASSERT(!GUEST_RECEIVED_NMI(vcpus[j]),
+ "NMI flag for vCPU %d not clear prior to test",
+ vcpus[j]->id);
+ }
+
+ trigger_interrupt(device, eventfd);
+
+ clock_gettime(CLOCK_MONOTONIC, &start);
+ while (!GUEST_RECEIVED_INTERRUPT(vcpu, do_use_nmi) &&
+ timespec_to_ns(timespec_elapsed(start)) <= timeout_ns)
+ cpu_relax();
+
+ TEST_ASSERT(GUEST_RECEIVED_INTERRUPT(vcpu, do_use_nmi),
+ "vCPU %d timed out waiting for %s (vector 0x%x) from GSI %d (via CPU %d)\n",
+ vcpu->id, do_use_nmi ? "NMI" : "IRQ",
+ do_use_nmi ? NMI_VECTOR : vector, gsi, irq_cpu);
+
+ if (do_use_nmi)
+ WRITE_AND_SYNC_TO_GUEST(vm, guest_received_nmi[vcpu->id], false);
+ else
+ WRITE_AND_SYNC_TO_GUEST(vm, guest_received_irq[vcpu->id], false);
+ }
+
+ WRITE_AND_SYNC_TO_GUEST(vm, done, true);
+
+ for (i = 0; i < nr_vcpus; i++)
+ pthread_join(vcpu_threads[i], NULL);
+
+ return 0;
+}
diff --git a/tools/testing/selftests/kvm/lib/assert.c b/tools/testing/selftests/kvm/lib/assert.c
index 8be0d09ecf0f..1d72dcdfce3b 100644
--- a/tools/testing/selftests/kvm/lib/assert.c
+++ b/tools/testing/selftests/kvm/lib/assert.c
@@ -10,6 +10,7 @@
#include <sys/syscall.h>
#include "kselftest.h"
+#include "kvm_syscalls.h"
#ifdef __GLIBC__
#include <execinfo.h>
@@ -64,11 +65,6 @@ static void test_dump_stack(void)
static void test_dump_stack(void) {}
#endif
-static pid_t _gettid(void)
-{
- return syscall(SYS_gettid);
-}
-
void __attribute__((noinline))
test_assert(bool exp, const char *exp_str,
const char *file, unsigned int line, const char *fmt, ...)
@@ -81,7 +77,7 @@ test_assert(bool exp, const char *exp_str,
fprintf(stderr, "==== Test Assertion Failure ====\n"
" %s:%u: %s\n"
" pid=%d tid=%d errno=%d - %s\n",
- file, line, exp_str, getpid(), _gettid(),
+ file, line, exp_str, getpid(), kvm_gettid(),
errno, strerror(errno));
test_dump_stack();
if (fmt) {
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index 195f3fdae1e3..3794575d2ca0 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -15,14 +15,22 @@
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <time.h>
#include <unistd.h>
#include <linux/kernel.h>
#define KVM_UTIL_MIN_PFN 2
-u32 guest_random_seed;
-struct guest_random_state guest_rng;
-static u32 last_guest_seed;
+u32 kvm_random_seed;
+struct kvm_random_state kvm_rng;
+static u32 last_kvm_seed;
+
+static void kvm_seed_rng(u32 seed)
+{
+ kvm_random_seed = last_kvm_seed = seed;
+ pr_info("Random seed: 0x%x\n", kvm_random_seed);
+ kvm_rng = new_kvm_random_state(kvm_random_seed);
+}
static size_t vcpu_mmap_sz(void);
@@ -515,12 +523,10 @@ struct kvm_vm *__vm_create(struct vm_shape shape, u32 nr_runnable_vcpus,
slot0 = memslot2region(vm, 0);
ucall_init(vm, slot0->region.guest_phys_addr + slot0->region.memory_size);
- if (guest_random_seed != last_guest_seed) {
- pr_info("Random seed: 0x%x\n", guest_random_seed);
- last_guest_seed = guest_random_seed;
- }
- guest_rng = new_guest_random_state(guest_random_seed);
- sync_global_to_guest(vm, guest_rng);
+ if (kvm_random_seed != last_kvm_seed)
+ kvm_seed_rng(kvm_random_seed);
+
+ sync_global_to_guest(vm, kvm_rng);
kvm_arch_vm_post_create(vm, nr_runnable_vcpus);
@@ -662,19 +668,39 @@ void kvm_print_vcpu_pinning_help(void)
" (default: no pinning)\n", name, name);
}
+void pin_task_to_random_cpu(pthread_t task, cpu_set_t *possible_cpus)
+{
+ int target_idx;
+ int nr_cpus;
+ int cpu;
+
+ nr_cpus = CPU_COUNT(possible_cpus);
+ TEST_ASSERT(nr_cpus > 0, "No CPUs available in possible_cpus");
+
+ target_idx = kvm_random_u64(&kvm_rng) % nr_cpus;
+
+ for (cpu = 0; cpu < CPU_SETSIZE; cpu++) {
+ if (CPU_ISSET(cpu, possible_cpus) && target_idx-- == 0) {
+ pin_task_to_cpu(task, cpu);
+ return;
+ }
+ }
+
+ TEST_FAIL("Failed to find random CPU in possible_cpus");
+}
+
void kvm_parse_vcpu_pinning(const char *pcpus_string, u32 vcpu_to_pcpu[],
int nr_vcpus)
{
cpu_set_t allowed_mask;
char *cpu, *cpu_list;
char delim[2] = ",";
- int i, r;
+ int i;
cpu_list = strdup(pcpus_string);
TEST_ASSERT(cpu_list, "strdup() allocation failed.");
- r = sched_getaffinity(0, sizeof(allowed_mask), &allowed_mask);
- TEST_ASSERT(!r, "sched_getaffinity() failed");
+ kvm_sched_getaffinity(0, sizeof(allowed_mask), &allowed_mask);
cpu = strtok(cpu_list, delim);
@@ -2279,8 +2305,8 @@ void __attribute((constructor)) kvm_selftest_init(void)
sigaction(SIGILL, &sig_sa, NULL);
sigaction(SIGFPE, &sig_sa, NULL);
- guest_random_seed = last_guest_seed = random();
- pr_info("Random seed: 0x%x\n", guest_random_seed);
+ srandom(time(0));
+ kvm_seed_rng(random());
kvm_selftest_arch_init();
}
diff --git a/tools/testing/selftests/kvm/lib/memstress.c b/tools/testing/selftests/kvm/lib/memstress.c
index 6dcd15910a06..3599b75d97c9 100644
--- a/tools/testing/selftests/kvm/lib/memstress.c
+++ b/tools/testing/selftests/kvm/lib/memstress.c
@@ -48,14 +48,14 @@ void memstress_guest_code(u32 vcpu_idx)
{
struct memstress_args *args = &memstress_args;
struct memstress_vcpu_args *vcpu_args = &args->vcpu_args[vcpu_idx];
- struct guest_random_state rand_state;
+ struct kvm_random_state rand_state;
gva_t gva;
u64 pages;
u64 addr;
u64 page;
int i;
- rand_state = new_guest_random_state(guest_random_seed + vcpu_idx);
+ rand_state = new_kvm_random_state(kvm_random_seed + vcpu_idx);
gva = vcpu_args->gva;
pages = vcpu_args->pages;
@@ -69,13 +69,13 @@ void memstress_guest_code(u32 vcpu_idx)
for (i = 0; i < pages; i++) {
if (args->random_access)
- page = guest_random_u32(&rand_state) % pages;
+ page = kvm_random_u32(&rand_state) % pages;
else
page = i;
addr = gva + (page * args->guest_page_size);
- if (__guest_random_bool(&rand_state, args->write_percent))
+ if (__kvm_random_bool(&rand_state, args->write_percent))
*(u64 *)addr = 0x0123456789ABCDEF;
else
READ_ONCE(*(u64 *)addr);
diff --git a/tools/testing/selftests/kvm/lib/proc_util.c b/tools/testing/selftests/kvm/lib/proc_util.c
new file mode 100644
index 000000000000..3960b3841d63
--- /dev/null
+++ b/tools/testing/selftests/kvm/lib/proc_util.c
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "kvm_util.h"
+#include "test_util.h"
+#include "proc_util.h"
+
+static FILE *open_proc_interrupts(void)
+{
+ FILE *fp;
+
+ fp = fopen("/proc/interrupts", "r");
+ TEST_ASSERT(fp, "fopen(/proc/interrupts) failed");
+
+ return fp;
+}
+
+unsigned int vfio_msix_to_host_irq(const char *device_bdf, int msix)
+{
+ char search_string[64];
+ char line[4096];
+ int irq = -1;
+ FILE *fp;
+
+ fp = open_proc_interrupts();
+
+ snprintf(search_string, sizeof(search_string), "vfio-msix[%d]", msix);
+
+ while (fgets(line, sizeof(line), fp)) {
+ if (strstr(line, device_bdf) && strstr(line, search_string)) {
+ TEST_ASSERT_EQ(1, sscanf(line, "%d:", &irq));
+ break;
+ }
+ }
+
+ fclose(fp);
+
+ TEST_ASSERT(irq != -1, "Failed to locate IRQ for %s %s", device_bdf,
+ search_string);
+ return (unsigned int)irq;
+}
+
+void proc_irq_set_smp_affinity(unsigned int irq, int cpu)
+{
+ char path[PATH_MAX];
+ int r, fd;
+
+ snprintf(path, sizeof(path), "/proc/irq/%u/smp_affinity_list", irq);
+ fd = open(path, O_RDWR);
+ TEST_ASSERT(fd >= 0, "Failed to open %s", path);
+
+ r = dprintf(fd, "%d\n", cpu);
+ TEST_ASSERT(r > 0, "Failed to affinitize IRQ-%u to CPU %d", irq, cpu);
+
+ kvm_close(fd);
+}
diff --git a/tools/testing/selftests/kvm/lib/test_util.c b/tools/testing/selftests/kvm/lib/test_util.c
index bab1bd2b775b..6b00ab11f3c0 100644
--- a/tools/testing/selftests/kvm/lib/test_util.c
+++ b/tools/testing/selftests/kvm/lib/test_util.c
@@ -17,6 +17,7 @@
#include "linux/kernel.h"
#include "test_util.h"
+#include "kvm_syscalls.h"
sigjmp_buf expect_sigbus_jmpbuf;
@@ -30,18 +31,36 @@ void __attribute__((used)) expect_sigbus_handler(int signum)
* Park-Miller LCG using standard constants.
*/
-struct guest_random_state new_guest_random_state(u32 seed)
+struct kvm_random_state new_kvm_random_state(u32 seed)
{
- struct guest_random_state s = {.seed = seed};
+ struct kvm_random_state s = {.seed = seed};
return s;
}
-u32 guest_random_u32(struct guest_random_state *state)
+u32 kvm_random_u32(struct kvm_random_state *state)
{
state->seed = (u64)state->seed * 48271 % ((u32)(1 << 31) - 1);
return state->seed;
}
+/* Returns a random u64 in the inclusive range [min, max] */
+u64 kvm_random_u64_in_range(struct kvm_random_state *state, u64 min,
+ u64 max)
+{
+ u64 value;
+ u64 range;
+
+ TEST_ASSERT(min <= max, "PEBKAC, min = 0x%lx, max = 0x%lx", min, max);
+
+ value = kvm_random_u64(state);
+
+ range = max - min;
+ if (range == ULLONG_MAX)
+ return value;
+
+ return min + (value % (range + 1));
+}
+
/*
* Parses "[0-9]+[kmgt]?".
*/
@@ -377,7 +396,7 @@ long get_run_delay(void)
long val[2];
FILE *fp;
- sprintf(path, "/proc/%ld/schedstat", syscall(SYS_gettid));
+ sprintf(path, "/proc/%ld/schedstat", (long)kvm_gettid());
fp = fopen(path, "r");
/* Return MIN_RUN_DELAY_NS upon failure just to be safe */
if (fscanf(fp, "%ld %ld ", &val[0], &val[1]) < 2)
diff --git a/tools/testing/selftests/kvm/mmu_stress_test.c b/tools/testing/selftests/kvm/mmu_stress_test.c
index 54d281419d31..3d5f33a63b2b 100644
--- a/tools/testing/selftests/kvm/mmu_stress_test.c
+++ b/tools/testing/selftests/kvm/mmu_stress_test.c
@@ -155,10 +155,8 @@ static void *vcpu_worker(void *data)
"Expected EFAULT on write to RO memory, got r = %d, errno = %d", r, errno);
atomic_inc(&nr_ro_faults);
- if (atomic_read(&nr_ro_faults) == nr_vcpus) {
- WRITE_ONCE(all_vcpus_hit_ro_fault, true);
- sync_global_to_guest(vm, all_vcpus_hit_ro_fault);
- }
+ if (atomic_read(&nr_ro_faults) == nr_vcpus)
+ WRITE_AND_SYNC_TO_GUEST(vm, all_vcpus_hit_ro_fault, true);
#if defined(__x86_64__) || defined(__aarch64__)
/*
@@ -257,11 +255,7 @@ static void rendezvous_with_vcpus(struct timespec *time, const char *name)
static void calc_default_nr_vcpus(void)
{
cpu_set_t possible_mask;
- int r;
-
- r = sched_getaffinity(0, sizeof(possible_mask), &possible_mask);
- TEST_ASSERT(!r, "sched_getaffinity failed, errno = %d (%s)",
- errno, strerror(errno));
+ kvm_sched_getaffinity(0, sizeof(possible_mask), &possible_mask);
nr_vcpus = CPU_COUNT(&possible_mask);
TEST_ASSERT(nr_vcpus > 0, "Uh, no CPUs?");
@@ -383,8 +377,7 @@ int main(int argc, char *argv[])
rendezvous_with_vcpus(&time_run2, "run 2");
mprotect(mem, slot_size, PROT_READ);
- mprotect_ro_done = true;
- sync_global_to_guest(vm, mprotect_ro_done);
+ WRITE_AND_SYNC_TO_GUEST(vm, mprotect_ro_done, true);
rendezvous_with_vcpus(&time_ro, "mprotect RO");
mprotect(mem, slot_size, PROT_READ | PROT_WRITE);
diff --git a/tools/testing/selftests/kvm/rseq_test.c b/tools/testing/selftests/kvm/rseq_test.c
index f80ad6b47d16..557e393c223b 100644
--- a/tools/testing/selftests/kvm/rseq_test.c
+++ b/tools/testing/selftests/kvm/rseq_test.c
@@ -226,9 +226,7 @@ int main(int argc, char *argv[])
}
}
- r = sched_getaffinity(0, sizeof(possible_mask), &possible_mask);
- TEST_ASSERT(!r, "sched_getaffinity failed, errno = %d (%s)", errno,
- strerror(errno));
+ kvm_sched_getaffinity(0, sizeof(possible_mask), &possible_mask);
calc_min_max_cpu();
@@ -244,7 +242,7 @@ int main(int argc, char *argv[])
vm = vm_create_with_one_vcpu(&vcpu, guest_code);
pthread_create(&migration_thread, NULL, migration_worker,
- (void *)(unsigned long)syscall(SYS_gettid));
+ (void *)(unsigned long)kvm_gettid());
if (latency >= 0) {
/*
diff --git a/tools/testing/selftests/kvm/steal_time.c b/tools/testing/selftests/kvm/steal_time.c
index 76fcdd1fd3cb..2de87549fcc0 100644
--- a/tools/testing/selftests/kvm/steal_time.c
+++ b/tools/testing/selftests/kvm/steal_time.c
@@ -70,8 +70,8 @@ static bool is_steal_time_supported(struct kvm_vcpu *vcpu)
static void steal_time_init(struct kvm_vcpu *vcpu, u32 i)
{
/* ST_GPA_BASE is identity mapped */
- st_gva[i] = (void *)(ST_GPA_BASE + i * STEAL_TIME_SIZE);
- sync_global_to_guest(vcpu->vm, st_gva[i]);
+ WRITE_AND_SYNC_TO_GUEST(vcpu->vm, st_gva[i],
+ (void *)(ST_GPA_BASE + i * STEAL_TIME_SIZE));
vcpu_set_msr(vcpu, MSR_KVM_STEAL_TIME, (ulong)st_gva[i] | KVM_MSR_ENABLED);
}
@@ -187,8 +187,7 @@ static void steal_time_init(struct kvm_vcpu *vcpu, u32 i)
};
/* ST_GPA_BASE is identity mapped */
- st_gva[i] = (void *)(ST_GPA_BASE + i * STEAL_TIME_SIZE);
- sync_global_to_guest(vm, st_gva[i]);
+ WRITE_AND_SYNC_TO_GUEST(vm, st_gva[i], (void *)(ST_GPA_BASE + i * STEAL_TIME_SIZE));
st_ipa = (ulong)st_gva[i];
vcpu_ioctl(vcpu, KVM_SET_DEVICE_ATTR, &dev);
@@ -310,10 +309,8 @@ static bool is_steal_time_supported(struct kvm_vcpu *vcpu)
static void steal_time_init(struct kvm_vcpu *vcpu, u32 i)
{
/* ST_GPA_BASE is identity mapped */
- st_gva[i] = (void *)(ST_GPA_BASE + i * STEAL_TIME_SIZE);
- st_gpa[i] = addr_gva2gpa(vcpu->vm, (gva_t)st_gva[i]);
- sync_global_to_guest(vcpu->vm, st_gva[i]);
- sync_global_to_guest(vcpu->vm, st_gpa[i]);
+ WRITE_AND_SYNC_TO_GUEST(vcpu->vm, st_gva[i], (void *)(ST_GPA_BASE + i * STEAL_TIME_SIZE));
+ WRITE_AND_SYNC_TO_GUEST(vcpu->vm, st_gpa[i], addr_gva2gpa(vcpu->vm, (gva_t)st_gva[i]));
}
static void steal_time_dump(struct kvm_vm *vm, u32 vcpu_idx)
@@ -442,8 +439,7 @@ static void steal_time_init(struct kvm_vcpu *vcpu, u32 i)
};
/* ST_GPA_BASE is identity mapped */
- st_gva[i] = (void *)(ST_GPA_BASE + i * STEAL_TIME_SIZE);
- sync_global_to_guest(vm, st_gva[i]);
+ WRITE_AND_SYNC_TO_GUEST(vm, st_gva[i], (void *)(ST_GPA_BASE + i * STEAL_TIME_SIZE));
err = __vcpu_ioctl(vcpu, KVM_HAS_DEVICE_ATTR, &attr);
TEST_ASSERT(err == 0, "No PV stealtime Feature");
@@ -549,8 +545,7 @@ int main(int ac, char **av)
/* Second VCPU run, expect guest stolen time to be <= run_delay */
run_vcpu(vcpus[i]);
- sync_global_from_guest(vm, guest_stolen_time[i]);
- stolen_time = guest_stolen_time[i];
+ stolen_time = SYNC_FROM_GUEST_AND_READ(vm, guest_stolen_time[i]);
run_delay = get_run_delay();
TEST_ASSERT(stolen_time <= run_delay,
"Expected stolen time <= %ld, got %ld",
@@ -570,8 +565,7 @@ int main(int ac, char **av)
/* Run VCPU again to confirm stolen time is consistent with run_delay */
run_vcpu(vcpus[i]);
- sync_global_from_guest(vm, guest_stolen_time[i]);
- stolen_time = guest_stolen_time[i] - stolen_time;
+ stolen_time = SYNC_FROM_GUEST_AND_READ(vm, guest_stolen_time[i]) - stolen_time;
TEST_ASSERT(stolen_time >= run_delay,
"Expected stolen time >= %ld, got %ld",
run_delay, stolen_time);
diff --git a/tools/testing/selftests/kvm/x86/sev_dbg_test.c b/tools/testing/selftests/kvm/x86/sev_dbg_test.c
index a9d8e4c059f9..eaa8201b937d 100644
--- a/tools/testing/selftests/kvm/x86/sev_dbg_test.c
+++ b/tools/testing/selftests/kvm/x86/sev_dbg_test.c
@@ -34,7 +34,7 @@ static void validate_buffers(void)
static void ____test_sev_dbg(struct kvm_vm *vm, int i, int j, int nr_bytes)
{
- u8 pattern = guest_random_u32(&guest_rng);
+ u8 pattern = kvm_random_u32(&kvm_rng);
if (i + nr_bytes > BUFFER_SIZE || j + nr_bytes > BUFFER_SIZE)
return;
diff --git a/tools/testing/selftests/kvm/x86/sev_migrate_tests.c b/tools/testing/selftests/kvm/x86/sev_migrate_tests.c
index 42bc023d5193..d59abb198d86 100644
--- a/tools/testing/selftests/kvm/x86/sev_migrate_tests.c
+++ b/tools/testing/selftests/kvm/x86/sev_migrate_tests.c
@@ -313,6 +313,49 @@ out:
kvm_vm_free(vm_no_vcpu);
}
+static void test_sev_snp_migrate_reject(void)
+{
+ struct kvm_vm *src_vm, *dst_vm;
+ int ret;
+
+ src_vm = vm_create_barebones_type(KVM_X86_SNP_VM);
+ snp_vm_init(src_vm);
+ __vm_vcpu_add(src_vm, 0);
+ vm_sev_launch(src_vm, snp_default_policy(), NULL);
+
+ dst_vm = vm_create_barebones_type(KVM_X86_SNP_VM);
+ __vm_vcpu_add(dst_vm, 0);
+
+ ret = __sev_migrate_from(dst_vm, src_vm);
+ TEST_ASSERT(ret == -1 && errno == EINVAL,
+ "SNP VM migration should be rejected. ret: %d, errno: %d",
+ ret, errno);
+
+ kvm_vm_free(src_vm);
+ kvm_vm_free(dst_vm);
+}
+
+static void test_sev_snp_mirror_reject(void)
+{
+ struct kvm_vm *src_vm, *dst_vm;
+ int ret;
+
+ src_vm = vm_create_barebones_type(KVM_X86_SNP_VM);
+ snp_vm_init(src_vm);
+ __vm_vcpu_add(src_vm, 0);
+ vm_sev_launch(src_vm, snp_default_policy(), NULL);
+
+ dst_vm = aux_vm_create(false);
+
+ ret = __sev_mirror_create(dst_vm, src_vm);
+ TEST_ASSERT(ret == -1 && errno == EINVAL,
+ "SNP VM mirroring should be rejected. ret: %d, errno: %d",
+ ret, errno);
+
+ kvm_vm_free(src_vm);
+ kvm_vm_free(dst_vm);
+}
+
static void test_sev_move_copy(void)
{
struct kvm_vm *dst_vm, *dst2_vm, *dst3_vm, *sev_vm, *mirror_vm,
@@ -384,12 +427,16 @@ int main(int argc, char *argv[])
test_sev_migrate_parameters();
if (kvm_has_cap(KVM_CAP_VM_COPY_ENC_CONTEXT_FROM))
test_sev_move_copy();
+ if (kvm_cpu_has(X86_FEATURE_SEV_SNP))
+ test_sev_snp_migrate_reject();
}
if (kvm_has_cap(KVM_CAP_VM_COPY_ENC_CONTEXT_FROM)) {
test_sev_mirror(/* es= */ false);
if (have_sev_es)
test_sev_mirror(/* es= */ true);
test_sev_mirror_parameters();
+ if (kvm_cpu_has(X86_FEATURE_SEV_SNP))
+ test_sev_snp_mirror_reject();
}
return 0;
}
diff --git a/tools/testing/selftests/kvm/x86/xapic_ipi_test.c b/tools/testing/selftests/kvm/x86/xapic_ipi_test.c
index 39ce9a9369f5..3a326c5e74ca 100644
--- a/tools/testing/selftests/kvm/x86/xapic_ipi_test.c
+++ b/tools/testing/selftests/kvm/x86/xapic_ipi_test.c
@@ -17,7 +17,7 @@
* amongst the available numa nodes on the machine.
*
* Migration is a command line option. When used on non-numa machines will
- * exit with error. Test is still usefull on non-numa for testing IPIs.
+ * exit with error. Test is still useful on non-numa for testing IPIs.
*/
#include <getopt.h>
#include <pthread.h>
diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c
index 86e08aa6e0a7..e672089e9329 100644
--- a/tools/testing/selftests/landlock/fs_test.c
+++ b/tools/testing/selftests/landlock/fs_test.c
@@ -6927,7 +6927,7 @@ TEST_F_FORK(layout2_overlay, same_content_different_file)
ASSERT_EQ(0, test_open(path_entry, O_RDWR));
}
- /* Only allowes access to the merge hierarchy. */
+ /* Only allows access to the merge hierarchy. */
enforce_fs(_metadata, ACCESS_RW, layer5_merge_only);
/* Checks new accesses on lower layer. */
diff --git a/tools/testing/selftests/landlock/net_test.c b/tools/testing/selftests/landlock/net_test.c
index 2e4dc5025b04..be2eb88092fb 100644
--- a/tools/testing/selftests/landlock/net_test.c
+++ b/tools/testing/selftests/landlock/net_test.c
@@ -1284,9 +1284,11 @@ TEST_F(protocol, connect_unspec)
TEST_F(protocol, tcp_fastopen)
{
const bool restricted = variant->sandbox == TCP_SANDBOX &&
- variant->prot.type == SOCK_STREAM &&
- (variant->prot.protocol == IPPROTO_TCP || variant->prot.protocol == IPPROTO_IP) &&
- (variant->prot.domain == AF_INET || variant->prot.domain == AF_INET6);
+ variant->prot.type == SOCK_STREAM &&
+ (variant->prot.protocol == IPPROTO_TCP ||
+ variant->prot.protocol == IPPROTO_IP) &&
+ (variant->prot.domain == AF_INET ||
+ variant->prot.domain == AF_INET6);
const struct landlock_ruleset_attr ruleset_attr = {
.handled_access_net = LANDLOCK_ACCESS_NET_CONNECT_TCP,
};
@@ -1331,7 +1333,8 @@ TEST_F(protocol, tcp_fastopen)
}
/* Fast Open to a denied address. */
- ret = sendto_variant(connect_fd, &self->srv0, "A", 1, MSG_FASTOPEN);
+ ret = sendto_variant(connect_fd, &self->srv0, "A", 1,
+ MSG_FASTOPEN);
if (restricted) {
EXPECT_EQ(-EACCES, ret);
} else if (self->srv0.protocol.domain == AF_UNIX &&
diff --git a/tools/testing/selftests/landlock/scoped_signal_test.c b/tools/testing/selftests/landlock/scoped_signal_test.c
index f24f2c28f62e..2d37d0c06c06 100644
--- a/tools/testing/selftests/landlock/scoped_signal_test.c
+++ b/tools/testing/selftests/landlock/scoped_signal_test.c
@@ -249,12 +249,12 @@ TEST_F(scoped_domains, check_access_signal)
_metadata->exit_code = KSFT_FAIL;
}
-enum thread_return {
- THREAD_INVALID = 0,
- THREAD_SUCCESS = 1,
- THREAD_ERROR = 2,
- THREAD_TEST_FAILED = 3,
-};
+/* clang-format off */
+#define THREAD_INVALID ((void *)0)
+#define THREAD_SUCCESS ((void *)1)
+#define THREAD_ERROR ((void *)2)
+#define THREAD_TEST_FAILED ((void *)3)
+/* clang-format on */
static void *thread_sync(void *arg)
{
@@ -262,15 +262,15 @@ static void *thread_sync(void *arg)
char buf;
if (read(pipe_read, &buf, 1) != 1)
- return (void *)THREAD_ERROR;
+ return THREAD_ERROR;
- return (void *)THREAD_SUCCESS;
+ return THREAD_SUCCESS;
}
TEST(signal_scoping_thread_before)
{
pthread_t no_sandbox_thread;
- enum thread_return ret = THREAD_INVALID;
+ void *ret = THREAD_INVALID;
int thread_pipe[2];
drop_caps(_metadata);
@@ -285,7 +285,7 @@ TEST(signal_scoping_thread_before)
EXPECT_EQ(0, pthread_kill(no_sandbox_thread, 0));
EXPECT_EQ(1, write(thread_pipe[1], ".", 1));
- EXPECT_EQ(0, pthread_join(no_sandbox_thread, (void **)&ret));
+ EXPECT_EQ(0, pthread_join(no_sandbox_thread, &ret));
EXPECT_EQ(THREAD_SUCCESS, ret);
EXPECT_EQ(0, close(thread_pipe[0]));
@@ -295,7 +295,7 @@ TEST(signal_scoping_thread_before)
TEST(signal_scoping_thread_after)
{
pthread_t scoped_thread;
- enum thread_return ret = THREAD_INVALID;
+ void *ret = THREAD_INVALID;
int thread_pipe[2];
drop_caps(_metadata);
@@ -310,7 +310,7 @@ TEST(signal_scoping_thread_after)
EXPECT_EQ(0, pthread_kill(scoped_thread, 0));
EXPECT_EQ(1, write(thread_pipe[1], ".", 1));
- EXPECT_EQ(0, pthread_join(scoped_thread, (void **)&ret));
+ EXPECT_EQ(0, pthread_join(scoped_thread, &ret));
EXPECT_EQ(THREAD_SUCCESS, ret);
EXPECT_EQ(0, close(thread_pipe[0]));
@@ -327,20 +327,20 @@ void *thread_setuid(void *ptr)
char buf;
if (read(arg->pipe_read, &buf, 1) != 1)
- return (void *)THREAD_ERROR;
+ return THREAD_ERROR;
/* libc's setuid() should update all thread's credentials. */
if (getuid() != arg->new_uid)
- return (void *)THREAD_TEST_FAILED;
+ return THREAD_TEST_FAILED;
- return (void *)THREAD_SUCCESS;
+ return THREAD_SUCCESS;
}
TEST(signal_scoping_thread_setuid)
{
struct thread_setuid_args arg;
pthread_t no_sandbox_thread;
- enum thread_return ret = THREAD_INVALID;
+ void *ret = THREAD_INVALID;
int pipe_parent[2];
int prev_uid;
@@ -367,7 +367,7 @@ TEST(signal_scoping_thread_setuid)
EXPECT_EQ(arg.new_uid, getuid());
EXPECT_EQ(1, write(pipe_parent[1], ".", 1));
- EXPECT_EQ(0, pthread_join(no_sandbox_thread, (void **)&ret));
+ EXPECT_EQ(0, pthread_join(no_sandbox_thread, &ret));
EXPECT_EQ(THREAD_SUCCESS, ret);
clear_cap(_metadata, CAP_SETUID);
@@ -400,6 +400,24 @@ static int setup_signal_handler(int signal)
return sigaction(SIGURG, &sa, NULL);
}
+/*
+ * MSG_OOB might be disabled in the kernel via the CONFIG_AF_UNIX_OOB
+ * switch, so this function can be used for probing for its availability.
+ */
+static bool has_af_unix_oob(void)
+{
+ bool available = false;
+ int sp[2];
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) == 0) {
+ available = (send(sp[0], ".", 1, MSG_OOB) == 1);
+ close(sp[0]);
+ close(sp[1]);
+ }
+
+ return available;
+}
+
/* clang-format off */
FIXTURE(fown) {};
/* clang-format on */
@@ -462,6 +480,9 @@ TEST_F(fown, sigurg_socket)
int pipe_parent[2], pipe_child[2];
pid_t child;
+ if (!has_af_unix_oob())
+ SKIP(return, "CONFIG_AF_UNIX_OOB / MSG_OOB not available");
+
memset(&server_address, 0, sizeof(server_address));
set_unix_address(&server_address, 0);
@@ -667,20 +688,20 @@ static void *thread_setown_scoped(void *arg)
ruleset_fd =
landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
if (ruleset_fd < 0)
- return (void *)THREAD_ERROR;
+ return THREAD_ERROR;
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) ||
landlock_restrict_self(ruleset_fd, 0)) {
close(ruleset_fd);
- return (void *)THREAD_ERROR;
+ return THREAD_ERROR;
}
close(ruleset_fd);
/* Makes this process group own the SIGIO source. */
if (fcntl(fd, F_SETSIG, SIGURG) || fcntl(fd, F_SETOWN, -getpgrp()) ||
fcntl(fd, F_SETFL, O_ASYNC))
- return (void *)THREAD_ERROR;
+ return THREAD_ERROR;
- return (void *)THREAD_SUCCESS;
+ return THREAD_SUCCESS;
}
/*
@@ -702,7 +723,7 @@ TEST(sigio_to_pgid_self)
{
int trigger[2];
pthread_t thread;
- enum thread_return ret = THREAD_INVALID;
+ void *ret = THREAD_INVALID;
int i;
drop_caps(_metadata);
@@ -722,7 +743,7 @@ TEST(sigio_to_pgid_self)
*/
ASSERT_EQ(0, pthread_create(&thread, NULL, thread_setown_scoped,
&trigger[0]));
- ASSERT_EQ(0, pthread_join(thread, (void **)&ret));
+ ASSERT_EQ(0, pthread_join(thread, &ret));
ASSERT_EQ(THREAD_SUCCESS, ret);
/* Fans SIGURG out to the process group. */
diff --git a/tools/testing/selftests/liveupdate/.gitignore b/tools/testing/selftests/liveupdate/.gitignore
index 661827083ab6..cb08ddb0dfee 100644
--- a/tools/testing/selftests/liveupdate/.gitignore
+++ b/tools/testing/selftests/liveupdate/.gitignore
@@ -6,4 +6,5 @@
!*.sh
!.gitignore
!config
+!config.*
!Makefile
diff --git a/tools/testing/selftests/liveupdate/config b/tools/testing/selftests/liveupdate/config
index 91d03f9a6a39..016d009dba13 100644
--- a/tools/testing/selftests/liveupdate/config
+++ b/tools/testing/selftests/liveupdate/config
@@ -1,4 +1,5 @@
CONFIG_BLK_DEV_INITRD=y
+CONFIG_DEVTMPFS=y
CONFIG_KEXEC_FILE=y
CONFIG_KEXEC_HANDOVER=y
CONFIG_KEXEC_HANDOVER_ENABLE_DEFAULT=y
diff --git a/tools/testing/selftests/liveupdate/config.aarch64 b/tools/testing/selftests/liveupdate/config.aarch64
new file mode 100644
index 000000000000..445716403925
--- /dev/null
+++ b/tools/testing/selftests/liveupdate/config.aarch64
@@ -0,0 +1,2 @@
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
diff --git a/tools/testing/selftests/liveupdate/config.x86_64 b/tools/testing/selftests/liveupdate/config.x86_64
new file mode 100644
index 000000000000..810d9c9d213e
--- /dev/null
+++ b/tools/testing/selftests/liveupdate/config.x86_64
@@ -0,0 +1,2 @@
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
diff --git a/tools/testing/selftests/liveupdate/init.c b/tools/testing/selftests/liveupdate/init.c
new file mode 100644
index 000000000000..fb08bd58b9b9
--- /dev/null
+++ b/tools/testing/selftests/liveupdate/init.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright (c) 2025, Google LLC.
+ * Pasha Tatashin <pasha.tatashin@soleen.com>
+ */
+#include <fcntl.h>
+#include <linux/kexec.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/reboot.h>
+#include <sys/syscall.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#define COMMAND_LINE_SIZE 2048
+#define KERNEL_IMAGE "/kernel"
+#define INITRD_IMAGE "/initrd.img"
+#define TEST_BINARY "/test_binary"
+
+static int mount_filesystems(void)
+{
+ if (mount("devtmpfs", "/dev", "devtmpfs", 0, NULL) < 0) {
+ fprintf(stderr, "INIT: Warning: Failed to mount devtmpfs\n");
+ return -1;
+ }
+
+ if (mount("debugfs", "/debugfs", "debugfs", 0, NULL) < 0) {
+ fprintf(stderr, "INIT: Failed to mount debugfs\n");
+ return -1;
+ }
+
+ if (mount("proc", "/proc", "proc", 0, NULL) < 0) {
+ fprintf(stderr, "INIT: Failed to mount proc\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static long kexec_file_load(int kernel_fd, int initrd_fd,
+ unsigned long cmdline_len, const char *cmdline,
+ unsigned long flags)
+{
+ return syscall(__NR_kexec_file_load, kernel_fd, initrd_fd, cmdline_len,
+ cmdline, flags);
+}
+
+static int kexec_load(void)
+{
+ char cmdline[COMMAND_LINE_SIZE];
+ int kernel_fd, initrd_fd, err;
+ ssize_t len;
+ int fd;
+
+ fd = open("/proc/cmdline", O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "INIT: Failed to read /proc/cmdline\n");
+
+ return -1;
+ }
+
+ len = read(fd, cmdline, sizeof(cmdline) - 1);
+ close(fd);
+ if (len < 0)
+ return -1;
+
+ cmdline[len] = 0;
+ if (len > 0 && cmdline[len - 1] == '\n')
+ cmdline[len - 1] = 0;
+
+ strncat(cmdline, " luo_stage=2", sizeof(cmdline) - strlen(cmdline) - 1);
+
+ kernel_fd = open(KERNEL_IMAGE, O_RDONLY);
+ if (kernel_fd < 0) {
+ fprintf(stderr, "INIT: Failed to open kernel image\n");
+ return -1;
+ }
+
+ initrd_fd = open(INITRD_IMAGE, O_RDONLY);
+ if (initrd_fd < 0) {
+ fprintf(stderr, "INIT: Failed to open initrd image\n");
+ close(kernel_fd);
+ return -1;
+ }
+
+ err = kexec_file_load(kernel_fd, initrd_fd, strlen(cmdline) + 1,
+ cmdline, 0);
+
+ close(initrd_fd);
+ close(kernel_fd);
+
+ return err;
+}
+
+static int run_test(int stage)
+{
+ char stage_arg[32];
+ int status;
+ pid_t pid;
+
+ snprintf(stage_arg, sizeof(stage_arg), "%d", stage);
+
+ pid = fork();
+ if (pid < 0)
+ return -1;
+
+ if (!pid) {
+ char *const argv[] = {TEST_BINARY, "-s", stage_arg, NULL};
+
+ execve(TEST_BINARY, argv, NULL);
+ fprintf(stderr, "INIT: execve failed\n");
+ _exit(1);
+ }
+
+ waitpid(pid, &status, 0);
+
+ return (WIFEXITED(status) && WEXITSTATUS(status) == 0) ? 0 : -1;
+}
+
+static int get_current_stage(void)
+{
+ char cmdline[COMMAND_LINE_SIZE];
+ ssize_t len;
+ int fd;
+
+ fd = open("/proc/cmdline", O_RDONLY);
+ if (fd < 0)
+ return -1;
+
+ len = read(fd, cmdline, sizeof(cmdline) - 1);
+ close(fd);
+
+ if (len < 0)
+ return -1;
+
+ cmdline[len] = 0;
+
+ return strstr(cmdline, "luo_stage=2") ? 2 : 1;
+}
+
+int main(int argc, char *argv[])
+{
+ int current_stage;
+ int err;
+
+ if (mount_filesystems())
+ goto err_reboot;
+
+ current_stage = get_current_stage();
+ if (current_stage < 0) {
+ fprintf(stderr, "INIT: Failed to read cmdline");
+ goto err_reboot;
+ }
+
+ printf("INIT: Starting Stage %d\n", current_stage);
+
+ if (current_stage == 1 && kexec_load()) {
+ fprintf(stderr, "INIT: Failed to load kexec kernel\n");
+ goto err_reboot;
+ }
+
+ if (run_test(current_stage)) {
+ fprintf(stderr, "INIT: Test binary returned failure\n");
+ goto err_reboot;
+ }
+
+ printf("INIT: Stage %d completed successfully.\n", current_stage);
+ reboot(current_stage == 1 ? RB_KEXEC : RB_AUTOBOOT);
+
+ return 0;
+
+err_reboot:
+ reboot(RB_AUTOBOOT);
+
+ return -1;
+}
diff --git a/tools/testing/selftests/liveupdate/luo_test_utils.c b/tools/testing/selftests/liveupdate/luo_test_utils.c
index 333a3530051b..1439b2b48ed0 100644
--- a/tools/testing/selftests/liveupdate/luo_test_utils.c
+++ b/tools/testing/selftests/liveupdate/luo_test_utils.c
@@ -21,6 +21,7 @@
#include <sys/stat.h>
#include <errno.h>
#include <stdarg.h>
+#include <linux/unistd.h>
#include "luo_test_utils.h"
@@ -81,7 +82,7 @@ int luo_retrieve_session(int luo_fd, const char *name)
int create_and_preserve_memfd(int session_fd, int token, const char *data)
{
struct liveupdate_session_preserve_fd arg = { .size = sizeof(arg) };
- long page_size = sysconf(_SC_PAGE_SIZE);
+ long page_size = getpagesize();
void *map = MAP_FAILED;
int mfd = -1, ret = -1;
@@ -117,7 +118,7 @@ int restore_and_verify_memfd(int session_fd, int token,
const char *expected_data)
{
struct liveupdate_session_retrieve_fd arg = { .size = sizeof(arg) };
- long page_size = sysconf(_SC_PAGE_SIZE);
+ long page_size = getpagesize();
void *map = MAP_FAILED;
int mfd = -1, ret = -1;
@@ -228,16 +229,11 @@ void daemonize_and_wait(void)
static int parse_stage_args(int argc, char *argv[])
{
- static struct option long_options[] = {
- {"stage", required_argument, 0, 's'},
- {0, 0, 0, 0}
- };
- int option_index = 0;
int stage = 1;
int opt;
optind = 1;
- while ((opt = getopt_long(argc, argv, "s:", long_options, &option_index)) != -1) {
+ while ((opt = getopt(argc, argv, "s:")) != -1) {
switch (opt) {
case 's':
stage = atoi(optarg);
@@ -248,6 +244,7 @@ static int parse_stage_args(int argc, char *argv[])
fail_exit("Unknown argument");
}
}
+
return stage;
}
@@ -275,7 +272,7 @@ int luo_test(int argc, char *argv[],
fail_exit("Failed to check for state session");
if (target_stage != detected_stage) {
- ksft_exit_fail_msg("Stage mismatch Requested --stage %d, but system is in stage %d.\n"
+ ksft_exit_fail_msg("Stage mismatch Requested stage %d, but system is in stage %d.\n"
"(State session %s: %s)\n",
target_stage, detected_stage, state_session_name,
(detected_stage == 2) ? "EXISTS" : "MISSING");
diff --git a/tools/testing/selftests/liveupdate/run-vmtests.sh b/tools/testing/selftests/liveupdate/run-vmtests.sh
new file mode 100755
index 000000000000..d656ce58c5a7
--- /dev/null
+++ b/tools/testing/selftests/liveupdate/run-vmtests.sh
@@ -0,0 +1,97 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+SCRIPT_DIR=$(dirname "$(realpath "$0")")
+TEST_RUNNER="$SCRIPT_DIR/vmtest.sh"
+
+TARGETS=("x86_64" "aarch64")
+
+GREEN='\033[0;32m'
+RED='\033[0;31m'
+YELLOW='\033[1;33m'
+NC='\033[0m'
+
+passed=0
+failed=0
+skipped=0
+
+TEST_NAMES=(
+ "luo_kexec_simple"
+ "luo_multi_session"
+ "luo_stress_files"
+ "luo_stress_sessions"
+)
+
+function usage() {
+ cat <<EOF
+$0 [-k] [-o output_dir] [-h]
+Options:
+ -k) keep logs
+ -o) specify output directory
+ -h) display this help
+EOF
+}
+
+function pass() {
+ echo -e "${GREEN}PASS${NC}"
+ ((passed++))
+}
+
+function skip() {
+ echo -e "${YELLOW}SKIP${NC}"
+ ((skipped++))
+}
+
+function fail() {
+ echo -e "${RED}FAIL${NC}"
+ ((failed++))
+}
+
+function main() {
+ while getopts 'hko:' opt; do
+ case $opt in
+ k) keep_logs=1 ;;
+ o) output_dir=$OPTARG ;;
+ h) usage; exit 0 ;;
+ *) echo Unknown argument "$opt"
+ usage; exit 1 ;;
+ esac
+ done
+
+ if [ -n "$keep_logs" ]; then
+ if [ -z "$output_dir" ]; then
+ output_dir="$SCRIPT_DIR/results_$(date +%Y%m%d_%H%M%S)"
+ fi;
+ mkdir -p "$output_dir"
+ else
+ output_dir=$(mktemp -d /tmp/luo.XXXXXXXX)
+ trap 'rm -fr "$output_dir"' EXIT
+ fi
+
+ for arch in "${TARGETS[@]}"; do
+ for test_name in "${TEST_NAMES[@]}"; do
+ log="$output_dir/${arch}_${test_name}.log"
+
+ printf " -> %-8s %-24s ... " "$arch" "$test_name"
+
+ "$TEST_RUNNER" -t "$arch" -T "$test_name" &> "$log"
+ exit_code=$?
+
+ case $exit_code in
+ 0) pass;;
+ 4) skip;;
+ *) fail;;
+ esac
+ done
+ echo ""
+ done
+
+ echo "SUMMARY: PASS=$passed SKIP=$skipped FAIL=$failed"
+ if [ -n "$keep_logs" ]; then
+ echo "Logs: $output_dir"
+ fi
+
+ exit $((failed != 0))
+}
+
+main "$@"
diff --git a/tools/testing/selftests/liveupdate/vmtest.sh b/tools/testing/selftests/liveupdate/vmtest.sh
new file mode 100755
index 000000000000..b0000fae1461
--- /dev/null
+++ b/tools/testing/selftests/liveupdate/vmtest.sh
@@ -0,0 +1,263 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+set -ue
+
+CROSS_COMPILE="${CROSS_COMPILE:-""}"
+
+test_dir=$(realpath "$(dirname "$0")")
+kernel_dir=$(realpath "$test_dir/../../../..")
+
+workspace_dir=""
+headers_dir=""
+initrd=""
+KEEP_WORKSPACE=0
+
+source "$test_dir/../kselftest/ktap_helpers.sh"
+
+function get_arch_conf() {
+ local arch=$1
+ if [[ "$arch" == "arm64" ]]; then
+ QEMU_CMD="qemu-system-aarch64 -M virt -cpu max"
+ KERNEL_IMAGE="Image"
+ KERNEL_CMDLINE="console=ttyAMA0"
+ elif [[ "$arch" == "x86" ]]; then
+ QEMU_CMD="qemu-system-x86_64"
+ KERNEL_IMAGE="bzImage"
+ KERNEL_CMDLINE="console=ttyS0"
+ else
+ echo "Unsupported architecture: $arch"
+ exit 1
+ fi
+}
+
+function usage() {
+ cat <<EOF
+$0 [-d build_dir] [-j jobs] [-t target_arch] [-T test_name] [-w workspace_dir] [-k] [-h]
+Options:
+ -d) path to the kernel build directory (default: .luo_test_build.<arch>)
+ -j) number of jobs for compilation
+ -t) run test for target_arch (aarch64, x86_64)
+ -T) test name to run (default: luo_kexec_simple)
+ -w) custom workspace directory (default: creates temp dir)
+ -k) keep workspace directory after successful test
+ -h) display this help
+EOF
+}
+
+function cleanup() {
+ if [ "$KEEP_WORKSPACE" -eq 1 ]; then
+ echo "# Workspace preserved at: $workspace_dir"
+ else
+ rm -fr "$workspace_dir"
+ fi
+
+ ktap_finished
+}
+
+function skip() {
+ local msg=${1:-""}
+ ktap_test_skip "$msg"
+ exit "$KSFT_SKIP"
+}
+
+function fail() {
+ local msg=${1:-""}
+ ktap_test_fail "$msg"
+ exit "$KSFT_FAIL"
+}
+
+function detect_cross_compile() {
+ local target=$1
+ local host=$(uname -m)
+
+ [[ "$host" == "arm64" ]] && host="aarch64"
+ [[ "$target" == "arm64" ]] && target="aarch64"
+
+ if [[ "$host" == "$target" ]]; then
+ CROSS_COMPILE=""
+ return
+ fi
+
+ if [[ -n "$CROSS_COMPILE" ]]; then
+ return
+ fi
+
+ local candidate=""
+ case "$target" in
+ aarch64) candidate="aarch64-linux-gnu-" ;;
+ x86_64) candidate="x86_64-linux-gnu-" ;;
+ *) skip "Auto-detection for target '$target' not supported. Please set CROSS_COMPILE manually." ;;
+ esac
+
+ if command -v "${candidate}gcc" &> /dev/null; then
+ CROSS_COMPILE="$candidate"
+ else
+ skip "Compiler '${candidate}gcc' not found. Please install it (e.g., 'apt install gcc-aarch64-linux-gnu') or set CROSS_COMPILE."
+ fi
+}
+
+function build_kernel() {
+ local build_dir=$1
+ local make_cmd=$2
+ local kimage=$3
+ local target_arch=$4
+
+ local luo_config="$build_dir/luo.config"
+ local kconfig="$build_dir/.config"
+ local common_conf="$test_dir/config"
+ local arch_conf="$test_dir/config.$target_arch"
+
+ echo "# Building kernel in: $build_dir"
+
+ cat "$arch_conf" "$common_conf" | tee "$kconfig" > "$luo_config"
+ $make_cmd olddefconfig
+
+ # verify that kernel confiration has all necessary options
+ while read -r opt ; do
+ grep "$opt" "$kconfig" &>/dev/null || skip "$opt is missing"
+ done < "$luo_config"
+
+ $make_cmd "$kimage"
+ $make_cmd headers_install INSTALL_HDR_PATH="$headers_dir"
+}
+
+function mkinitrd() {
+ local build_dir=$1
+ local kernel_path=$2
+ local test_name=$3
+
+ # Compile the test binary and the init process
+ "$CROSS_COMPILE"gcc -static -O2 -nostdinc -nostdlib \
+ -I "$headers_dir/include" \
+ -I "$kernel_dir/tools/include/nolibc" \
+ -I "$test_dir" \
+ -o "$workspace_dir/test_binary" \
+ "$test_dir/$test_name.c" "$test_dir/luo_test_utils.c"
+
+ "$CROSS_COMPILE"gcc -s -static -Os -nostdinc -nostdlib \
+ -fno-asynchronous-unwind-tables -fno-ident \
+ -fno-stack-protector \
+ -I "$headers_dir/include" \
+ -I "$kernel_dir/tools/include/nolibc" \
+ -o "$workspace_dir/init" "$test_dir/init.c"
+
+ cat > "$workspace_dir/cpio_list_inner" <<EOF
+dir /dev 0755 0 0
+dir /proc 0755 0 0
+dir /debugfs 0755 0 0
+nod /dev/console 0600 0 0 c 5 1
+file /init $workspace_dir/init 0755 0 0
+file /test_binary $workspace_dir/test_binary 0755 0 0
+EOF
+
+ # Generate inner_initrd.cpio
+ "$build_dir/usr/gen_init_cpio" "$workspace_dir/cpio_list_inner" > "$workspace_dir/inner_initrd.cpio"
+
+ cat > "$workspace_dir/cpio_list" <<EOF
+dir /dev 0755 0 0
+dir /proc 0755 0 0
+dir /debugfs 0755 0 0
+nod /dev/console 0600 0 0 c 5 1
+file /init $workspace_dir/init 0755 0 0
+file /kernel $kernel_path 0644 0 0
+file /test_binary $workspace_dir/test_binary 0755 0 0
+file /initrd.img $workspace_dir/inner_initrd.cpio 0644 0 0
+EOF
+
+ # Generate the final initrd
+ "$build_dir/usr/gen_init_cpio" "$workspace_dir/cpio_list" > "$initrd"
+}
+
+function run_qemu() {
+ local qemu_cmd=$1
+ local cmdline=$2
+ local kernel_path=$3
+ local serial="$workspace_dir/qemu.serial"
+
+ cmdline="$cmdline liveupdate=on panic=-1"
+
+ echo "# Serial Log: $serial"
+ timeout 30s \
+ $qemu_cmd -m 1G -smp 2 -no-reboot -nographic -nodefaults \
+ -accel tcg -accel hvf -accel kvm \
+ -serial file:"$serial" \
+ -append "$cmdline" \
+ -kernel "$kernel_path" \
+ -initrd "$initrd"
+
+ grep "TEST PASSED" "$serial" &> /dev/null || fail "Liveupdate failed"
+}
+
+function target_to_arch() {
+ local target=$1
+ case $target in
+ aarch64) echo "arm64" ;;
+ x86_64) echo "x86" ;;
+ *) skip "architecture $target is not supported"
+ esac
+}
+
+function main() {
+ local build_dir=""
+ local jobs=$(nproc)
+ local target="$(uname -m)"
+ local test_name="luo_kexec_simple"
+ local workspace_arg=""
+
+ set -o errtrace
+ trap fail ERR
+
+ while getopts 'hd:j:t:T:w:k' opt; do
+ case $opt in
+ d) build_dir="$OPTARG" ;;
+ j) jobs="$OPTARG" ;;
+ t) target="$OPTARG" ;;
+ T) test_name="$OPTARG" ;;
+ w) workspace_arg="$OPTARG" ;;
+ k) KEEP_WORKSPACE=1 ;;
+ h) usage; exit 0 ;;
+ *) echo "Unknown argument $opt"; usage; exit 1 ;;
+ esac
+ done
+
+ ktap_print_header
+ ktap_set_plan 1
+ trap cleanup EXIT
+
+ if [ -n "$workspace_arg" ]; then
+ workspace_dir="$(realpath -m "$workspace_arg")"
+ mkdir -p "$workspace_dir"
+ else
+ workspace_dir=$(mktemp -d /tmp/luo-test.XXXXXXXX)
+ fi
+
+ echo "# Workspace created at: $workspace_dir"
+ headers_dir="$workspace_dir/usr"
+ initrd="$workspace_dir/initrd.cpio"
+
+ detect_cross_compile "$target"
+
+ local arch=$(target_to_arch "$target")
+
+ if [ -z "$build_dir" ]; then
+ build_dir="$kernel_dir/.luo_test_build.$arch"
+ fi
+
+ mkdir -p "$build_dir"
+ build_dir=$(realpath "$build_dir")
+ get_arch_conf "$arch"
+
+ local make_cmd="make -s ARCH=$arch CROSS_COMPILE=$CROSS_COMPILE -j$jobs"
+ local make_cmd_build="$make_cmd -C $kernel_dir O=$build_dir"
+
+ build_kernel "$build_dir" "$make_cmd_build" "$KERNEL_IMAGE" "$target"
+
+ local final_kernel="$build_dir/arch/$arch/boot/$KERNEL_IMAGE"
+ mkinitrd "$build_dir" "$final_kernel" "$test_name"
+
+ run_qemu "$QEMU_CMD" "$KERNEL_CMDLINE" "$final_kernel"
+ ktap_test_pass "$test_name succeeded"
+}
+
+main "$@"
diff --git a/tools/testing/selftests/mm/pagemap_ioctl.c b/tools/testing/selftests/mm/pagemap_ioctl.c
index f9bcff8e78fa..1c80d070b9f1 100644
--- a/tools/testing/selftests/mm/pagemap_ioctl.c
+++ b/tools/testing/selftests/mm/pagemap_ioctl.c
@@ -1102,6 +1102,59 @@ static void unpopulated_scan_test(void)
munmap(mem, mem_size);
}
+/*
+ * A 2MB anon THP dropped with MADV_DONTNEED leaves a pmd_none hole with no
+ * page table, which pagemap_page_category() never sees. PAGEMAP_SCAN must
+ * still report it as written on a uffd-wp VMA, via pagemap_scan_pte_hole().
+ */
+static void unpopulated_thp_hole_test(void)
+{
+ long npages, written = 0, ret, i;
+ struct page_region regions[16];
+ char *area, *mem;
+
+ if (!hpage_size) {
+ ksft_test_result_skip("%s THP not supported\n", __func__);
+ return;
+ }
+ npages = hpage_size / page_size;
+
+ /* Get a PMD-aligned range so the range can be a single THP. */
+ area = mmap(NULL, 2 * hpage_size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (area == MAP_FAILED)
+ ksft_exit_fail_msg("%s mmap failed\n", __func__);
+ mem = (char *)(((unsigned long)area + hpage_size - 1) & ~(hpage_size - 1));
+
+ memset(mem, 1, hpage_size);
+ if (madvise(mem, hpage_size, MADV_COLLAPSE) ||
+ !check_huge_anon(mem, 1, hpage_size)) {
+ ksft_test_result_skip("%s could not form a THP\n", __func__);
+ munmap(area, 2 * hpage_size);
+ return;
+ }
+
+ wp_init(mem, hpage_size);
+
+ /* Drop the whole PMD: it is cleared to a pmd_none hole. */
+ if (madvise(mem, hpage_size, MADV_DONTNEED))
+ ksft_exit_fail_msg("%s MADV_DONTNEED failed\n", __func__);
+
+ ret = pagemap_ioctl(mem, hpage_size, regions, 16, 0, 0,
+ PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN);
+ if (ret < 0)
+ ksft_exit_fail_msg("%s scan failed\n", __func__);
+ for (i = 0; i < ret; i++)
+ written += LEN(regions[i]);
+
+ ksft_test_result(written == npages,
+ "%s pmd-hole reported written (%ld of %ld)\n",
+ __func__, written, npages);
+
+ wp_free(mem, hpage_size);
+ munmap(area, 2 * hpage_size);
+}
+
int sanity_tests(void)
{
unsigned long long mem_size, vec_size;
@@ -1610,7 +1663,7 @@ int main(int __attribute__((unused)) argc, char *argv[])
if (!hugetlb_setup_default(4))
ksft_print_msg("HugeTLB test will be skipped\n");
- ksft_set_plan(118);
+ ksft_set_plan(119);
page_size = getpagesize();
hpage_size = read_pmd_pagesize();
@@ -1790,6 +1843,7 @@ int main(int __attribute__((unused)) argc, char *argv[])
/* 18. Unpopulated pte scan-path consistency */
unpopulated_scan_test();
+ unpopulated_thp_hole_test();
close(pagemap_fd);
ksft_finished();
diff --git a/tools/testing/selftests/mm/uffd-unit-tests.c b/tools/testing/selftests/mm/uffd-unit-tests.c
index a6c14109e818..ef9b3956bdcf 100644
--- a/tools/testing/selftests/mm/uffd-unit-tests.c
+++ b/tools/testing/selftests/mm/uffd-unit-tests.c
@@ -7,6 +7,8 @@
#include "uffd-common.h"
+#include <linux/fs.h>
+#include <sys/uio.h>
#include "../../../../mm/gup_test.h"
#ifdef __NR_userfaultfd
@@ -109,6 +111,10 @@ static void uffd_test_skip(const char *message)
static void test_uffd_api(bool use_dev)
{
+ const uint64_t expected_ioctls =
+ BIT_ULL(_UFFDIO_REGISTER) |
+ BIT_ULL(_UFFDIO_UNREGISTER) |
+ BIT_ULL(_UFFDIO_API);
struct uffdio_api uffdio_api;
int uffd;
@@ -148,6 +154,15 @@ static void test_uffd_api(bool use_dev)
goto out;
}
+ /* Verify returned fd-level ioctls bitmask */
+ if ((uffdio_api.ioctls & expected_ioctls) != expected_ioctls) {
+ uffd_test_fail("UFFDIO_API missing expected ioctls: "
+ "got=0x%"PRIx64", expected=0x%"PRIx64,
+ (uint64_t)uffdio_api.ioctls,
+ expected_ioctls);
+ goto out;
+ }
+
/* Test double requests of UFFDIO_API with a random feature set */
uffdio_api.features = BIT_ULL(0);
if (ioctl(uffd, UFFDIO_API, &uffdio_api) == 0) {
@@ -602,6 +617,814 @@ void uffd_minor_collapse_test(uffd_global_test_opts_t *gopts, uffd_test_args_t *
uffd_minor_test_common(gopts, true, false);
}
+static int uffd_register_rwp(int uffd, void *addr, uint64_t len)
+{
+ struct uffdio_register reg = {
+ .range = { .start = (unsigned long)addr, .len = len },
+ .mode = UFFDIO_REGISTER_MODE_RWP,
+ };
+
+ if (ioctl(uffd, UFFDIO_REGISTER, &reg) == -1)
+ return -errno;
+ return 0;
+}
+
+static void rwprotect_range(int uffd, __u64 start, __u64 len, bool protect)
+{
+ struct uffdio_rwprotect rwp = {
+ .range = { .start = start, .len = len },
+ .mode = protect ? UFFDIO_RWPROTECT_MODE_RWP : 0,
+ };
+
+ if (ioctl(uffd, UFFDIO_RWPROTECT, &rwp))
+ err("UFFDIO_RWPROTECT failed");
+}
+
+static void set_async_mode(int uffd, bool enable)
+{
+ struct uffdio_set_mode mode = { };
+
+ if (enable)
+ mode.enable = UFFD_FEATURE_RWP_ASYNC;
+ else
+ mode.disable = UFFD_FEATURE_RWP_ASYNC;
+
+ if (ioctl(uffd, UFFDIO_SET_MODE, &mode))
+ err("UFFDIO_SET_MODE failed");
+}
+
+/*
+ * Test async RWP faults on anonymous memory.
+ * Populate pages, register MODE_RWP with RWP_ASYNC,
+ * RW-protect, re-access, verify content preserved and no faults delivered.
+ */
+static void uffd_rwp_async_test(uffd_global_test_opts_t *gopts,
+ uffd_test_args_t *args)
+{
+ unsigned long nr_pages = gopts->nr_pages;
+ unsigned long page_size = gopts->page_size;
+ unsigned long p;
+
+ /* Populate all pages with known content */
+ for (p = 0; p < nr_pages; p++)
+ memset(gopts->area_dst + p * page_size, p % 255 + 1, page_size);
+
+ /* Register MODE_RWP */
+ if (uffd_register_rwp(gopts->uffd, gopts->area_dst,
+ nr_pages * page_size))
+ err("register failure");
+
+ /* RW-protect all pages (sets protnone) */
+ rwprotect_range(gopts->uffd, (uint64_t)gopts->area_dst,
+ nr_pages * page_size, true);
+
+ /* Access all pages — should auto-resolve, no faults */
+ for (p = 0; p < nr_pages; p++) {
+ unsigned char *page = (unsigned char *)gopts->area_dst +
+ p * page_size;
+ unsigned char expected = p % 255 + 1;
+
+ if (page[0] != expected) {
+ uffd_test_fail("page %lu content mismatch: %u != %u",
+ p, page[0], expected);
+ return;
+ }
+ }
+
+ uffd_test_pass();
+}
+
+/*
+ * Fault handler for RWP — unprotect the page via UFFDIO_RWPROTECT.
+ */
+static void uffd_handle_rwp_fault(uffd_global_test_opts_t *gopts,
+ struct uffd_msg *msg,
+ struct uffd_args *uargs)
+{
+ if (!(msg->arg.pagefault.flags & UFFD_PAGEFAULT_FLAG_RWP))
+ err("expected RWP fault, got 0x%llx",
+ msg->arg.pagefault.flags);
+
+ rwprotect_range(gopts->uffd, msg->arg.pagefault.address,
+ gopts->page_size, false);
+ uargs->minor_faults++;
+}
+
+/*
+ * Test sync RWP faults on anonymous memory.
+ * Populate pages, register MODE_RWP (sync), RW-protect,
+ * access from worker thread, verify fault delivered, UFFDIO_RWPROTECT resolves.
+ */
+static void uffd_rwp_sync_test(uffd_global_test_opts_t *gopts,
+ uffd_test_args_t *args)
+{
+ unsigned long nr_pages = gopts->nr_pages;
+ unsigned long page_size = gopts->page_size;
+ pthread_t uffd_mon;
+ struct uffd_args uargs = { };
+ bool failed = false;
+ char c = '\0';
+ unsigned long p;
+
+ uargs.gopts = gopts;
+ uargs.handle_fault = uffd_handle_rwp_fault;
+
+ /* Populate all pages */
+ for (p = 0; p < nr_pages; p++)
+ memset(gopts->area_dst + p * page_size, p % 255 + 1, page_size);
+
+ /* Register MODE_RWP */
+ if (uffd_register_rwp(gopts->uffd, gopts->area_dst,
+ nr_pages * page_size))
+ err("register failure");
+
+ /* RW-protect all pages */
+ rwprotect_range(gopts->uffd, (uint64_t)gopts->area_dst,
+ nr_pages * page_size, true);
+
+ /* Start fault handler thread */
+ if (pthread_create(&uffd_mon, NULL, uffd_poll_thread, &uargs))
+ err("uffd_poll_thread create");
+
+ /* Access all pages — triggers sync RWP faults, handler unprotects */
+ for (p = 0; p < nr_pages; p++) {
+ unsigned char *page = (unsigned char *)gopts->area_dst +
+ p * page_size;
+
+ if (page[0] != (p % 255 + 1)) {
+ uffd_test_fail("page %lu content mismatch", p);
+ failed = true;
+ goto out;
+ }
+ }
+
+out:
+ /*
+ * Stop the handler before reading minor_faults: the last fault
+ * resolution rwprotect_range()s before incrementing the counter,
+ * so the main thread can race ahead of the increment.
+ */
+ if (write(gopts->pipefd[1], &c, sizeof(c)) != sizeof(c))
+ err("pipe write");
+ if (pthread_join(uffd_mon, NULL))
+ err("join() failed");
+
+ if (failed)
+ return;
+ if (uargs.minor_faults == 0)
+ uffd_test_fail("expected RWP faults, got 0");
+ else
+ uffd_test_pass();
+}
+
+/*
+ * Test PAGEMAP_SCAN working-set discovery via the "hot" (accessed) scan.
+ *
+ * The working-set primitive is to find pages that were accessed: scan for
+ * PAGE_IS_ACCESSED, which is set once an access clears the protnone+uffd
+ * marker. A VMM treats every access fault as "hot" (RWP here; MINOR/MISSING
+ * for non-resident pages) and reclaims the rest from the backing file.
+ *
+ * We deliberately do NOT use an inverted "cold" scan: that only sees
+ * VMA-resident ptes, so for a file mapping it misses cached-but-unmapped (and
+ * never-faulted, pre-populated) pages, which are pte_none and thus invisible.
+ * Hot tracking + file-level reclaim covers them; a cold pte scan cannot.
+ */
+static void uffd_rwp_pagemap_test(uffd_global_test_opts_t *gopts,
+ uffd_test_args_t *args)
+{
+ unsigned long nr_pages = gopts->nr_pages;
+ unsigned long page_size = gopts->page_size;
+ unsigned long p;
+ struct page_region regions[16];
+ struct pm_scan_arg pm_arg;
+ int pagemap_fd;
+ long ret;
+
+ /* Need at least 4 pages */
+ if (nr_pages < 4) {
+ uffd_test_skip("need at least 4 pages");
+ return;
+ }
+
+ /* Populate all pages */
+ for (p = 0; p < nr_pages; p++)
+ memset(gopts->area_dst + p * page_size, 0xab, page_size);
+
+ /* Register and RW-protect */
+ if (uffd_register_rwp(gopts->uffd, gopts->area_dst,
+ nr_pages * page_size))
+ err("register failure");
+
+ rwprotect_range(gopts->uffd, (uint64_t)gopts->area_dst,
+ nr_pages * page_size, true);
+
+ /* Touch first half of pages to re-activate them (async auto-resolve) */
+ for (p = 0; p < nr_pages / 2; p++) {
+ volatile char *page = gopts->area_dst + p * page_size;
+ (void)*page;
+ }
+
+ uint64_t start = (uint64_t)gopts->area_dst;
+ uint64_t boundary = start + (nr_pages / 2) * page_size;
+ uint64_t end = start + nr_pages * page_size;
+
+ pagemap_fd = open("/proc/self/pagemap", O_RDONLY);
+ if (pagemap_fd < 0)
+ err("open pagemap");
+
+ /*
+ * Hot scan: report the pages that were accessed. PAGE_IS_ACCESSED is
+ * set once the protnone+uffd marker is cleared (by the access, async
+ * auto-resolve here). The touched first half must come back as exactly
+ * one hot region [start, boundary); the untouched second half must not
+ * appear.
+ */
+ memset(&pm_arg, 0, sizeof(pm_arg));
+ pm_arg.size = sizeof(pm_arg);
+ pm_arg.start = start;
+ pm_arg.end = end;
+ pm_arg.vec = (uint64_t)regions;
+ pm_arg.vec_len = ARRAY_SIZE(regions);
+ pm_arg.category_mask = PAGE_IS_ACCESSED;
+ pm_arg.return_mask = PAGE_IS_ACCESSED;
+
+ ret = ioctl(pagemap_fd, PAGEMAP_SCAN, &pm_arg);
+ close(pagemap_fd);
+
+ if (ret < 0) {
+ uffd_test_fail("PAGEMAP_SCAN failed: %s", strerror(errno));
+ return;
+ }
+
+ if (ret != 1 || regions[0].start != start ||
+ regions[0].end != boundary) {
+ uffd_test_fail("hot set wrong: got %ld regions [0x%lx,0x%lx), expected 1 [0x%lx,0x%lx)",
+ ret, (unsigned long)regions[0].start,
+ (unsigned long)regions[0].end,
+ (unsigned long)start, (unsigned long)boundary);
+ return;
+ }
+
+ uffd_test_pass();
+}
+
+/*
+ * Test that RWP protection survives a mprotect(PROT_NONE) ->
+ * mprotect(PROT_READ|PROT_WRITE) round-trip. The uffd-wp bit on a
+ * VM_UFFD_RWP VMA must continue to carry PROT_NONE semantics after
+ * mprotect() changes the base protection; otherwise accesses would
+ * silently succeed and the pagemap bit would stick without a fault
+ * ever clearing it.
+ */
+static void uffd_rwp_mprotect_test(uffd_global_test_opts_t *gopts,
+ uffd_test_args_t *args)
+{
+ unsigned long nr_pages = gopts->nr_pages;
+ unsigned long page_size = gopts->page_size;
+ unsigned long p;
+ struct page_region regions[16];
+ struct pm_scan_arg pm_arg;
+ int pagemap_fd;
+ uint64_t value;
+ long ret;
+
+ /* Populate all pages */
+ for (p = 0; p < nr_pages; p++)
+ memset(gopts->area_dst + p * page_size, 0xab, page_size);
+
+ /* Register and RW-protect the whole range */
+ if (uffd_register_rwp(gopts->uffd, gopts->area_dst,
+ nr_pages * page_size))
+ err("register failure");
+ rwprotect_range(gopts->uffd, (uint64_t)gopts->area_dst,
+ nr_pages * page_size, true);
+
+ /* Round-trip mprotect(): PROT_NONE -> PROT_READ|PROT_WRITE */
+ if (mprotect(gopts->area_dst, nr_pages * page_size, PROT_NONE))
+ err("mprotect() PROT_NONE");
+ if (mprotect(gopts->area_dst, nr_pages * page_size,
+ PROT_READ | PROT_WRITE))
+ err("mprotect() PROT_READ|PROT_WRITE");
+
+ /*
+ * The marker must survive the round-trip; if mprotect() dropped it,
+ * the touches below would not fault and the scan would pass
+ * vacuously.
+ */
+ pagemap_fd = pagemap_open();
+ value = pagemap_get_entry(pagemap_fd, gopts->area_dst);
+ close(pagemap_fd);
+ if (!(value & PM_UFFD_WP)) {
+ uffd_test_fail("RWP marker lost across mprotect()");
+ return;
+ }
+
+ /* Touch every page. Async RWP must auto-resolve each fault. */
+ for (p = 0; p < nr_pages; p++) {
+ volatile char *page = gopts->area_dst + p * page_size;
+ (void)*page;
+ }
+
+ /*
+ * After touching, no page should remain RW-protected. A stuck
+ * uffd-wp bit would mean mprotect() silently dropped PROT_NONE and
+ * the access never faulted.
+ */
+ pagemap_fd = open("/proc/self/pagemap", O_RDONLY);
+ if (pagemap_fd < 0)
+ err("open pagemap");
+
+ memset(&pm_arg, 0, sizeof(pm_arg));
+ pm_arg.size = sizeof(pm_arg);
+ pm_arg.start = (uint64_t)gopts->area_dst;
+ pm_arg.end = (uint64_t)gopts->area_dst + nr_pages * page_size;
+ pm_arg.vec = (uint64_t)regions;
+ pm_arg.vec_len = ARRAY_SIZE(regions);
+ pm_arg.category_mask = PAGE_IS_ACCESSED;
+ pm_arg.category_inverted = PAGE_IS_ACCESSED;
+ pm_arg.return_mask = PAGE_IS_ACCESSED;
+
+ ret = ioctl(pagemap_fd, PAGEMAP_SCAN, &pm_arg);
+ close(pagemap_fd);
+
+ if (ret < 0) {
+ uffd_test_fail("PAGEMAP_SCAN failed: %s", strerror(errno));
+ return;
+ }
+ if (ret != 0) {
+ uffd_test_fail("expected no cold pages after mprotect()+touch, got %ld regions",
+ ret);
+ return;
+ }
+
+ uffd_test_pass();
+}
+
+/*
+ * Test that GUP resolves through protnone PTEs (async mode).
+ * vmsplice() into a pipe pins user pages via get_user_pages_fast() --
+ * unlike write(), which goes through copy_from_user() and ordinary
+ * hardware page faults -- so it exercises gup_can_follow_protnone() on
+ * the RW-protected PTE. In async mode the kernel auto-restores
+ * permissions and GUP returns the page.
+ */
+static void uffd_rwp_gup_test(uffd_global_test_opts_t *gopts,
+ uffd_test_args_t *args)
+{
+ struct iovec iov;
+ char buf;
+ int pipefd[2];
+
+ /* Populate first page with known content */
+ memset(gopts->area_dst, 0xCD, gopts->page_size);
+
+ if (uffd_register_rwp(gopts->uffd, gopts->area_dst, gopts->page_size))
+ err("register failure");
+
+ rwprotect_range(gopts->uffd, (uint64_t)gopts->area_dst,
+ gopts->page_size, true);
+
+ if (pipe(pipefd))
+ err("pipe");
+
+ /*
+ * One byte's worth of iov is enough to GUP the containing page and
+ * keeps the pipe transfer well under any pipe-capacity limit even on
+ * hugetlb-backed runs.
+ */
+ iov.iov_base = gopts->area_dst;
+ iov.iov_len = 1;
+ if (vmsplice(pipefd[1], &iov, 1, 0) != 1) {
+ uffd_test_fail("vmsplice from RW-protected page failed: %s",
+ strerror(errno));
+ goto out;
+ }
+
+ if (read(pipefd[0], &buf, 1) != 1) {
+ uffd_test_fail("read from pipe failed");
+ goto out;
+ }
+
+ if (buf != (char)0xCD) {
+ uffd_test_fail("content mismatch: got 0x%02x, expected 0xCD",
+ (unsigned char)buf);
+ goto out;
+ }
+
+ uffd_test_pass();
+out:
+ close(pipefd[0]);
+ close(pipefd[1]);
+}
+
+/*
+ * Test runtime toggle between async and sync modes.
+ * Start in async mode (detection), flip to sync (eviction), verify faults
+ * block, resolve them, flip back to async.
+ */
+static void uffd_rwp_async_toggle_test(uffd_global_test_opts_t *gopts,
+ uffd_test_args_t *args)
+{
+ unsigned long nr_pages = gopts->nr_pages;
+ unsigned long page_size = gopts->page_size;
+ struct uffd_args uargs = { };
+ pthread_t uffd_mon;
+ char c = '\0';
+ unsigned long p;
+
+ uargs.gopts = gopts;
+ uargs.handle_fault = uffd_handle_rwp_fault;
+
+ /* Populate */
+ for (p = 0; p < nr_pages; p++)
+ memset(gopts->area_dst + p * page_size, p % 255 + 1, page_size);
+
+ if (uffd_register_rwp(gopts->uffd, gopts->area_dst,
+ nr_pages * page_size))
+ err("register failure");
+
+ /* Phase 1: async detection — RW-protect, access first half */
+ rwprotect_range(gopts->uffd, (uint64_t)gopts->area_dst,
+ nr_pages * page_size, true);
+
+ for (p = 0; p < nr_pages / 2; p++) {
+ volatile char *page = gopts->area_dst + p * page_size;
+ (void)*page; /* auto-resolves in async mode */
+ }
+
+ /* Phase 2: flip to sync for eviction */
+ set_async_mode(gopts->uffd, false);
+
+ /* Start handler — will receive faults for cold pages */
+ if (pthread_create(&uffd_mon, NULL, uffd_poll_thread, &uargs))
+ err("uffd_poll_thread create");
+
+ /* Access second half (cold pages) — should trigger sync faults */
+ for (p = nr_pages / 2; p < nr_pages; p++) {
+ unsigned char *page = (unsigned char *)gopts->area_dst +
+ p * page_size;
+ if (page[0] != (p % 255 + 1)) {
+ uffd_test_fail("page %lu content mismatch", p);
+ goto out;
+ }
+ }
+
+ /*
+ * Stop the handler before reading minor_faults: the last fault
+ * resolution rwprotect_range()s before incrementing the counter,
+ * so the main thread can race ahead of the increment. Stopping
+ * here also makes Phase 3 a clean async-only test -- with the
+ * handler still running it would silently resolve any sync fault
+ * the kernel erroneously delivers, masking a regression.
+ */
+ if (write(gopts->pipefd[1], &c, sizeof(c)) != sizeof(c))
+ err("pipe write");
+ if (pthread_join(uffd_mon, NULL))
+ err("join() failed");
+
+ if (uargs.minor_faults == 0) {
+ uffd_test_fail("expected sync faults, got 0");
+ return;
+ }
+
+ /* Phase 3: flip back to async */
+ set_async_mode(gopts->uffd, true);
+
+ /* RW-protect and access again — should auto-resolve */
+ rwprotect_range(gopts->uffd, (uint64_t)gopts->area_dst,
+ nr_pages * page_size, true);
+
+ for (p = 0; p < nr_pages; p++) {
+ volatile char *page = gopts->area_dst + p * page_size;
+ (void)*page;
+ }
+
+ uffd_test_pass();
+ return;
+out:
+ if (write(gopts->pipefd[1], &c, sizeof(c)) != sizeof(c))
+ err("pipe write");
+ if (pthread_join(uffd_mon, NULL))
+ err("join() failed");
+}
+
+/*
+ * Test that RW-protected pages become accessible after closing uffd.
+ */
+static void uffd_rwp_close_test(uffd_global_test_opts_t *gopts,
+ uffd_test_args_t *args)
+{
+ unsigned long nr_pages = gopts->nr_pages;
+ unsigned long page_size = gopts->page_size;
+ unsigned long p;
+
+ /* Populate */
+ for (p = 0; p < nr_pages; p++)
+ memset(gopts->area_dst + p * page_size, p % 255 + 1, page_size);
+
+ if (uffd_register_rwp(gopts->uffd, gopts->area_dst,
+ nr_pages * page_size))
+ err("register failure");
+
+ rwprotect_range(gopts->uffd, (uint64_t)gopts->area_dst,
+ nr_pages * page_size, true);
+
+ /* Close uffd — should restore protnone PTEs */
+ close(gopts->uffd);
+ gopts->uffd = -1;
+
+ /* All pages should be accessible with original content */
+ for (p = 0; p < nr_pages; p++) {
+ unsigned char *page = (unsigned char *)gopts->area_dst +
+ p * page_size;
+ unsigned char expected = p % 255 + 1;
+
+ if (page[0] != expected) {
+ uffd_test_fail("page %lu not accessible after close", p);
+ return;
+ }
+ }
+
+ uffd_test_pass();
+}
+
+/*
+ * Test that RWP protection is preserved across fork() when
+ * UFFD_FEATURE_EVENT_FORK is enabled. Without preservation, the child's
+ * PTEs would lose the uffd-wp marker and RWP-protected accesses would
+ * silently fall through to do_numa_page().
+ */
+static void uffd_rwp_fork_test(uffd_global_test_opts_t *gopts,
+ uffd_test_args_t *args)
+{
+ unsigned long nr_pages = gopts->nr_pages;
+ unsigned long page_size = gopts->page_size;
+ int pagemap_fd;
+ uint64_t value;
+
+ if (uffd_register_rwp(gopts->uffd, gopts->area_dst,
+ nr_pages * page_size))
+ err("register failed");
+
+ /* Populate + RWP-protect */
+ *gopts->area_dst = 1;
+ rwprotect_range(gopts->uffd, (uint64_t)gopts->area_dst,
+ page_size, true);
+
+ /* Parent: verify uffd-wp bit is set before fork */
+ pagemap_fd = pagemap_open();
+ value = pagemap_get_entry(pagemap_fd, gopts->area_dst);
+ pagemap_check_wp(value, true);
+
+ /*
+ * Fork with EVENT_FORK: child inherits VM_UFFD_RWP. Child reads
+ * its own pagemap and must still see the uffd-wp bit set.
+ */
+ if (pagemap_test_fork(gopts, true, false)) {
+ uffd_test_fail("RWP marker lost in child after fork");
+ goto out;
+ }
+
+ uffd_test_pass();
+out:
+ close(pagemap_fd);
+}
+
+/*
+ * Test that RWP protection on a pinned anon page is preserved across fork().
+ * Pinning forces copy_present_page() in the child path, which must restore
+ * PAGE_NONE on top of the uffd bit. Using async mode, a read in the child
+ * auto-resolves if — and only if — the PTE was actually protnone+uffd; the
+ * cleared uffd bit afterward proves the fault path ran.
+ */
+static void uffd_rwp_fork_pin_test(uffd_global_test_opts_t *gopts,
+ uffd_test_args_t *args)
+{
+ unsigned long page_size = gopts->page_size;
+ fork_event_args fevent_args = { .gopts = gopts, .child_uffd = -1 };
+ pin_args pin_args = {};
+ int pagemap_fd, status;
+ pthread_t fevent_thread;
+ uint64_t value;
+ pid_t child;
+
+ if (uffd_register_rwp(gopts->uffd, gopts->area_dst, page_size))
+ err("register failed");
+
+ /* Populate. */
+ *gopts->area_dst = 1;
+
+ /* RO-longterm pin so fork() takes copy_present_page() for this PTE. */
+ if (pin_pages(&pin_args, gopts->area_dst, page_size)) {
+ uffd_test_skip("Possibly CONFIG_GUP_TEST missing or unprivileged");
+ uffd_unregister(gopts->uffd, gopts->area_dst, page_size);
+ return;
+ }
+
+ /* RWP-protect: PTE is now PAGE_NONE + uffd bit. */
+ rwprotect_range(gopts->uffd, (uint64_t)gopts->area_dst, page_size, true);
+
+ pagemap_fd = pagemap_open();
+ value = pagemap_get_entry(pagemap_fd, gopts->area_dst);
+ pagemap_check_wp(value, true);
+
+ /*
+ * UFFD_FEATURE_EVENT_FORK is required so the child inherits
+ * VM_UFFD_RWP and the marker; without it dup_userfaultfd() resets
+ * the child VMA and the test would pass for the wrong reason.
+ * dup_userfaultfd() blocks until the EVENT_FORK message is consumed,
+ * so spawn a reader before the fork().
+ */
+ gopts->ready_for_fork = false;
+ if (pthread_create(&fevent_thread, NULL, fork_event_consumer,
+ &fevent_args))
+ err("pthread_create() for fork event consumer");
+ while (!gopts->ready_for_fork)
+ ; /* Wait for consumer to start polling. */
+
+ child = fork();
+ if (child < 0)
+ err("fork");
+ if (child == 0) {
+ volatile char c;
+ int cfd;
+
+ /*
+ * Precondition: the child must have inherited the marker.
+ * If copy_present_page() dropped it together with PAGE_NONE,
+ * the read below would succeed without the fault path and
+ * the after-read check would pass for the wrong reason.
+ */
+ cfd = pagemap_open();
+ value = pagemap_get_entry(cfd, gopts->area_dst);
+ if (!(value & PM_UFFD_WP)) {
+ close(cfd);
+ _exit(2);
+ }
+
+ /*
+ * Read the pinned page. Only reaches the fault path if the
+ * child PTE is protnone + uffd; async mode auto-resolves and
+ * clears the uffd bit. If copy_present_page() dropped
+ * PAGE_NONE, the read would silently succeed and the bit
+ * would still be set.
+ */
+ c = *(volatile char *)gopts->area_dst;
+ (void)c;
+
+ value = pagemap_get_entry(cfd, gopts->area_dst);
+ close(cfd);
+ _exit((value & PM_UFFD_WP) ? 1 : 0);
+ }
+ if (waitpid(child, &status, 0) < 0)
+ err("waitpid");
+ if (pthread_join(fevent_thread, NULL))
+ err("pthread_join() for fork event consumer");
+ if (fevent_args.child_uffd >= 0)
+ close(fevent_args.child_uffd);
+
+ unpin_pages(&pin_args);
+ close(pagemap_fd);
+ if (uffd_unregister(gopts->uffd, gopts->area_dst, page_size))
+ err("unregister failed");
+
+ if (WIFEXITED(status) && WEXITSTATUS(status) == 2) {
+ uffd_test_fail("RWP marker not inherited by child");
+ return;
+ }
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+ uffd_test_fail("RWP not enforced in child after pinned fork");
+ return;
+ }
+
+ uffd_test_pass();
+}
+
+/*
+ * A non-exclusive (forked, COW-shared) anon page that is RWP-protected and
+ * then swapped out must keep tracking across swap-in. On the write that
+ * swaps it back in, do_swap_page() restores PAGE_NONE and the access retries
+ * through the RWP fault path, instead of being COWed straight to a fresh
+ * accessible page -- which would silently drop the marker for a non-exclusive
+ * folio. Sync mode lets us observe the fault directly: with the bug, the
+ * write COWs without delivering any RWP fault.
+ *
+ * Needs a swap device; skipped if MADV_PAGEOUT cannot evict the page.
+ */
+static void uffd_rwp_swap_cow_test(uffd_global_test_opts_t *gopts,
+ uffd_test_args_t *args)
+{
+ unsigned long page_size = gopts->page_size;
+ struct uffd_args uargs = { };
+ int pagemap_fd, go[2], i;
+ pthread_t uffd_mon;
+ char c = '\0';
+ pid_t child;
+
+ uargs.gopts = gopts;
+ uargs.handle_fault = uffd_handle_rwp_fault;
+
+ if (uffd_register_rwp(gopts->uffd, gopts->area_dst, page_size))
+ err("register failed");
+
+ /* Populate one page (exclusive at this point). */
+ *gopts->area_dst = 0x11;
+
+ /* RWP-protect: PTE becomes PAGE_NONE + uffd bit (still exclusive). */
+ rwprotect_range(gopts->uffd, (uint64_t)gopts->area_dst, page_size, true);
+
+ /*
+ * Swap the page out while it is still exclusive: a shared (forked)
+ * folio does not get reclaimed by MADV_PAGEOUT. Retry, since a hot
+ * page may just be rotated on the first reclaim pass.
+ */
+ pagemap_fd = pagemap_open();
+ for (i = 0; i < 100; i++) {
+ if (madvise(gopts->area_dst, page_size, MADV_PAGEOUT))
+ err("MADV_PAGEOUT");
+ if (pagemap_is_swapped(pagemap_fd, gopts->area_dst))
+ break;
+ usleep(10000);
+ }
+ if (!pagemap_is_swapped(pagemap_fd, gopts->area_dst)) {
+ uffd_test_skip("MADV_PAGEOUT did not swap the page; is swap enabled?");
+ close(pagemap_fd);
+ uffd_unregister(gopts->uffd, gopts->area_dst, page_size);
+ return;
+ }
+
+ /*
+ * fork() now: the child duplicates the swap entry, so the slot becomes
+ * non-exclusive. The child parks (keeping the reference) until the
+ * parent has faulted the page back in.
+ */
+ if (pipe(go))
+ err("pipe");
+ child = fork();
+ if (child < 0)
+ err("fork");
+ if (child == 0) {
+ close(go[1]);
+ read(go[0], &c, 1);
+ _exit(0);
+ }
+ close(go[0]);
+
+ if (pthread_create(&uffd_mon, NULL, uffd_poll_thread, &uargs))
+ err("uffd_poll_thread create");
+
+ /*
+ * Write the page: swaps it back in (do_swap_page) on a non-exclusive
+ * folio with FAULT_FLAG_WRITE. The marker must survive and deliver an
+ * RWP fault rather than COW silently.
+ */
+ *gopts->area_dst = 0x22;
+
+ if (write(gopts->pipefd[1], &c, sizeof(c)) != sizeof(c))
+ err("pipe write");
+ if (pthread_join(uffd_mon, NULL))
+ err("join failed");
+
+ if (uargs.minor_faults == 0)
+ uffd_test_fail("no RWP fault on swapped-in non-exclusive page");
+ else
+ uffd_test_pass();
+
+ close(pagemap_fd);
+ if (write(go[1], &c, 1) != 1)
+ err("child release");
+ close(go[1]);
+ waitpid(child, NULL, 0);
+}
+
+/*
+ * WP and RWP share the uffd-wp PTE bit and cannot coexist in the same VMA.
+ * Registration requesting both modes must be rejected.
+ */
+static void uffd_rwp_wp_exclusive_test(uffd_global_test_opts_t *gopts,
+ uffd_test_args_t *args)
+{
+ unsigned long nr_pages = gopts->nr_pages;
+ unsigned long page_size = gopts->page_size;
+ struct uffdio_register reg = { };
+
+ reg.range.start = (unsigned long)gopts->area_dst;
+ reg.range.len = nr_pages * page_size;
+ reg.mode = UFFDIO_REGISTER_MODE_WP | UFFDIO_REGISTER_MODE_RWP;
+
+ if (ioctl(gopts->uffd, UFFDIO_REGISTER, &reg) == 0) {
+ uffd_test_fail("register with WP|RWP unexpectedly succeeded");
+ return;
+ }
+ if (errno != EINVAL) {
+ uffd_test_fail("register with WP|RWP: expected EINVAL, got %d",
+ errno);
+ return;
+ }
+ uffd_test_pass();
+}
+
static sigjmp_buf jbuf, *sigbuf;
static void sighndl(int sig, siginfo_t *siginfo, void *ptr)
@@ -1605,6 +2428,83 @@ uffd_test_case_t uffd_tests[] = {
.uffd_feature_required = UFFD_FEATURE_MINOR_SHMEM,
},
{
+ .name = "rwp-async",
+ .uffd_fn = uffd_rwp_async_test,
+ .mem_targets = MEM_ALL,
+ .uffd_feature_required =
+ UFFD_FEATURE_RWP | UFFD_FEATURE_RWP_ASYNC,
+ },
+ {
+ .name = "rwp-sync",
+ .uffd_fn = uffd_rwp_sync_test,
+ .mem_targets = MEM_ALL,
+ .uffd_feature_required = UFFD_FEATURE_RWP,
+ },
+ {
+ .name = "rwp-pagemap",
+ .uffd_fn = uffd_rwp_pagemap_test,
+ .mem_targets = MEM_ALL,
+ .uffd_feature_required =
+ UFFD_FEATURE_RWP | UFFD_FEATURE_RWP_ASYNC,
+ },
+ {
+ .name = "rwp-mprotect",
+ .uffd_fn = uffd_rwp_mprotect_test,
+ .mem_targets = MEM_ALL,
+ .uffd_feature_required =
+ UFFD_FEATURE_RWP | UFFD_FEATURE_RWP_ASYNC,
+ },
+ {
+ .name = "rwp-gup",
+ .uffd_fn = uffd_rwp_gup_test,
+ .mem_targets = MEM_ALL,
+ .uffd_feature_required =
+ UFFD_FEATURE_RWP | UFFD_FEATURE_RWP_ASYNC,
+ },
+ {
+ .name = "rwp-async-toggle",
+ .uffd_fn = uffd_rwp_async_toggle_test,
+ .mem_targets = MEM_ALL,
+ .uffd_feature_required =
+ UFFD_FEATURE_RWP | UFFD_FEATURE_RWP_ASYNC,
+ },
+ {
+ .name = "rwp-close",
+ .uffd_fn = uffd_rwp_close_test,
+ .mem_targets = MEM_ALL,
+ .uffd_feature_required = UFFD_FEATURE_RWP,
+ },
+ {
+ .name = "rwp-fork",
+ .uffd_fn = uffd_rwp_fork_test,
+ .mem_targets = MEM_ALL,
+ .uffd_feature_required =
+ UFFD_FEATURE_RWP | UFFD_FEATURE_EVENT_FORK,
+ },
+ {
+ .name = "rwp-fork-pin",
+ .uffd_fn = uffd_rwp_fork_pin_test,
+ .mem_targets = MEM_ANON,
+ .uffd_feature_required =
+ UFFD_FEATURE_RWP | UFFD_FEATURE_RWP_ASYNC |
+ UFFD_FEATURE_EVENT_FORK,
+ },
+ {
+ .name = "rwp-swap-cow",
+ .uffd_fn = uffd_rwp_swap_cow_test,
+ .mem_targets = MEM_ANON,
+ .uffd_feature_required = UFFD_FEATURE_RWP,
+ },
+ {
+ .name = "rwp-wp-exclusive",
+ .uffd_fn = uffd_rwp_wp_exclusive_test,
+ .mem_targets = MEM_ALL,
+ .uffd_feature_required =
+ UFFD_FEATURE_RWP |
+ UFFD_FEATURE_PAGEFAULT_FLAG_WP |
+ UFFD_FEATURE_WP_HUGETLBFS_SHMEM,
+ },
+ {
.name = "sigbus",
.uffd_fn = uffd_sigbus_test,
.mem_targets = MEM_ALL,
@@ -1814,6 +2714,25 @@ int main(int argc, char *argv[])
uffd_test_skip(errmsg);
continue;
}
+ /*
+ * RWP tracks protection on ptes; a THP-backed shmem/anon
+ * range (e.g. shmem_enabled=always) would split on
+ * rwprotect and change behaviour under the test. Keep
+ * such ranges off THP. hugetlb is huge by definition and
+ * rejects MADV_NOHUGEPAGE, so skip it.
+ */
+ if ((test->uffd_feature_required & UFFD_FEATURE_RWP) &&
+ !(mem_type->mem_flag & (MEM_HUGETLB | MEM_HUGETLB_PRIVATE))) {
+ unsigned long len = gopts.nr_pages * gopts.page_size;
+
+ /*
+ * EINVAL means CONFIG_TRANSPARENT_HUGEPAGE=n:
+ * nothing to opt out of.
+ */
+ if (madvise(gopts.area_dst, len, MADV_NOHUGEPAGE) &&
+ errno != EINVAL)
+ err("madvise(MADV_NOHUGEPAGE)");
+ }
test->uffd_fn(&gopts, &args);
uffd_test_ctx_clear(&gopts);
}
diff --git a/tools/testing/selftests/net/lib.sh b/tools/testing/selftests/net/lib.sh
index f13672c985bf..d46d2cec89e4 100644
--- a/tools/testing/selftests/net/lib.sh
+++ b/tools/testing/selftests/net/lib.sh
@@ -72,9 +72,13 @@ ksft_exit_status_merge()
timestamp_ms()
{
- local now=$(date -u +%s:%N)
- local seconds=${now%:*}
- local nanoseconds=${now#*:}
+ local now
+ local seconds
+ local nanoseconds
+
+ now=$(date -u +%s:%N) || return
+ seconds=${now%:*}
+ nanoseconds=${now#*:}
if [[ $nanoseconds =~ ^[0-9]+$ ]]; then
nanoseconds=${nanoseconds:0:9}
@@ -89,9 +93,10 @@ loopy_wait()
{
local sleep_cmd=$1; shift
local timeout_ms=$1; shift
+ local start_time
local current_time
- local start_time=$(timestamp_ms)
+ start_time=$(timestamp_ms) || return
while true
do
local out
@@ -100,7 +105,7 @@ loopy_wait()
return 0
fi
- local current_time=$(timestamp_ms)
+ current_time=$(timestamp_ms) || return
if ((current_time - start_time > timeout_ms)); then
echo -n "$out"
return 1
diff --git a/tools/testing/selftests/net/tcp_mmap.c b/tools/testing/selftests/net/tcp_mmap.c
index 4fcce5150850..2544ae35d07a 100644
--- a/tools/testing/selftests/net/tcp_mmap.c
+++ b/tools/testing/selftests/net/tcp_mmap.c
@@ -313,6 +313,8 @@ end:
tcp_info_get_rcv_mss(fd));
}
error:
+ if (ctx)
+ EVP_MD_CTX_free(ctx);
munmap(buffer, buffer_sz);
close(fd);
if (zflg)
@@ -606,6 +608,8 @@ int main(int argc, char *argv[])
EVP_DigestFinal_ex(ctx, digest, &digest_len);
send(fd, digest, (size_t)SHA256_DIGEST_LENGTH, 0);
}
+ if (ctx)
+ EVP_MD_CTX_free(ctx);
close(fd);
munmap(buffer, buffer_sz);
return 0;
diff --git a/tools/testing/selftests/rseq/Makefile b/tools/testing/selftests/rseq/Makefile
index 50d69e22ee7a..aba6317f6cb8 100644
--- a/tools/testing/selftests/rseq/Makefile
+++ b/tools/testing/selftests/rseq/Makefile
@@ -5,9 +5,13 @@ CLANG_FLAGS += -no-integrated-as
endif
top_srcdir = ../../../..
+include $(top_srcdir)/scripts/subarch.include
+ARCH ?= $(SUBARCH)
+LINUX_TOOL_ARCH_INCLUDE = $(top_srcdir)/tools/arch/$(ARCH)/include
CFLAGS += -O2 -Wall -g -I./ $(KHDR_INCLUDES) -L$(OUTPUT) -Wl,-rpath=./ \
- $(CLANG_FLAGS) -I$(top_srcdir)/tools/include
+ $(CLANG_FLAGS) -I$(top_srcdir)/tools/include \
+ -I$(LINUX_TOOL_ARCH_INCLUDE)
LDLIBS += -lpthread -ldl
# Own dependencies because we only want to build against 1st prerequisite, but
diff --git a/tools/testing/selftests/sched_ext/Makefile b/tools/testing/selftests/sched_ext/Makefile
index 5d2dffca0e91..3cfe90e0f34f 100644
--- a/tools/testing/selftests/sched_ext/Makefile
+++ b/tools/testing/selftests/sched_ext/Makefile
@@ -176,6 +176,7 @@ auto-test-targets := \
maybe_null \
minimal \
non_scx_kfunc_deny \
+ nohz_tick \
numa \
allowed_cpus \
peek_dsq \
diff --git a/tools/testing/selftests/sched_ext/nohz_tick.bpf.c b/tools/testing/selftests/sched_ext/nohz_tick.bpf.c
new file mode 100644
index 000000000000..6998c5dd6bcb
--- /dev/null
+++ b/tools/testing/selftests/sched_ext/nohz_tick.bpf.c
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES
+ *
+ * Exercise tick dependency transitions between infinite and finite slices.
+ */
+#include <scx/common.bpf.h>
+
+char _license[] SEC("license") = "GPL";
+
+const volatile s32 test_cpu;
+bool finite_phase;
+u64 nr_inf_running;
+u64 nr_finite_running;
+u64 nr_finite_ticks;
+
+UEI_DEFINE(uei);
+
+s32 BPF_STRUCT_OPS(nohz_tick_select_cpu, struct task_struct *p, s32 prev_cpu,
+ u64 wake_flags)
+{
+ return prev_cpu;
+}
+
+void BPF_STRUCT_OPS(nohz_tick_enqueue, struct task_struct *p, u64 enq_flags)
+{
+ u64 slice = finite_phase ? 1000000ULL : SCX_SLICE_INF;
+
+ scx_bpf_dsq_insert(p, SCX_DSQ_GLOBAL, slice, enq_flags);
+ if (enq_flags & SCX_ENQ_LAST)
+ scx_bpf_kick_cpu(test_cpu, SCX_KICK_IDLE);
+}
+
+void BPF_STRUCT_OPS(nohz_tick_running, struct task_struct *p)
+{
+ if (bpf_get_smp_processor_id() != test_cpu)
+ return;
+
+ if (finite_phase)
+ __sync_fetch_and_add(&nr_finite_running, 1);
+ else
+ __sync_fetch_and_add(&nr_inf_running, 1);
+}
+
+void BPF_STRUCT_OPS(nohz_tick_tick, struct task_struct *p)
+{
+ if (bpf_get_smp_processor_id() == test_cpu && finite_phase)
+ __sync_fetch_and_add(&nr_finite_ticks, 1);
+}
+
+void BPF_STRUCT_OPS(nohz_tick_exit, struct scx_exit_info *ei)
+{
+ UEI_RECORD(uei, ei);
+}
+
+SEC(".struct_ops.link")
+struct sched_ext_ops nohz_tick_ops = {
+ .select_cpu = (void *)nohz_tick_select_cpu,
+ .enqueue = (void *)nohz_tick_enqueue,
+ .running = (void *)nohz_tick_running,
+ .tick = (void *)nohz_tick_tick,
+ .exit = (void *)nohz_tick_exit,
+ .name = "nohz_tick",
+ .timeout_ms = 1000U,
+};
diff --git a/tools/testing/selftests/sched_ext/nohz_tick.c b/tools/testing/selftests/sched_ext/nohz_tick.c
new file mode 100644
index 000000000000..028f54391c2c
--- /dev/null
+++ b/tools/testing/selftests/sched_ext/nohz_tick.c
@@ -0,0 +1,347 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES
+ *
+ * Validate that a finite-slice EXT task restarts the scheduler tick when it
+ * follows an infinite-slice EXT task and an idle interval on a NOHZ_FULL CPU.
+ */
+#define _GNU_SOURCE
+
+#include <bpf/bpf.h>
+#include <errno.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/prctl.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <scx/common.h>
+
+#include "nohz_tick.bpf.skel.h"
+#include "scx_test.h"
+
+#ifndef SCHED_EXT
+#define SCHED_EXT 7
+#endif
+
+#define MIN_FINITE_TICKS 3
+#define PHASE_TIMEOUT_MS 1000
+
+struct nohz_tick_ctx {
+ struct nohz_tick *skel;
+ cpu_set_t original_mask;
+ int test_cpu;
+};
+
+static int first_allowed_cpu(const cpu_set_t *mask, int first, int last)
+{
+ int cpu;
+
+ for (cpu = first; cpu <= last && cpu < CPU_SETSIZE; cpu++)
+ if (CPU_ISSET(cpu, mask))
+ return cpu;
+
+ return -1;
+}
+
+static int find_nohz_full_cpu(const cpu_set_t *allowed)
+{
+ char buf[4096], *cur, *end;
+ FILE *file;
+
+ file = fopen("/sys/devices/system/cpu/nohz_full", "r");
+ if (!file)
+ return -1;
+ if (!fgets(buf, sizeof(buf), file)) {
+ fclose(file);
+ return -1;
+ }
+ fclose(file);
+
+ cur = buf;
+ while (*cur) {
+ long first, last;
+ int cpu;
+
+ while (*cur == ' ' || *cur == '\t' || *cur == ',')
+ cur++;
+ if (*cur < '0' || *cur > '9')
+ break;
+
+ errno = 0;
+ first = strtol(cur, &end, 10);
+ if (errno || end == cur || first < 0 || first >= CPU_SETSIZE)
+ return -1;
+ cur = end;
+ last = first;
+ if (*cur == '-') {
+ cur++;
+ errno = 0;
+ last = strtol(cur, &end, 10);
+ if (errno || end == cur || last < first)
+ return -1;
+ cur = end;
+ }
+
+ cpu = first_allowed_cpu(allowed, first, last);
+ if (cpu >= 0)
+ return cpu;
+ }
+
+ return -1;
+}
+
+static pid_t start_worker(int cpu)
+{
+ struct sched_param param = {};
+ cpu_set_t mask;
+ pid_t parent;
+ pid_t pid;
+
+ parent = getpid();
+ pid = fork();
+ if (pid != 0)
+ return pid;
+ if (prctl(PR_SET_PDEATHSIG, SIGKILL) || getppid() != parent)
+ _exit(1);
+
+ /*
+ * Become EXT before touching the target so it stays idle until wakeup.
+ */
+ if (sched_setscheduler(0, SCHED_EXT, &param))
+ _exit(1);
+
+ CPU_ZERO(&mask);
+ CPU_SET(cpu, &mask);
+ if (sched_setaffinity(0, sizeof(mask), &mask))
+ _exit(1);
+
+ for (;;)
+ asm volatile("" ::: "memory");
+}
+
+static void stop_worker(pid_t pid)
+{
+ if (pid <= 0)
+ return;
+
+ kill(pid, SIGKILL);
+ waitpid(pid, NULL, 0);
+}
+
+static int pause_worker(pid_t pid)
+{
+ int status;
+
+ if (kill(pid, SIGSTOP))
+ return -errno;
+ if (waitpid(pid, &status, WUNTRACED) != pid)
+ return -errno;
+ if (!WIFSTOPPED(status))
+ return -ECHILD;
+
+ return 0;
+}
+
+static bool wait_for_counter(const u64 *counter, u64 value, int timeout_ms)
+{
+ int elapsed;
+
+ for (elapsed = 0; elapsed < timeout_ms; elapsed++) {
+ if (__atomic_load_n(counter, __ATOMIC_RELAXED) >= value)
+ return true;
+ usleep(1000);
+ }
+
+ return false;
+}
+
+static enum scx_test_status setup(void **ctx_ptr)
+{
+ struct nohz_tick_ctx *ctx;
+ cpu_set_t controller_mask;
+ int cpu;
+
+ ctx = calloc(1, sizeof(*ctx));
+ SCX_FAIL_IF(!ctx, "Failed to allocate context");
+ if (sched_getaffinity(0, sizeof(ctx->original_mask),
+ &ctx->original_mask)) {
+ free(ctx);
+ SCX_FAIL("Failed to get affinity (%d)", errno);
+ }
+
+ cpu = find_nohz_full_cpu(&ctx->original_mask);
+ if (cpu < 0) {
+ fprintf(stderr, "SKIP: no allowed NOHZ_FULL CPU\n");
+ free(ctx);
+ return SCX_TEST_SKIP;
+ }
+
+ controller_mask = ctx->original_mask;
+ CPU_CLR(cpu, &controller_mask);
+ if (CPU_COUNT(&controller_mask) == 0) {
+ fprintf(stderr, "SKIP: no housekeeping CPU available\n");
+ free(ctx);
+ return SCX_TEST_SKIP;
+ }
+
+ ctx->test_cpu = cpu;
+ ctx->skel = nohz_tick__open();
+ if (!ctx->skel) {
+ free(ctx);
+ SCX_FAIL("Failed to open skeleton");
+ }
+
+ SCX_ENUM_INIT(ctx->skel);
+ ctx->skel->rodata->test_cpu = cpu;
+ ctx->skel->struct_ops.nohz_tick_ops->flags |= SCX_OPS_SWITCH_PARTIAL |
+ SCX_OPS_ENQ_LAST;
+ if (nohz_tick__load(ctx->skel)) {
+ nohz_tick__destroy(ctx->skel);
+ free(ctx);
+ SCX_FAIL("Failed to load skeleton");
+ }
+
+ if (sched_setaffinity(0, sizeof(controller_mask), &controller_mask)) {
+ nohz_tick__destroy(ctx->skel);
+ free(ctx);
+ SCX_FAIL("Failed to move controller off CPU %d (%d)", cpu, errno);
+ }
+
+ *ctx_ptr = ctx;
+ return SCX_TEST_PASS;
+}
+
+static enum scx_test_status run(void *ctx_ptr)
+{
+ struct nohz_tick_ctx *ctx = ctx_ptr;
+ struct nohz_tick *skel = ctx->skel;
+ struct bpf_link *link = NULL;
+ enum scx_test_status status = SCX_TEST_FAIL;
+ pid_t finite_worker = -1;
+ pid_t inf_worker = -1;
+ u64 finite_running;
+ u64 finite_ticks;
+ int ret;
+
+ link = bpf_map__attach_struct_ops(skel->maps.nohz_tick_ops);
+ if (!link) {
+ SCX_ERR("Failed to attach scheduler");
+ goto out;
+ }
+
+ /*
+ * Establish SCX_RQ_CAN_STOP_TICK with an infinite-slice task.
+ */
+ inf_worker = start_worker(ctx->test_cpu);
+ if (inf_worker < 0) {
+ SCX_ERR("Failed to start infinite-slice worker (%d)", errno);
+ goto out;
+ }
+ if (!wait_for_counter(&skel->bss->nr_inf_running, 1,
+ PHASE_TIMEOUT_MS)) {
+ SCX_ERR("Infinite-slice worker was not scheduled");
+ goto out;
+ }
+
+ /* Block without exiting so the rq retains the infinite-slice state. */
+ ret = pause_worker(inf_worker);
+ if (ret) {
+ SCX_ERR("Failed to stop infinite-slice worker (%d)", ret);
+ goto out;
+ }
+
+ /* Let the target enter idle with its tick stopped. */
+ usleep(100000);
+
+ /*
+ * The next EXT task receives a finite slice and must restart the tick.
+ */
+ __atomic_store_n(&skel->bss->finite_phase, true, __ATOMIC_RELEASE);
+ finite_worker = start_worker(ctx->test_cpu);
+ if (finite_worker < 0) {
+ SCX_ERR("Failed to start finite-slice worker (%d)", errno);
+ goto out;
+ }
+ if (!wait_for_counter(&skel->bss->nr_finite_running, 1,
+ PHASE_TIMEOUT_MS)) {
+ SCX_ERR("Finite-slice worker was not scheduled");
+ goto out;
+ }
+ if (!wait_for_counter(&skel->bss->nr_finite_ticks, MIN_FINITE_TICKS,
+ PHASE_TIMEOUT_MS)) {
+ SCX_ERR("Finite-slice worker received only %llu scheduler ticks",
+ (unsigned long long)skel->bss->nr_finite_ticks);
+ goto out;
+ }
+ stop_worker(finite_worker);
+ finite_worker = -1;
+
+ /*
+ * Leave the CPU idle after a finite-slice task. The next finite-slice
+ * task must restart the tick even though the slice type is unchanged.
+ */
+ usleep(100000);
+ finite_running = __atomic_load_n(&skel->bss->nr_finite_running,
+ __ATOMIC_RELAXED);
+ finite_ticks = __atomic_load_n(&skel->bss->nr_finite_ticks,
+ __ATOMIC_RELAXED);
+
+ finite_worker = start_worker(ctx->test_cpu);
+ if (finite_worker < 0) {
+ SCX_ERR("Failed to start second finite-slice worker (%d)", errno);
+ goto out;
+ }
+ if (!wait_for_counter(&skel->bss->nr_finite_running,
+ finite_running + 1, PHASE_TIMEOUT_MS)) {
+ SCX_ERR("Second finite-slice worker was not scheduled");
+ goto out;
+ }
+ if (!wait_for_counter(&skel->bss->nr_finite_ticks,
+ finite_ticks + MIN_FINITE_TICKS,
+ PHASE_TIMEOUT_MS)) {
+ SCX_ERR("Second finite-slice worker received only %llu scheduler ticks",
+ (unsigned long long)(skel->bss->nr_finite_ticks -
+ finite_ticks));
+ goto out;
+ }
+
+ if (skel->data->uei.kind != EXIT_KIND(SCX_EXIT_NONE)) {
+ SCX_ERR("Scheduler exited unexpectedly (kind=%llu code=%lld)",
+ (unsigned long long)skel->data->uei.kind,
+ (long long)skel->data->uei.exit_code);
+ goto out;
+ }
+
+ fprintf(stderr, "CPU %d received %llu finite-slice ticks\n",
+ ctx->test_cpu,
+ (unsigned long long)skel->bss->nr_finite_ticks);
+ status = SCX_TEST_PASS;
+out:
+ stop_worker(finite_worker);
+ stop_worker(inf_worker);
+ if (link)
+ bpf_link__destroy(link);
+ return status;
+}
+
+static void cleanup(void *ctx_ptr)
+{
+ struct nohz_tick_ctx *ctx = ctx_ptr;
+
+ sched_setaffinity(0, sizeof(ctx->original_mask), &ctx->original_mask);
+ nohz_tick__destroy(ctx->skel);
+ free(ctx);
+}
+
+struct scx_test nohz_tick = {
+ .name = "nohz_tick",
+ .description = "Verify finite EXT slices restart the NOHZ_FULL tick",
+ .setup = setup,
+ .run = run,
+ .cleanup = cleanup,
+};
+REGISTER_SCX_TEST(&nohz_tick)
diff --git a/tools/testing/selftests/sched_ext/prog_run.c b/tools/testing/selftests/sched_ext/prog_run.c
index 05974820ca69..1129ec2aaddc 100644
--- a/tools/testing/selftests/sched_ext/prog_run.c
+++ b/tools/testing/selftests/sched_ext/prog_run.c
@@ -28,7 +28,8 @@ static enum scx_test_status setup(void **ctx)
static enum scx_test_status run(void *ctx)
{
struct prog_run *skel = ctx;
- struct bpf_link *link;
+ struct bpf_link *link = NULL;
+ enum scx_test_status status = SCX_TEST_PASS;
int prog_fd, err = 0;
prog_fd = bpf_program__fd(skel->progs.prog_run_syscall);
@@ -42,23 +43,40 @@ static enum scx_test_status run(void *ctx)
link = bpf_map__attach_struct_ops(skel->maps.prog_run_ops);
if (!link) {
SCX_ERR("Failed to attach scheduler");
- close(prog_fd);
- return SCX_TEST_FAIL;
+ status = SCX_TEST_FAIL;
+ goto out;
}
err = bpf_prog_test_run_opts(prog_fd, &topts);
- SCX_EQ(err, 0);
+ if (err) {
+ SCX_ERR("BPF_PROG_RUN failed (%d)", err);
+ status = SCX_TEST_FAIL;
+ goto out;
+ }
/* Assumes uei.kind is written last */
while (skel->data->uei.kind == EXIT_KIND(SCX_EXIT_NONE))
sched_yield();
- SCX_EQ(skel->data->uei.kind, EXIT_KIND(SCX_EXIT_UNREG_BPF));
- SCX_EQ(skel->data->uei.exit_code, 0xdeadbeef);
+ if (skel->data->uei.kind != EXIT_KIND(SCX_EXIT_UNREG_BPF)) {
+ SCX_ERR("Unexpected exit kind: %llu",
+ (unsigned long long)skel->data->uei.kind);
+ status = SCX_TEST_FAIL;
+ goto out;
+ }
+ if (skel->data->uei.exit_code != 0xdeadbeef) {
+ SCX_ERR("Unexpected exit code: %lld",
+ (long long)skel->data->uei.exit_code);
+ status = SCX_TEST_FAIL;
+ goto out;
+ }
+
+out:
close(prog_fd);
- bpf_link__destroy(link);
+ if (link)
+ bpf_link__destroy(link);
- return SCX_TEST_PASS;
+ return status;
}
static void cleanup(void *ctx)
diff --git a/tools/testing/vma/include/dup.h b/tools/testing/vma/include/dup.h
index cf73bcd9bb9d..bf26b3f48d3a 100644
--- a/tools/testing/vma/include/dup.h
+++ b/tools/testing/vma/include/dup.h
@@ -243,7 +243,7 @@ enum {
#define VM_NOHUGEPAGE INIT_VM_FLAG(NOHUGEPAGE)
#define VM_MERGEABLE INIT_VM_FLAG(MERGEABLE)
#define VM_STACK INIT_VM_FLAG(STACK)
-#ifdef CONFIG_STACK_GROWSUP
+#ifdef CONFIG_STACK_GROWS_UP
#define VM_STACK_EARLY INIT_VM_FLAG(STACK_EARLY)
#else
#define VM_STACK_EARLY VM_NONE
diff --git a/tools/usb/usbip/libsrc/usbip_common.c b/tools/usb/usbip/libsrc/usbip_common.c
index b8d7d480595a..f4734f552d31 100644
--- a/tools/usb/usbip/libsrc/usbip_common.c
+++ b/tools/usb/usbip/libsrc/usbip_common.c
@@ -29,6 +29,8 @@ static const struct speed_string speed_strings[] = {
{ USB_SPEED_HIGH, "480", "High Speed(480Mbps)" },
{ USB_SPEED_WIRELESS, "53.3-480", "Wireless"},
{ USB_SPEED_SUPER, "5000", "Super Speed(5000Mbps)" },
+ { USB_SPEED_SUPER_PLUS, "10000", "Super Speed Plus(10000Mbps)" },
+ { USB_SPEED_SUPER_PLUS, "20000", "Super Speed Plus(20000Mbps)" },
{ 0, NULL, NULL }
};
diff --git a/tools/usb/usbip/libsrc/usbip_device_driver.c b/tools/usb/usbip/libsrc/usbip_device_driver.c
index 1dfbb76ab26c..c9b3619d86f3 100644
--- a/tools/usb/usbip/libsrc/usbip_device_driver.c
+++ b/tools/usb/usbip/libsrc/usbip_device_driver.c
@@ -57,6 +57,10 @@ static struct {
.speed = USB_SPEED_SUPER,
.name = "super-speed",
},
+ {
+ .speed = USB_SPEED_SUPER_PLUS,
+ .name = "super-speed-plus",
+ },
};
static
diff --git a/tools/usb/usbip/libsrc/vhci_driver.c b/tools/usb/usbip/libsrc/vhci_driver.c
index 8159fd98680b..4ca3783ee5b7 100644
--- a/tools/usb/usbip/libsrc/vhci_driver.c
+++ b/tools/usb/usbip/libsrc/vhci_driver.c
@@ -338,6 +338,7 @@ int usbip_vhci_get_free_port(uint32_t speed)
switch (speed) {
case USB_SPEED_SUPER:
+ case USB_SPEED_SUPER_PLUS:
if (vhci_driver->idev[i].hub != HUB_SPEED_SUPER)
continue;
break;
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 45e784462ec6..c40a2aca2303 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -4188,6 +4188,8 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, unsigned long id)
goto vcpu_decrement;
}
+ vcpu->vcpu_idx = -1;
+
BUILD_BUG_ON(sizeof(struct kvm_run) > PAGE_SIZE);
page = alloc_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO);
if (!page) {
@@ -4216,6 +4218,11 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, unsigned long id)
goto unlock_vcpu_destroy;
}
+ /*
+ * Set the vCPU's index *before* the vCPU is reachable by other tasks.
+ * Unwind the index back to -1 on failure so that KVM can use the index
+ * to detect that the vCPU is unreachable, e.g. for lockdep asserts.
+ */
vcpu->vcpu_idx = atomic_read(&kvm->online_vcpus);
r = xa_insert(&kvm->vcpu_array, vcpu->vcpu_idx, vcpu, GFP_KERNEL_ACCOUNT);
WARN_ON_ONCE(r == -EBUSY);
@@ -4254,6 +4261,7 @@ kvm_put_xa_erase:
kvm_put_kvm_no_destroy(kvm);
xa_erase(&kvm->vcpu_array, vcpu->vcpu_idx);
unlock_vcpu_destroy:
+ vcpu->vcpu_idx = -1;
mutex_unlock(&kvm->lock);
kvm_dirty_ring_free(&vcpu->dirty_ring);
arch_vcpu_destroy:
@@ -6553,6 +6561,7 @@ err_virt:
err_gmem:
kvm_vfio_ops_exit();
err_vfio:
+ debugfs_remove_recursive(kvm_debugfs_dir);
kvm_async_pf_deinit();
err_async_pf:
kvm_irqfd_exit();